Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/GlaDSCoupledSolver.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: Olivier Gagliardini, Mauro Werder
26
! * Email: [email protected], [email protected]
27
! * Web: http://www.csc.fi/elmer
28
! * Address: CSC - Scientific Computing Ltd.
29
! * Keilaranta 14
30
! * 02101 Espoo, Finland
31
! *
32
! * Original Date: 15 February 2013
33
! *
34
! *****************************************************************************/
35
!> Solve for the sheet hydraulic Potential, sheet thickness and channels area
36
!> similutaneously (GlaDS model) - This solver replace the 3 solvers solving
37
!> for these 3 variables independently.
38
!> Equations defined in Werder et al., 2013
39
RECURSIVE SUBROUTINE GlaDSCoupledsolver( Model,Solver,Timestep,TransientSimulation )
40
!******************************************************************************
41
!
42
! ARGUMENTS:
43
!
44
! TYPE(Model_t) :: Model,
45
! INPUT: All model information (mesh,materials,BCs,etc...)
46
!
47
! TYPE(Solver_t) :: Solver
48
! INPUT: Linear equation solver options
49
!
50
! REAL(KIND=dp) :: Timestep
51
! INPUT: Timestep size for time dependent simulations
52
!
53
!******************************************************************************
54
USE Differentials
55
USE MaterialModels
56
USE DefUtils
57
!------------------------------------------------------------------------------
58
IMPLICIT NONE
59
!------------------------------------------------------------------------------
60
!------------------------------------------------------------------------------
61
! External variables
62
!------------------------------------------------------------------------------
63
TYPE(Model_t) :: Model
64
TYPE(Solver_t), TARGET :: Solver
65
LOGICAL :: TransientSimulation
66
REAL(KIND=dp) :: Timestep
67
!------------------------------------------------------------------------------
68
! Local variables
69
!------------------------------------------------------------------------------
70
TYPE(Solver_t), POINTER :: PointerToSolver
71
TYPE(Matrix_t), POINTER :: Systemmatrix
72
TYPE(Nodes_t) :: ElementNodes, EdgeNodes
73
TYPE(Element_t), POINTER :: Element, Edge, Face, Bulk
74
TYPE(ValueList_t), POINTER :: Equation, Material, SolverParams, BodyForce, BC, Constants
75
TYPE(Variable_t), POINTER :: WorkVar, WorkVar2
76
TYPE(Mesh_t), POINTER :: Mesh
77
78
INTEGER :: i, j, k, l, m, n, t, iter, body_id, eq_id, material_id, &
79
istat, LocalNodes,bf_id, bc_id, DIM, dimSheet, iterC, &
80
NSDOFs, NonlinearIter, GhostNodes, NonlinearIterMin, Ne, BDForder, &
81
CoupledIter, Nel, ierror, ChannelSolver, FluxVariable, ThicknessSolver, ierr
82
83
TYPE(Variable_t), POINTER :: HydPotSol
84
TYPE(Variable_t), POINTER :: ThickSol, AreaSol, VSol, WSol, NSol, &
85
PwSol, ZbSol, qSol, hstoreSol, QcSol, QmSol, &
86
MoulinMaskSol, MoulinFluxSol
87
88
INTEGER, POINTER :: NodeIndexes(:), HydPotPerm(:), PwPerm(:), ZbPerm(:), &
89
ThickPerm(:), VPerm(:), WPerm(:), NPerm(:), AreaPerm(:), &
90
qPerm(:), hstorePerm(:), QcPerm(:), QmPerm(:),&
91
CAPerm(:), CFPerm(:), SHPerm(:), &
92
MoulinMaskPerm(:), MoulinFluxPerm(:)
93
94
REAL(KIND=dp), POINTER :: HydPot(:), HydPotPrev(:,:), ForceVector(:)
95
REAL(KIND=dp), POINTER :: ThickSolution(:), ThickPrev(:,:), VSolution(:), WSolution(:), &
96
NSolution(:), PwSolution(:), AreaSolution(:), AreaPrev(:,:), ZbSolution(:), &
97
qSolution(:), hstoreSolution(:), QcSolution(:), QmSolution(:),&
98
CAValues(:), CFValues(:), SHValues(:),&
99
MoulinMask(:), MoulinFluxVal(:)
100
101
CHARACTER(LEN=MAX_NAME_LEN) :: VariableName, SolverName
102
CHARACTER(LEN=MAX_NAME_LEN) :: SheetThicknessName, ChannelAreaName, ZbName
103
CHARACTER(LEN=MAX_NAME_LEN) :: methodSheet, methodChannels
104
105
LOGICAL :: Found, FluxBC, Channels, Storage, FirstTime = .TRUE., &
106
AllocationsDone = .FALSE., SubroutineVisited = .FALSE., &
107
meltChannels = .TRUE., NeglectH = .TRUE., Calving = .FALSE., &
108
CycleElement=.FALSE., MABool = .FALSE., MaxHBool = .FALSE., LimitEffPres=.FALSE., &
109
MinHBool=.FALSE., HaveMoulinMask=.FALSE.
110
LOGICAL, ALLOCATABLE :: IsGhostNode(:), NoChannel(:), NodalNoChannel(:)
111
112
REAL(KIND=dp) :: NonlinearTol, dt, CumulativeTime, RelativeChange, &
113
Norm, PrevNorm, S, C, Qc, MaxArea, MaxH, MinH
114
REAL(KIND=dp), ALLOCATABLE :: MASS(:,:), &
115
STIFF(:,:), LOAD(:), SheetConductivity(:), ChannelConductivity(:),&
116
FORCE(:), C1(:), CT(:), OldValues(:), Refq(:)
117
118
REAL(KIND=dp), ALLOCATABLE :: Vvar(:), ublr(:), hr2(:)
119
120
REAL(KIND=dp), ALLOCATABLE :: lr(:), hr(:), Ar(:), Wopen(:), &
121
ub(:), Snn(:), Ev(:), &
122
ng(:), alphas(:), betas(:), betac(:), Phi0(:), Phim(:), Afactor(:), Bfactor(:), &
123
MoulinArea(:), MoulinFlux(:)
124
125
REAL(KIND=dp), ALLOCATABLE :: IceDensity(:), Ac(:), alphac(:), CCt(:), &
126
CCw(:), lc(:)
127
REAL(KIND=dp) :: ChannelArea, WaterDensity, gravity, Lw, EdgeTangent(3), &
128
ALPHA, BETA, CoupledTol, CoupledNorm, PrevCoupledNorm, &
129
Discharge(3)
130
131
REAL(KIND=dp) :: totat, st, totst, t1
132
REAL(KIND=dp) :: Np, pw, zb, Wo, he
133
134
REAL(KIND=dp) :: at, at0
135
136
TYPE(ValueHandle_t) :: Load_h
137
138
SAVE &
139
ElementNodes, EdgeNodes, &
140
C1, &
141
CT, &
142
FirstTime, &
143
SheetConductivity, &
144
ChannelConductivity, &
145
MASS, &
146
STIFF,LOAD, &
147
FORCE, &
148
IsGhostNode, &
149
AllocationsDone, VariableName, SolverName, NonLinearTol, M, &
150
lr, hr, Ar, Wopen, Afactor, Bfactor, &
151
MoulinArea, MoulinFlux, &
152
ub, Snn, Ev, WaterDensity, gravity, &
153
ng, alphas, betas, betac, Phi0, Phim, SheetThicknessName, &
154
ChannelAreaName, ZbName, IceDensity, Ac, alphac, CCt, &
155
CCw, lc, Lw, NoChannel, NodalNoChannel, &
156
Channels, meltChannels, NeglectH, BDForder, &
157
Vvar, ublr, hr2, Refq, Nel,&
158
Calving, Load_h, LimitEffPres, HaveMoulinMask
159
160
161
totst = 0.0_dp
162
totat = 0.0_dp
163
164
!------------------------------------------------------------------------------
165
! Get variables needed for solution
166
!------------------------------------------------------------------------------
167
VariableName = TRIM(Solver % Variable % Name)
168
SolverName = 'GlaDSCoupledsolver ('// VariableName // ')'
169
170
CALL ListInitElementKeyword( Load_h, 'Body Force', TRIM(Solver % Variable % Name) // ' Volume Source')
171
172
173
IF ( .NOT. ASSOCIATED( Solver % Matrix ) ) RETURN
174
SystemMatrix => Solver % Matrix
175
ForceVector => Solver % Matrix % RHS
176
177
PointerToSolver => Solver
178
179
HydPotSol => Solver % Variable
180
HydPotPerm => HydPotSol % Perm
181
HydPot => HydPotSol % Values
182
HydPotPrev => HydPotSol % PrevValues
183
184
LocalNodes = COUNT( HydPotPerm > 0 )
185
IF ( LocalNodes <= 0 ) RETURN
186
187
!CHANGE (and at all DIMs)
188
Mesh => Solver % Mesh
189
DIM = Mesh % MeshDim
190
M = Mesh % NumberOfNodes
191
192
!------------------------------------------------------------------------------
193
! Allocate some permanent storage, this is done first time only
194
!------------------------------------------------------------------------------
195
IF ( .NOT. AllocationsDone .OR. Mesh % Changed ) THEN
196
N = Mesh % MaxElementNodes
197
Ne = Mesh % NumberOfEdges
198
Nel = Mesh % NumberOfBulkElements + Mesh % NumberOfBoundaryElements
199
K = SIZE( SystemMatrix % Values )
200
L = SIZE( SystemMatrix % RHS )
201
202
IF ( AllocationsDone ) THEN
203
DEALLOCATE( &
204
ElementNodes % x, &
205
ElementNodes % y, &
206
ElementNodes % z, &
207
EdgeNodes % x, &
208
EdgeNodes % y, &
209
EdgeNodes % z, &
210
C1, &
211
CT, &
212
SheetConductivity, &
213
ChannelConductivity, &
214
MASS, &
215
STIFF,LOAD, &
216
FORCE, &
217
IsGhostNode, &
218
lr, hr, Ar, Wopen, Afactor, Bfactor, &
219
MoulinArea, MoulinFlux, &
220
ub, Snn, Ev, &
221
ng, alphas, betas, betac, Phi0, Phim, &
222
IceDensity, Ac, alphac, CCt, &
223
CCw, lc, OldValues, NoChannel, NodalNoChannel, &
224
Vvar, ublr, hr2, &
225
Refq)
226
227
END IF
228
229
ALLOCATE( &
230
ElementNodes % x( N ), &
231
ElementNodes % y( N ), &
232
ElementNodes % z( N ), &
233
EdgeNodes % x( N ), &
234
EdgeNodes % y( N ), &
235
EdgeNodes % z( N ), &
236
C1( N ), &
237
CT( N ), &
238
SheetConductivity( N ), &
239
ChannelConductivity( N ), &
240
MASS( N, N ), &
241
STIFF( N, N ), LOAD( N ), &
242
FORCE( N ), &
243
IsGhostNode( M ), &
244
lr(N), hr(N), Ar(N), Wopen(N), Afactor(N), Bfactor(N), &
245
MoulinArea(N), MoulinFlux(N), &
246
ub(N), Snn(N), Ev(N), &
247
ng(N), alphas(N), betas(N), betac(N), Phi0(N), Phim(N), &
248
IceDensity(N), Ac(N), alphac(N), CCt(N), &
249
CCw(N), lc(N), OldValues(K), NoChannel(M), NodalNoChannel(N), &
250
Vvar(M), ublr(M), hr2(M), &
251
refq(dim*M), &
252
STAT=istat)
253
254
IF ( istat /= 0 ) THEN
255
CALL FATAL( SolverName, 'Memory allocation error' )
256
ELSE
257
CALL INFO(SolverName, 'Memory allocation done', level=1 )
258
END IF
259
260
! get the ghost nodes of this partition
261
IF ( ParEnv % PEs > 1 ) THEN !only if we have a parallel run
262
IsGhostNode( 1:M ) = .FALSE.
263
GhostNodes = 0;
264
DO t=1,Solver % NumberOfActiveElements
265
Element => GetActiveElement(t)
266
IF (ParEnv % myPe == Element % partIndex) CYCLE
267
DO i=1,GetElementNOFNodes(Element)
268
IsGhostNode(Element % NodeIndexes(i)) = .TRUE.
269
GhostNodes = GhostNodes + 1
270
END DO
271
END DO
272
PRINT *, ParEnv % myPe, ':', GhostNodes, ' ghost nodes'
273
END IF
274
275
! Find the nodes for which we have no channel (on the boundary)
276
! Default is False - We allow Channel to growth everywhere
277
NoChannel = .False.
278
DO t=1, Mesh % NumberOfBoundaryElements
279
! get element information
280
Element => GetBoundaryElement(t)
281
!IF ( .NOT.ActiveBoundaryElement() ) CYCLE
282
IF (ParEnv % PEs > 1) THEN
283
IF (ParEnv % myPe /= Mesh % ParallelInfo % EdgeNeighbourList(t) % Neighbours(1)) CYCLE
284
END IF
285
n = GetElementNOFNodes()
286
IF ( GetElementFamily() == 1 ) CYCLE
287
288
NULLIFY(BC)
289
BC => GetBC( Element )
290
bc_id = GetBCId( Element )
291
NodalNoChannel = .False.
292
NodalNoChannel(1:n) = GetLogical(BC, 'No Channel BC', Found)
293
IF (Found) NoChannel(Element % NodeIndexes(1:n)) = NodalNoChannel(1:n)
294
END DO
295
296
AllocationsDone = .TRUE.
297
END IF
298
299
300
!------------------------------------------------------------------------------
301
! Read physical and numerical constants and initialize
302
!------------------------------------------------------------------------------
303
IF (FirstTime) THEN
304
FirstTime = .FALSE.
305
Constants => GetConstants()
306
307
WaterDensity = ListGetConstReal( Constants, 'Fresh Water Density', Found )
308
IF (.NOT. Found) THEN
309
WaterDensity = ListGetConstReal( Constants, 'Water Density', Found )
310
IF (Found) THEN
311
WRITE(Message,'(A)') 'Constant name >Water Density< has been &
312
replaced with >Fresh Water Density< due to naming conflict'
313
CALL WARN(SolverName, Message )
314
END IF
315
CALL FATAL(SolverName, 'Constant >Fresh Water Density< not found')
316
END IF
317
318
gravity = ListGetConstReal( Constants, 'Gravity Norm', UnFoundFatal=.TRUE. )
319
Lw = ListGetConstReal( Constants, 'Latent Heat', UnFoundFatal=.TRUE. )
320
321
ChannelAreaName = GetString( Constants, &
322
'Channel Area Variable Name', Found )
323
IF(.NOT.Found) THEN
324
CALL WARN(SolverName,'Keyword >Channel Area Variable Name< not found in section Constants')
325
CALL WARN(SolverName,'Taking default value >Channel Area<')
326
WRITE(ChannelAreaName,'(A)') 'Channel Area'
327
END IF
328
329
SheetThicknessName = GetString( Constants, &
330
'Sheet Thickness Variable Name', Found )
331
IF(.NOT.Found) THEN
332
CALL WARN(SolverName,'Keyword >Sheet Thickness Variable Name< not found in section Constants')
333
CALL WARN(SolverName,'Taking default value >Sheet Thickness<')
334
WRITE(SheetThicknessName,'(A)') 'Sheet Thickness'
335
END IF
336
337
ZbName = GetString( Constants, 'Bedrock Variable Name', Found )
338
IF (Found) THEN
339
ZbSol => VariableGet( Solver % Mesh % Variables, ZbName, UnFoundFatal=.TRUE. )
340
ELSE
341
CALL WARN(SolverName,'Keyword >Bedrock Variable Name< not found in section Constants')
342
CALL WARN(SolverName,'Taking default value >zb<')
343
WRITE(ZbName,'(A)') 'Zb'
344
END IF
345
346
!CHANGE - to get Channel variables added to this solver mesh if
347
!doing calving and hydrology and consequently having many meshes
348
Calving = ListGetLogical(Model % Simulation, 'Calving', Found)
349
IF(.NOT.Found) Calving = .FALSE.
350
IF(Calving) THEN
351
DO i=1,Model % NumberOfSolvers
352
IF(Model % Solvers(i) % Variable % Name == ChannelAreaName) THEN
353
ChannelSolver = i
354
EXIT
355
END IF
356
END DO
357
WorkVar => VariableGet(Model % Solvers(ChannelSolver) % Mesh&
358
% Variables, ChannelAreaName, ThisOnly=.TRUE.)
359
ALLOCATE(CAPerm(SIZE(WorkVar % Perm)), CAValues(SIZE(WorkVar % Values)))
360
CAPerm = WorkVar % Perm
361
CAValues = WorkVar % Values
362
CALL VariableAdd(Mesh % Variables, Mesh, Solver,&
363
'Channel Area', 1, CAValues, CAPerm)
364
WorkVar => VariableGet(Mesh % Variables, 'Channel Area',&
365
ThisOnly=.TRUE.)
366
ALLOCATE(WorkVar % PrevValues(SIZE(WorkVar % Values),MAX(Solver&
367
% Order, Solver % TimeOrder)))
368
WorkVar % PrevValues(:,1) = WorkVar % Values
369
370
WorkVar => VariableGet(Model % Solvers(ChannelSolver) % Mesh&
371
% Variables, 'Channel Flux', ThisOnly=.TRUE.)
372
ALLOCATE(CFPerm(SIZE(WorkVar % Perm)), CFValues(SIZE(WorkVar % Values)))
373
CFPerm = WorkVar % Perm
374
CFValues = WorkVar % Values
375
CALL VariableAdd(Mesh % Variables, Mesh, Solver,&
376
'Channel Flux', 1, CFValues, CFPerm)
377
WorkVar => VariableGet(Mesh % Variables, 'Channel Flux',&
378
ThisOnly=.TRUE.)
379
ALLOCATE(WorkVar % PrevValues(SIZE(WorkVar % Values),MAX(Solver&
380
% Order, Solver % TimeOrder)))
381
WorkVar % PrevValues(:,1) = WorkVar % Values
382
383
!The same for sheet thickness
384
DO i=1,Model % NumberOfSolvers
385
IF(Model % Solvers(i) % Variable % Name == SheetThicknessName) THEN
386
ThicknessSolver = i
387
EXIT
388
END IF
389
END DO
390
WorkVar => VariableGet(Model % Solvers(ThicknessSolver) % Mesh&
391
% Variables, SheetThicknessName, ThisOnly=.TRUE.)
392
ALLOCATE(SHPerm(SIZE(WorkVar % Perm)), SHValues(SIZE(WorkVar % Values)))
393
SHPerm = WorkVar % Perm
394
SHValues = WorkVar % Values !Needed to reflect initial condition
395
CALL VariableAdd(Mesh % Variables, Mesh, Solver,&
396
'Sheet Thickness', 1, SHValues, SHPerm)
397
WorkVar => VariableGet(Mesh % Variables, 'Sheet Thickness',&
398
ThisOnly=.TRUE.)
399
ALLOCATE(WorkVar % PrevValues(SIZE(WorkVar % Values),MAX(Solver&
400
% Order, Solver % TimeOrder)))
401
WorkVar % PrevValues(:,1) = WorkVar % Values
402
!Necessary to ensure initial condition value reflected in PrevValues
403
WorkVar % PrevValues(:,1) = WorkVar % Values
404
NULLIFY(WorkVar)
405
END IF
406
407
! TODO : implement higher order BDF method
408
BDForder = GetInteger(GetSimulation(),'BDF Order', Found)
409
IF (.NOT.Found) BDForder = 1
410
IF (BDForder /= 1) THEN
411
WRITE(Message,'(a)') 'Only working for BDF = 1'
412
CALL FATAL(SolverName, Message)
413
END IF
414
END IF ! FirstTime
415
416
SolverParams => GetSolverParams()
417
418
HaveMoulinMask = GetLogical( SolverParams,'Have Moulin Mask', Found)
419
IF (Found) THEN
420
WRITE(Message, *) 'Have Moulin Mask set to', HaveMoulinMask
421
CALL INFO(SolverName,Message,Level=1)
422
END IF
423
424
NeglectH = GetLogical( SolverParams,'Neglect Sheet Thickness in Potential', Found )
425
IF ( .NOT.Found ) THEN
426
CALL FATAL(SolverName, 'No >Neglect Sheet Thickness in Potential< found')
427
END IF
428
429
methodSheet = GetString( SolverParams, 'Sheet Integration Method', Found )
430
IF(.NOT.Found) THEN
431
CALL FATAL(SolverName, 'No >Sheet Integration Methods< found')
432
ELSE
433
IF ((methodSheet /='explicit').AND.(methodSheet /='implicit').AND.(methodSheet /= 'crank-nicolson')) THEN
434
CALL FATAL(SolverName, 'Sheet Integration Method: Implicit, Explicit or Crank-Nicolson')
435
END IF
436
END IF
437
438
Channels = GetLogical( SolverParams,'Activate Channels', Found )
439
IF (.NOT. Found) Channels = .FALSE.
440
441
!CHANGE
442
!To pick up channel and sheet size limiters, if specified
443
MaxArea = GetConstReal( SolverParams, &
444
'Max Channel Area', MABool )
445
IF ((.NOT. MABool)) CALL WARN(SolverName,'No max channel area specified. &
446
Channels may grow very large')
447
448
LimitEffPres = GetLogical( SolverParams, &
449
'Limit Negative Effective Pressure', Found)
450
IF (.NOT.Found) LimitEffPres= .FALSE.
451
452
MaxH = GetConstReal( SolverParams, &
453
'Max Sheet Thickness', MaxHBool )
454
IF ((.NOT. MaxHBool)) CALL WARN(SolverName,'No max sheet thickness specified.&
455
Sheet may grow very large')
456
457
MinH = GetConstReal( SolverParams, &
458
'Min Sheet Thickness', MinHBool )
459
460
461
IF (Channels) THEN
462
meltChannels = GetLogical( SolverParams,'Activate Melt From Channels', Found )
463
IF ( .NOT.Found ) THEN
464
CALL FATAL(SolverName, 'No >Activate Melt From Channels< found')
465
END IF
466
467
methodChannels = GetString( SolverParams, 'Channels Integration Method', Found )
468
IF(.NOT.Found) THEN
469
CALL FATAL(SolverName, 'No >Channels Integration Methods< found')
470
ELSE
471
IF ((methodChannels /= 'explicit').AND.(methodChannels /= 'implicit').AND.(methodChannels /= 'crank-nicolson')) THEN
472
CALL FATAL(SolverName, 'Channels Integration Method: Implicit, Explicit or Crank-Nicolson')
473
END IF
474
END IF
475
END IF
476
477
NonlinearIter = GetInteger( SolverParams, &
478
'Nonlinear System Max Iterations', Found )
479
IF ( .NOT.Found ) NonlinearIter = 1
480
481
NonlinearIterMin = GetInteger( SolverParams, &
482
'Nonlinear System Min Iterations', Found )
483
IF ( .NOT.Found ) NonlinearIterMin = 1
484
485
NonlinearTol = GetConstReal( SolverParams, &
486
'Nonlinear System Convergence Tolerance', Found )
487
IF ((.Not.Found).AND.(NonlinearIter>1)) CALL FATAL(SolverName,'Need >Nonlinear System Convergence Tolerance<')
488
489
CoupledIter = GetInteger( SolverParams, &
490
'Coupled Max Iterations', Found)
491
IF ( .NOT.Found ) CoupledIter = 1
492
493
CoupledTol = GetConstReal( SolverParams, &
494
'Coupled Convergence Tolerance', Found )
495
IF ((.Not.Found).AND.(CoupledIter>1)) CALL FATAL(SolverName,'Need >Nonlinear System Convergence Tolerance<')
496
497
ThickSol => VariableGet( Mesh % Variables, SheetThicknessName, UnfoundFatal = .TRUE. )
498
ThickPerm => ThickSol % Perm
499
ThickSolution => ThickSol % Values
500
ThickPrev => ThickSol % PrevValues
501
IF (HaveMoulinMask) THEN
502
MoulinMaskSol => VariableGet( Solver % Mesh % Variables, "Moulin Mask", UnFoundFatal=.TRUE. )
503
IF (.NOT.ASSOCIATED(MoulinMaskSol)) CALL FATAL(SolverName,">Have Moulin Mask< declared but no >Moulin Mask< variable found")
504
MoulinMaskPerm => MoulinMaskSol % Perm
505
MoulinMask => MoulinMaskSol % Values
506
MoulinFluxSol => VariableGet( Solver % Mesh % Variables, "Moulin Flux", UnFoundFatal=.TRUE. )
507
IF (.NOT.ASSOCIATED(MoulinMaskSol)) CALL FATAL(SolverName,">Have Moulin Mask< declared but no >Moulin Flux< variable found")
508
MoulinFluxPerm => MoulinFluxSol % Perm
509
MoulinFluxVal => MoulinFluxSol % Values
510
END IF
511
512
IF (Channels) THEN
513
AreaSol => VariableGet( Mesh % Variables, ChannelAreaName, UnfoundFatal = .TRUE. )
514
AreaPerm => AreaSol % Perm
515
AreaSolution => AreaSol % Values
516
AreaPrev => AreaSol % PrevValues
517
518
! flux in the channels (for output only) - edge type variable
519
QcSol => VariableGet( Mesh % Variables, "Channel Flux" )
520
IF ( ASSOCIATED( QcSol ) ) THEN
521
QcPerm => QcSol % Perm
522
QcSolution => QcSol % Values
523
END IF
524
END IF
525
526
! discharge out of the moulins (for output only)
527
QmSol => VariableGet( Mesh % Variables, "Flux from Moulins" )
528
IF ( ASSOCIATED( QmSol ) ) THEN
529
QmPerm => QmSol % Perm
530
QmSolution => QmSol % Values
531
END IF
532
533
ZbSol => VariableGet( Mesh % Variables, ZbName )
534
IF ( ASSOCIATED( ZbSol ) ) THEN
535
ZbPerm => ZbSol % Perm
536
ZbSolution => ZbSol % Values
537
END IF
538
539
dt = Timestep
540
541
!------------------------------------------------------------------------------
542
! Read the other variables needed
543
!------------------------------------------------------------------------------
544
VSol => VariableGet( Mesh % Variables, 'Vclose' )
545
IF ( ASSOCIATED( VSol ) ) THEN
546
VPerm => VSol % Perm
547
VSolution => VSol % Values
548
END IF
549
550
WSol => VariableGet( Mesh % Variables, 'Wopen' )
551
IF ( ASSOCIATED( WSol ) ) THEN
552
WPerm => WSol % Perm
553
WSolution => WSol % Values
554
END IF
555
556
NSol => VariableGet( Mesh % Variables, 'Effective Pressure' )
557
IF ( ASSOCIATED( NSol ) ) THEN
558
NPerm => NSol % Perm
559
NSolution => NSol % Values
560
END IF
561
562
PwSol => VariableGet( Mesh % Variables, 'Water Pressure' )
563
IF ( ASSOCIATED( PwSol ) ) THEN
564
PwPerm => PwSol % Perm
565
PwSolution => PwSol % Values
566
END IF
567
568
qSol => VariableGet( Mesh % Variables, 'Sheet Discharge' )
569
IF ( ASSOCIATED( qSol ) ) THEN
570
qPerm => qSol % Perm
571
qSolution => qSol % Values
572
END IF
573
574
hstoreSol => VariableGet( Mesh % Variables, 'Sheet Storage' )
575
IF ( ASSOCIATED( hstoreSol ) ) THEN
576
hstorePerm => hstoreSol % Perm
577
hstoreSolution => hstoreSol % Values
578
END IF
579
580
!------------------------------------------------------------------------------
581
! Loop for the coupling of the three equations
582
!------------------------------------------------------------------------------
583
! check on the coupled Convergence is done on the potential solution only
584
PrevCoupledNorm = ComputeNorm( Solver, SIZE(HydPot), HydPot )
585
586
587
DO iterC = 1, CoupledIter
588
589
!------------------------------------------------------------------------------
590
! non-linear system iteration loop
591
!------------------------------------------------------------------------------
592
DO iter = 1, NonlinearIter
593
!------------------------------------------------------------------------------
594
! print out some information
595
!------------------------------------------------------------------------------
596
at = CPUTime()
597
at0 = RealTime()
598
599
CALL Info( SolverName, ' ', Level=4 )
600
CALL Info( SolverName, ' ', Level=4 )
601
CALL Info( SolverName, '-------------------------------------',Level=4 )
602
WRITE( Message,'(A,A,I3,A,I3)') &
603
TRIM(Solver % Variable % Name), ' iteration no.', iter,' of ',NonlinearIter
604
CALL Info( SolverName, Message, Level=4 )
605
CALL Info( SolverName, '-------------------------------------',Level=4 )
606
CALL Info( SolverName, ' ', Level=4 )
607
CALL Info( SolverName, 'Starting Assembly...', Level=4 )
608
609
Ne = Mesh % NumberOfEdges
610
611
!------------------------------------------------------------------------------
612
! lets start
613
!------------------------------------------------------------------------------
614
CALL DefaultInitialize()
615
body_id = -1
616
NULLIFY(Material)
617
!------------------------------------------------------------------------------
618
! Bulk elements (the sheet layer)
619
!------------------------------------------------------------------------------
620
DO t=1,Solver % NumberOfActiveElements
621
!------------------------------------------------------------------------------
622
! write some info on status of assembly
623
!------------------------------------------------------------------------------
624
IF ( RealTime() - at0 > 1.0 ) THEN
625
WRITE(Message,'(a,i3,a)' ) ' Assembly: ', INT(100.0 - 100.0 * &
626
(Solver % NumberOfActiveElements-t) / &
627
(1.0*Solver % NumberOfActiveElements)), ' % done'
628
629
CALL Info( SolverName, Message, Level=5 )
630
at0 = RealTime()
631
END IF
632
!------------------------------------------------------------------------------
633
! Check if this element belongs to a body where scalar equation
634
! should be calculated
635
!------------------------------------------------------------------------------
636
Element => GetActiveElement(t,Solver)
637
638
! cycle halo elements
639
!-------------------
640
IF (ParEnv % myPe /= Element % partIndex) CYCLE
641
642
IF (.NOT.ASSOCIATED(Element)) CYCLE
643
IF ( Element % BodyId /= body_id ) THEN
644
body_id = Element % bodyId
645
Equation => GetEquation()
646
IF (.NOT.ASSOCIATED(Equation)) THEN
647
WRITE (Message,'(A,I3)') 'No Equation found for boundary element no. ', t
648
CALL FATAL(SolverName,Message)
649
END IF
650
651
Material => GetMaterial()
652
IF (.NOT.ASSOCIATED(Material)) THEN
653
WRITE (Message,'(A,I3)') 'No Material found for boundary element no. ', t
654
CALL FATAL(SolverName,Message)
655
ELSE
656
material_id = GetMaterialId( Element, Found)
657
IF(.NOT.Found) THEN
658
WRITE (Message,'(A,I3)') 'No Material ID found for boundary element no. ', t
659
CALL FATAL(SolverName,Message)
660
END IF
661
END IF
662
END IF
663
!------------------------------------------------------------------------------
664
! Check if Element dimension is 2 (in x, y plane)
665
!------------------------------------------------------------------------------
666
dimSheet = Element % TYPE % DIMENSION
667
IF(dimSheet>2) THEN
668
WRITE (Message,'(A,I3)')' Work only for 1D or 2D elements'
669
CALL FATAL(SolverName,Message)
670
END IF
671
672
!------------------------------------------------------------------------------
673
! Get element material parameters
674
!------------------------------------------------------------------------------
675
N = GetElementNOFNodes(Element)
676
CALL GetElementNodes( ElementNodes )
677
678
!----------------------------------------------------
679
! Get parameters to compute the Total Conductivity
680
! K = k . f(h) . |grad HydPot |^(beta-2)
681
! k = SheetConductivity
682
! f(h) = h^alphas
683
!
684
! And read parameters to evaluate v - w
685
! w = u_b/l_r (h_r - h)
686
! N = p_i + rhow . g . b - HydPot
687
! v = A . h . | N |^{n-1} . N
688
!----------------------------------------------------
689
690
CALL GetParametersSheet( Element, Material, N, SheetConductivity, alphas, &
691
betas, Ev, ub, Snn, lr, hr, Ar, ng )
692
693
CT = 0.0_dp
694
Wopen = 0.0_dp
695
Phi0 = 0.0_dp
696
DO i=1, n
697
j = Element % NodeIndexes(i)
698
k = ThickPerm(j)
699
IF ( ASSOCIATED( ZbSol )) THEN
700
zb = ZbSolution(ZbPerm(j))
701
ELSE
702
IF (dimSheet==1) THEN
703
zb = Mesh % Nodes % y(j)
704
ELSE
705
zb = Mesh % Nodes % z(j)
706
END IF
707
END IF
708
CT(i) = Ev(i) /( WaterDensity * gravity)
709
Wopen(i) = MAX(ub(i) / lr(i) * (hr(i) - ThickSolution(k)), 0.0)
710
711
Phi0(i) = Snn(i) + gravity*WaterDensity*zb
712
IF (.NOT. NeglectH) THEN
713
Phi0(i) = Phi0(i) + gravity*WaterDensity*ThickSolution(k)
714
END IF
715
END DO
716
717
!------------------------------------------------------------------------------
718
! Add body forces
719
!------------------------------------------------------------------------------
720
LOAD = 0.0_dp
721
722
BodyForce => GetBodyForce()
723
!IF ( ASSOCIATED( BodyForce ) ) THEN
724
! bf_id = GetBodyForceId()
725
! LOAD(1:N) = LOAD(1:N) + &
726
! GetReal( BodyForce, TRIM(Solver % Variable % Name) // ' Volume Source', Found )
727
!END IF
728
! f = m - w + v
729
! v is not added here as it will be linearized for the assembly
730
LOAD(1:N) = LOAD(1:N) - Wopen(1:N)
731
732
!------------------------------------------------------------------------------
733
! Get element local matrices, and RHS vectors
734
!------------------------------------------------------------------------------
735
MASS = 0.0_dp
736
STIFF = 0.0_dp
737
FORCE = 0.0_dp
738
! cartesian coords
739
!----------------
740
IF ( CurrentCoordinateSystem() == Cartesian ) THEN
741
CALL SheetCompose( MASS, STIFF, FORCE, LOAD, &
742
ThickSolution(ThickPerm(Element % NodeIndexes(1:n))), &
743
HydPot(HydPotPerm(Element % NodeIndexes(1:N))), &
744
CT(1:N), SheetConductivity(1:n), alphas(1:n), betas(1:n), &
745
Phi0(1:n), Ar(1:n), ng(1:n), Element, N, ElementNodes )
746
ELSE
747
WRITE(Message,'(A)')' Work only for cartesian coordinate'
748
CALL FATAL( SolverName, Message)
749
END IF
750
!------------------------------------------------------------------------------
751
! If time dependent simulation add mass matrix to stiff matrix
752
!------------------------------------------------------------------------------
753
IF ( TransientSimulation ) THEN
754
CALL Default1stOrderTime( MASS, STIFF, FORCE )
755
END IF
756
757
CALL DefaultUpdateEquations( STIFF, FORCE )
758
END DO ! Bulk elements
759
760
! TODO: Is this really needed?
761
CALL DefaultFinishBulkAssembly()
762
763
!------------------------------------------------------------------------------
764
! Edge element (the channels)
765
! Edge element are created in the SIF file using Element = 'n=1 e:1'
766
!------------------------------------------------------------------------------
767
! Go only if Activate Channels is True
768
!------------------------------------------------------------------------------
769
IF (Channels) THEN
770
body_id = -1
771
NULLIFY(Material)
772
DO t=1, Mesh % NumberOfEdges
773
Edge => Mesh % Edges(t)
774
IF (.NOT.ASSOCIATED(Edge)) CYCLE
775
IF (ParEnv % PEs > 1) THEN
776
IF (ParEnv % myPe /= Mesh % ParallelInfo % EdgeNeighbourList(t) % Neighbours(1)) CYCLE
777
END IF
778
n = Edge % TYPE % NumberOfNodes
779
780
! Work only for 202 elements => n=2
781
IF (n/=2) CALL FATAL(SolverName, 'Work only for edge element of type 202')
782
! We keep only the edge which belong in the sheet surface
783
! i.e. Both nodes have Perm > 0
784
IF (ANY(HydPotPerm(Edge % NodeIndexes(1:n))==0)) CYCLE
785
786
! We check if we are in a boundary where we want No channel
787
IF (ALL(NoChannel(Edge % NodeIndexes(1:n)))) CYCLE
788
789
790
EdgeNodes % x(1:n) = Mesh % Nodes % x(Edge % NodeIndexes(1:n))
791
EdgeNodes % y(1:n) = Mesh % Nodes % y(Edge % NodeIndexes(1:n))
792
EdgeNodes % z(1:n) = Mesh % Nodes % z(Edge % NodeIndexes(1:n))
793
794
! Compute the unit tangent vector of the edge
795
EdgeTangent(1) = EdgeNodes % x(2) - EdgeNodes % x(1)
796
EdgeTangent(2) = EdgeNodes % y(2) - EdgeNodes % y(1)
797
EdgeTangent(3) = EdgeNodes % z(2) - EdgeNodes % z(1)
798
EdgeTangent = EdgeTangent / SQRT(SUM(EdgeTangent*EdgeTangent))
799
800
! Read in the Material Section the needed Parameters for the
801
! Channels -
802
! In case DIM = 2 Faces have a material ASSOCIATED
803
! In case DIM = 3, Bulk elements have material ASSOCIATED
804
IF (DIM==2) THEN
805
Bulk => Edge % BoundaryInfo % Left
806
IF (.Not.ASSOCIATED(Bulk)) Bulk => Edge % BoundaryInfo % Right
807
ELSE
808
Face => Edge % BoundaryInfo % Left
809
IF (.Not.ASSOCIATED(Face)) Face => Edge % BoundaryInfo % Right
810
IF (ASSOCIATED(Face)) THEN
811
Bulk => Face % BoundaryInfo % Left
812
IF (.Not.ASSOCIATED(Bulk)) Bulk => Face % BoundaryInfo % Right
813
END IF
814
END IF
815
IF (.Not.ASSOCIATED(Bulk)) THEN
816
WRITE(Message,'(a,i0)')'No face or bulk element associated to edge no:', t
817
CALL FATAL(SolverName, Message)
818
END IF
819
820
IF ( Bulk % BodyId /= body_id ) THEN
821
body_id = Bulk % bodyId
822
Material => GetMaterial( Bulk )
823
IF (.NOT.ASSOCIATED(Material)) THEN
824
WRITE (Message,'(A,I3)') 'No Material found for edge no. ', t
825
CALL FATAL(SolverName,Message)
826
ELSE
827
material_id = GetMaterialId( Bulk, Found)
828
IF(.NOT.Found) THEN
829
WRITE (Message,'(A,I3)') 'No Material ID found for edge no. ', t
830
CALL FATAL(SolverName,Message)
831
END IF
832
END IF
833
END IF
834
835
!----------------------------------------------------
836
! Get parameters to compute the Total Conductivity
837
! Kc = kc . fc(h) . |grad HydPot |^(betac-2)
838
! kc = ChannelConductivity
839
! fc(h) = S^alphac
840
! and the closure and opening velocity for Channels
841
!----------------------------------------------------
842
843
CALL GetParametersChannel( Edge, Material, n, SheetConductivity, &
844
ChannelConductivity, alphac, betac, alphas, betas, IceDensity, &
845
Snn, Ac, ng, CCt, CCw, lc )
846
847
Phi0 = 0.0_dp
848
Afactor = 0.0_dp
849
Bfactor = 0.0_dp
850
Phi0 = 0.0_dp
851
Phim = 0.0_dp
852
DO i=1,N
853
IF ( ASSOCIATED( ZbSol )) THEN
854
zb = ZbSolution(ZbPerm(Edge % NodeIndexes(i)))
855
ELSE
856
IF (dimSheet==1) THEN
857
zb = Mesh % Nodes % y(Edge % NodeIndexes(i))
858
ELSE
859
zb = Mesh % Nodes % z(Edge % NodeIndexes(i))
860
END IF
861
END If
862
Phim(i) = gravity*WaterDensity*zb
863
Phi0(i) = Snn(i) + Phim(i)
864
IF (.NOT. NeglectH) THEN
865
k = ThickPerm(Edge % NodeIndexes(i))
866
Phi0(i) = Phi0(i) + gravity*WaterDensity*ThickSolution(k)
867
END IF
868
Afactor(i) = CCt(i) * CCw(i) * WaterDensity
869
Bfactor(i) = 1.0/(Lw * IceDensity(i))
870
IF (meltChannels) Bfactor(i) = Bfactor(i) - 1.0/(Lw * WaterDensity)
871
END DO
872
873
! The variable Channel Area is defined on the edges only
874
IF (AreaPerm(M+t) <= 0) CYCLE
875
876
!CHANGE
877
!To stabilise channels
878
IF(MABool) THEN
879
IF(AreaSolution(AreaPerm(M+t)) > MaxArea) AreaSolution(AreaPerm(M+t)) = MaxArea
880
END IF
881
ChannelArea = AreaSolution(AreaPerm(M+t))
882
883
!------------------------------------------------------------------------------
884
! Get element local matrices, and RHS vectors
885
!------------------------------------------------------------------------------
886
MASS = 0.0_dp
887
STIFF = 0.0_dp
888
FORCE = 0.0_dp
889
! cartesian coords
890
!----------------
891
892
IF ( CurrentCoordinateSystem() == Cartesian ) THEN
893
CALL ChannelCompose( MASS, STIFF, FORCE, &
894
ThickSolution(ThickPerm(Edge % NodeIndexes(1:n))), &
895
HydPot(HydPotPerm(Edge % NodeIndexes(1:N))), ChannelArea, &
896
ChannelConductivity, alphac, betac, Phi0, Phim, Ac, lc, ng, &
897
SheetConductivity, alphas, betas, Afactor, Bfactor, EdgeTangent, &
898
Edge, n, EdgeNodes )
899
ELSE
900
WRITE(Message,'(A)')' Work only for cartesian coordinate'
901
CALL FATAL( SolverName, Message)
902
END IF
903
!CHANGE
904
!To stop weird channel instability where some channels grow
905
!exponentially to stupid levels and eventually mess up whole
906
!mesh. Usually seems to be channels with limited fluxes that
907
!shouldn't do much, so resetting to 0 seems safest
908
!TODO Come up with a better way of fixing this
909
IF(MABool) THEN
910
k = AreaPerm(M+t)
911
IF(AreaSolution(k) > MaxArea) AreaSolution(k) = MaxArea
912
END IF
913
! This should be not needed as MASS = 0 here
914
IF ( TransientSimulation ) THEN
915
CALL Default1stOrderTime( MASS, STIFF, FORCE, Edge )
916
END IF
917
918
CALL DefaultUpdateEquations( STIFF, FORCE, Edge )
919
END DO ! Edge elements
920
END IF
921
922
923
!------------------------------------------------------------------------------
924
! Neumann & Newton boundary conditions
925
!------------------------------------------------------------------------------
926
IF (HaveMoulinMask) THEN
927
DO t=1,Solver % NumberOfActiveElements
928
Element => GetActiveElement(t,Solver)
929
BodyForce => GetBodyForce()
930
Storage = GetLogical(BodyForce,'Moulin Storage', Found)
931
FORCE = 0.0
932
933
! cycle halo elements
934
!-------------------
935
IF (ParEnv % myPe /= Element % partIndex) CYCLE
936
IF (Storage) THEN
937
MoulinArea(1:N) = ListGetReal( BodyForce, 'Moulin Area', N, Element % NodeIndexes, Found, &
938
UnfoundFatal = .TRUE. )
939
END IF
940
DO I=1,Element % TYPE % NumberOfNodes
941
k = Element % NodeIndexes(I)
942
IF (MoulinMask(MoulinMaskPerm(k)) > 0.0) THEN
943
FORCE(i) = MoulinFluxVal(MoulinFluxPerm(k))
944
MASS(i,i) = MoulinArea(i)/(WaterDensity*gravity)
945
END IF
946
END DO
947
948
IF ( TransientSimulation ) THEN
949
CALL Default1stOrderTime( MASS, STIFF, FORCE, Element )
950
END IF
951
CALL DefaultUpdateEquations( STIFF, FORCE, Element )
952
END DO
953
ELSE
954
DO t=1, Mesh % NumberOfBoundaryElements
955
! get element information
956
Element => GetBoundaryElement(t)
957
! Don't test this as BC on the side are not active for this solver
958
!IF ( .NOT.ActiveBoundaryElement() ) CYCLE
959
960
! cycle halo elements
961
!--------------------
962
IF (ParEnv % myPe /= Element % partIndex) CYCLE
963
n = GetElementNOFNodes()
964
965
IF ( GetElementFamily() == 1 ) THEN
966
! Moulin case (flux at node)
967
968
BC => GetBC( Element )
969
bc_id = GetBCId( Element )
970
CALL GetElementNodes( ElementNodes )
971
IF ( ASSOCIATED( BC ) ) THEN
972
STIFF=0.0_dp
973
FORCE=0.0_dp
974
MASS=0.0_dp
975
976
Storage = GetLogical(BC,'Moulin Storage', Found)
977
IF (Storage) THEN
978
MoulinArea(1:N) = ListGetReal( BC, 'Moulin Area', N, Element % NodeIndexes, Found, &
979
UnfoundFatal = .TRUE. )
980
! MASS is a scalar here
981
MASS(1,1) = MoulinArea(1)/(WaterDensity*gravity)
982
END IF
983
984
! Is there surface input
985
MoulinFlux(1:N) = ListGetReal( BC, 'Moulin Flux', N, Element % NodeIndexes, Found, &
986
UnfoundFatal = .TRUE. )
987
FORCE(1) = MoulinFlux(1)
988
989
! If variable exist, update the Flux from Moulins variable
990
IF (ASSOCIATED( QmSol )) THEN
991
j = Element % NodeIndexes(1)
992
IF ( HydPotPerm(j) <= 0 ) CYCLE
993
QmSolution(QmPerm(j)) = MoulinFlux(1)-MASS(1,1)*(HydPot(HydPotPerm(j))-HydPotPrev(HydPotPerm(j),1))/dt
994
END IF
995
996
!------------------------------------------------------------------------------
997
! Update global matrices from local matrices
998
!------------------------------------------------------------------------------
999
! We need the Default1stOrderUpdate for the Moulin
1000
IF ( TransientSimulation ) THEN
1001
CALL Default1stOrderTime( MASS, STIFF, FORCE, Element )
1002
END IF
1003
CALL DefaultUpdateEquations( STIFF, FORCE, Element )
1004
END IF
1005
1006
ELSE
1007
! flux over the sheet
1008
BC => GetBC( Element )
1009
bc_id = GetBCId( Element )
1010
CALL GetElementNodes( ElementNodes )
1011
1012
IF ( ASSOCIATED( BC ) ) THEN
1013
! Check that we are on the correct boundary part!
1014
STIFF=0.0_dp
1015
FORCE=0.0_dp
1016
MASS=0.0_dp
1017
1018
LOAD=0.0_dp
1019
FluxBC = GetLogical(BC,TRIM(Solver % Variable % Name) // ' Flux BC', Found)
1020
1021
IF (FluxBC) THEN
1022
!---------------
1023
!BC: -k@T/@n = q
1024
!---------------
1025
LOAD(1:N) = LOAD(1:N) + &
1026
GetReal( BC, 'Sheet Water Flux', Found )
1027
! -------------------------------------
1028
! set boundary due to coordinate system
1029
! -------------------------------------
1030
IF ( CurrentCoordinateSystem() == Cartesian ) THEN
1031
CALL SheetBoundary( STIFF, FORCE, &
1032
LOAD, Element, n, ElementNodes )
1033
ELSE
1034
WRITE(Message,'(A)')' Work only for cartesian coordinate'
1035
CALL FATAL( SolverName, Message)
1036
END IF
1037
!!! TODO : do we need that as MASS = 0 here
1038
IF ( TransientSimulation ) THEN
1039
CALL Default1stOrderTime( MASS, STIFF, FORCE, Element )
1040
END IF
1041
1042
CALL DefaultUpdateEquations( STIFF, FORCE, Element )
1043
END IF
1044
END IF
1045
END IF ! Element 1O1
1046
1047
END DO ! Neumann & Newton BCs
1048
END IF ! END IF(HaveMoulinMask)
1049
!------------------------------------------------------------------------------
1050
1051
CALL DefaultFinishAssembly()
1052
1053
CALL DefaultDirichletBCs()
1054
1055
CALL Info( SolverName, 'Assembly done', Level=4 )
1056
1057
!------------------------------------------------------------------------------
1058
! Solve the system and check for convergence
1059
!------------------------------------------------------------------------------
1060
at = CPUTime() - at
1061
st = CPUTime()
1062
Norm = 0.0_dp
1063
1064
PrevNorm = Solver % Variable % Norm
1065
Norm = DefaultSolve()
1066
1067
st = CPUTime()-st
1068
totat = totat + at
1069
totst = totst + st
1070
WRITE(Message,'(a,i4,a,F8.2,F8.2)') 'iter: ',iter,' Assembly: (s)', at, totat
1071
CALL Info( SolverName, Message, Level=4 )
1072
WRITE(Message,'(a,i4,a,F8.2,F8.2)') 'iter: ',iter,' Solve: (s)', st, totst
1073
CALL Info( SolverName, Message, Level=4 )
1074
1075
1076
IF ( PrevNorm + Norm /= 0.0d0 ) THEN
1077
RelativeChange = 2.0d0 * ABS( PrevNorm-Norm ) / (PrevNorm + Norm)
1078
ELSE
1079
RelativeChange = 0.0d0
1080
END IF
1081
1082
WRITE( Message, * ) 'Result Norm : ',Norm
1083
CALL Info( SolverName, Message, Level=4 )
1084
WRITE( Message, * ) 'Relative Change : ',RelativeChange
1085
CALL Info( SolverName, Message, Level=4 )
1086
1087
! !----------------------
1088
! ! check for convergence
1089
! !----------------------
1090
IF ( RelativeChange < NonlinearTol .AND. iter > NonlinearIterMin ) EXIT
1091
END DO ! of the nonlinear iteration
1092
1093
!------------------------------------------------------------------------------
1094
! Update the Sheet Thickness
1095
!------------------------------------------------------------------------------
1096
DO t=1,Solver % NumberOfActiveElements
1097
Element => GetActiveElement(t,Solver)
1098
IF (ParEnv % myPe /= Element % partIndex) CYCLE
1099
1100
IF (.NOT.ASSOCIATED(Element)) CYCLE
1101
IF ( Element % BodyId /= body_id ) THEN
1102
body_id = Element % bodyId
1103
Equation => GetEquation()
1104
IF (.NOT.ASSOCIATED(Equation)) THEN
1105
WRITE (Message,'(A,I3)') 'No Equation found for boundary element no. ', t
1106
CALL FATAL(SolverName,Message)
1107
END IF
1108
1109
Material => GetMaterial()
1110
IF (.NOT.ASSOCIATED(Material)) THEN
1111
WRITE (Message,'(A,I3)') 'No Material found for boundary element no. ', t
1112
CALL FATAL(SolverName,Message)
1113
ELSE
1114
material_id = GetMaterialId( Element, Found)
1115
IF(.NOT.Found) THEN
1116
WRITE (Message,'(A,I3)') 'No Material ID found for boundary element no. ', t
1117
CALL FATAL(SolverName,Message)
1118
END IF
1119
END IF
1120
END IF
1121
1122
N = GetElementNOFNodes(Element)
1123
CALL GetElementNodes( ElementNodes )
1124
1125
!CHANGE
1126
!If calving, cycle elements with ungrounded nodes and zero all
1127
!hydrology variables
1128
IF(Calving) THEN
1129
CycleElement = .FALSE.
1130
WorkVar => VariableGet(Mesh % Variables, "gmcheck", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
1131
WorkVar2 => VariableGet(Mesh % Variables, "groundedmask", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
1132
IF(ASSOCIATED(WorkVar)) THEN
1133
DO i=1, N
1134
IF(WorkVar % Values(WorkVar % Perm(Element % NodeIndexes(i)))>0.0) THEN
1135
!IF(WorkVar2 % Values(WorkVar2 % Perm(Element % NodeIndexes(i)))<0.0) THEN
1136
CycleElement = .TRUE.
1137
1138
WSolution(WPerm(Element % NodeIndexes(i))) = 0.0
1139
Vvar(Element % NodeIndexes(i)) = 0.0
1140
NSolution(NPerm(Element % NodeIndexes(i))) = 0.0
1141
!PwSolution(PwPerm(Element % NodeIndexes(i))) = 0.0
1142
hstoreSolution(hstorePerm(Element % NodeIndexes(i))) = 0.0
1143
!END IF
1144
END IF
1145
END DO
1146
END IF
1147
IF(ASSOCIATED(WorkVar2) .AND. .NOT. ASSOCIATED(WorkVar)) THEN
1148
DO i=1, N
1149
IF(WorkVar2 % Values(WorkVar2 % Perm(Element % NodeIndexes(i)))<0.0) THEN
1150
CycleElement = .TRUE.
1151
1152
WSolution(WPerm(Element % NodeIndexes(i))) = 0.0
1153
Vvar(Element % NodeIndexes(i)) = 0.0
1154
NSolution(NPerm(Element % NodeIndexes(i))) = 0.0
1155
!PwSolution(PwPerm(Element % NodeIndexes(i))) = 0.0
1156
hstoreSolution(hstorePerm(Element % NodeIndexes(i))) = 0.0
1157
END IF
1158
END DO
1159
END IF
1160
NULLIFY(WorkVar, WorkVar2)
1161
IF(CycleElement) CYCLE
1162
END IF
1163
1164
CALL GetParametersSheet( Element, Material, N, SheetConductivity, alphas, &
1165
betas, Ev, ub, Snn, lr, hr, Ar, ng )
1166
1167
CT = 0.0_dp
1168
Phi0 = 0.0_dp
1169
DO i=1, n
1170
j = Element % NodeIndexes(i)
1171
k = ThickPerm(j)
1172
IF ( ASSOCIATED( ZbSol )) THEN
1173
zb = ZbSolution(ZbPerm(j))
1174
ELSE
1175
IF (dimSheet==1) THEN
1176
zb = Mesh % Nodes % y(j)
1177
ELSE
1178
zb = Mesh % Nodes % z(j)
1179
END IF
1180
END IF
1181
CT(i) = Ev(i) /( WaterDensity * gravity)
1182
Phi0(i) = Snn(i) + gravity*WaterDensity*zb
1183
Np = Phi0(i) - HydPot(HydPotPerm(j))
1184
IF (.NOT. NeglectH) THEN
1185
Np = Np + WaterDensity*gravity*ThickSolution(k)
1186
END IF
1187
pw = HydPot(HydPotPerm(j)) - gravity*WaterDensity*zb
1188
Vvar(j) = Ar(i)*ABS(Np)**(ng(i)-1.0)*Np
1189
Wo = MAX(ub(i) / lr(i) * (hr(i) - ThickSolution(k)), 0.0)
1190
he = Ev(i)*(HydPot(HydPotPerm(j))/(WaterDensity*gravity)-zb)
1191
ublr(j) = ub(i)/lr(i)
1192
hr2(j) = hr(i)
1193
1194
!CHANGE
1195
!To stop it working out values for non-ice covered parts of a
1196
!hydromesh in a coupled calving-hydro simulation
1197
IF(Calving) THEN
1198
IF(Snn(i)==0.0) THEN
1199
Np = 0.0
1200
!pw = 0.0
1201
he = 0.0
1202
END IF
1203
END IF
1204
1205
! Save this for output only
1206
IF (ASSOCIATED(WSol)) WSolution(WPerm(j)) = Wo
1207
IF (ASSOCIATED(NSol)) NSolution(NPerm(j)) = Np
1208
IF (ASSOCIATED(PwSol)) PwSolution(PwPerm(j)) = pw
1209
IF (ASSOCIATED(hstoreSol)) hstoreSolution(hstorePerm(j)) = he
1210
END DO
1211
END DO ! Bulk elements
1212
! Loop over all nodes to update ThickSolution
1213
DO j = 1, Mesh % NumberOfNodes
1214
k = ThickPerm(j)
1215
IF (k==0) CYCLE
1216
!CHANGE
1217
!If calving, cycle elements with ungrounded nodes and zero all
1218
!hydrology variables
1219
IF(Calving) THEN
1220
CycleElement = .FALSE.
1221
WorkVar => VariableGet(Mesh % Variables, "gmcheck", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
1222
WorkVar2 => VariableGet(Mesh % Variables, "groundedmask", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
1223
IF(ASSOCIATED(WorkVar)) THEN
1224
IF(WorkVar % Values(k)>0.0) THEN !.AND. WorkVar2 % Values(k)<0.0) THEN
1225
CycleElement = .TRUE.
1226
ThickSolution(k) = 0.0
1227
ThickPrev(k,1) = 0.0
1228
END IF
1229
END IF
1230
IF(ASSOCIATED(WorkVar2) .AND. .NOT. ASSOCIATED(WorkVar)) THEN
1231
IF(WorkVar2 % Values(k)<0.0) THEN
1232
CycleElement = .TRUE.
1233
ThickSolution(k) = 0.0
1234
ThickPrev(k,1) = 0.0
1235
END IF
1236
END IF
1237
WorkVar => VariableGet(Mesh % Variables, "hydraulic potential", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
1238
IF(WorkVar % Values(k)==0.0) THEN
1239
ThickSolution(k) = 0.0
1240
ThickPrev(k,1) = 0.0
1241
CycleElement = .TRUE.
1242
END IF
1243
NULLIFY(WorkVar, WorkVar2)
1244
IF(CycleElement) CYCLE
1245
END IF
1246
1247
IF(MaxHBool) THEN
1248
IF (ThickSolution(k)>MaxH) THEN
1249
ThickSolution(k) = MaxH
1250
!ThickPrev(k,1) = 0.0
1251
END IF
1252
END IF
1253
1254
IF(MinHBool) THEN
1255
IF (ThickSolution(k)<MinH) THEN
1256
ThickSolution(k) = MinH
1257
END IF
1258
END IF
1259
1260
SELECT CASE(methodSheet)
1261
CASE('implicit')
1262
IF (ThickSolution(k) > hr2(j)) THEN
1263
ThickSolution(k) = MAX(ThickPrev(k,1)/(1.0_dp + dt*Vvar(j)) , AEPS)
1264
ELSE
1265
ThickSolution(k) = MAX((ThickPrev(k,1) + dt*ublr(j)*hr2(j))/(1.0_dp + dt*(Vvar(j)+ublr(j))) , AEPS)
1266
END IF
1267
CASE('explicit')
1268
IF (ThickSolution(k) > hr2(j)) THEN
1269
ThickSolution(k) = MAX(ThickPrev(k,1)*(1.0_dp - dt*Vvar(j)) , AEPS)
1270
ELSE
1271
ThickSolution(k) = MAX(ThickPrev(k,1)*(1.0_dp - dt*(Vvar(j)+ublr(j))) + dt*ublr(j)*hr2(j), AEPS)
1272
END IF
1273
CASE('crank-nicolson')
1274
IF (ThickSolution(k) > hr2(j)) THEN
1275
ThickSolution(k) = MAX(ThickPrev(k,1)*(1.0_dp - 0.5*dt*Vvar(j))/(1.0_dp + 0.5*dt*Vvar(j)) , AEPS)
1276
ELSE
1277
ThickSolution(k) = MAX((ThickPrev(k,1)*(1.0_dp - 0.5*dt*(Vvar(j)+ublr(j))) + dt*ublr(j)*hr2(j)) &
1278
& /(1.0_dp + 0.5*dt*(Vvar(j)+ublr(j))) , AEPS)
1279
END IF
1280
END SELECT
1281
1282
! Update Vvar
1283
Vvar(j) = Vvar(j) * ThickSolution(k)
1284
1285
END DO
1286
!------------------------------------------------------------------------------
1287
! Update the Channels Area
1288
!------------------------------------------------------------------------------
1289
!------------------------------------------------------------------------------
1290
! non-linear system iteration loop
1291
!------------------------------------------------------------------------------
1292
IF (Channels) THEN
1293
PrevNorm = ChannelAreaNorm()
1294
1295
DO iter = 1, NonlinearIter
1296
DO t=1, Mesh % NumberOfEdges
1297
Edge => Mesh % Edges(t)
1298
IF (.NOT.ASSOCIATED(Edge)) CYCLE
1299
IF (ParEnv % PEs > 1) THEN
1300
IF (ParEnv % myPe /= Mesh % ParallelInfo % EdgeNeighbourList(t) % Neighbours(1)) CYCLE
1301
END IF
1302
n = Edge % TYPE % NumberOfNodes
1303
IF (ANY(HydPotPerm(Edge % NodeIndexes(1:n))==0)) CYCLE
1304
IF (ALL(NoChannel(Edge % NodeIndexes(1:n)))) CYCLE
1305
1306
!CHANGE
1307
!If calving, cycle elements with ungrounded nodes and zero all
1308
!hydrology variables
1309
IF(Calving) THEN
1310
CycleElement = .FALSE.
1311
WorkVar => VariableGet(Mesh % Variables, "gmcheck", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
1312
WorkVar2 => VariableGet(Mesh % Variables, "groundedmask", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
1313
IF(ASSOCIATED(WorkVar)) THEN
1314
DO i=1, n
1315
IF(WorkVar % Values(WorkVar % Perm(Edge % NodeIndexes(i)))>0.0) THEN
1316
!IF(WorkVar2 % Values(WorkVar2 % Perm(Edge % NodeIndexes(i)))<0.0) THEN
1317
CycleElement = .TRUE.
1318
AreaSolution(AreaPerm(M+t)) = 0.0
1319
QcSolution(QcPerm(M+t)) = 0.0
1320
!END IF
1321
END IF
1322
END DO
1323
END IF
1324
IF(ASSOCIATED(WorkVar2) .AND. .NOT. ASSOCIATED(WorkVar)) THEN
1325
DO i=1,n
1326
IF(WorkVar2 % Values(WorkVar2 % Perm(Edge % NodeIndexes(i)))<0.0) THEN
1327
CycleElement = .TRUE.
1328
AreaSolution(AreaPerm(M+t)) = 0.0
1329
QcSolution(QcPerm(M+t)) = 0.0
1330
END IF
1331
END DO
1332
END IF
1333
NULLIFY(WorkVar, WorkVar2)
1334
IF(CycleElement) CYCLE
1335
END IF
1336
1337
EdgeNodes % x(1:n) = Mesh % Nodes % x(Edge % NodeIndexes(1:n))
1338
EdgeNodes % y(1:n) = Mesh % Nodes % y(Edge % NodeIndexes(1:n))
1339
EdgeNodes % z(1:n) = Mesh % Nodes % z(Edge % NodeIndexes(1:n))
1340
1341
! Compute the unit tangent vector of the edge
1342
EdgeTangent(1) = EdgeNodes % x(2) - EdgeNodes % x(1)
1343
EdgeTangent(2) = EdgeNodes % y(2) - EdgeNodes % y(1)
1344
EdgeTangent(3) = EdgeNodes % z(2) - EdgeNodes % z(1)
1345
EdgeTangent = EdgeTangent / SQRT(SUM(EdgeTangent*EdgeTangent))
1346
1347
IF (DIM==2) THEN
1348
Bulk => Edge % BoundaryInfo % Left
1349
IF (.Not.ASSOCIATED(Bulk)) Bulk => Edge % BoundaryInfo % Right
1350
ELSE
1351
Face => Edge % BoundaryInfo % Left
1352
IF (.Not.ASSOCIATED(Face)) Face => Edge % BoundaryInfo % Right
1353
IF (ASSOCIATED(Face)) THEN
1354
Bulk => Face % BoundaryInfo % Left
1355
IF (.Not.ASSOCIATED(Bulk)) Bulk => Face % BoundaryInfo % Right
1356
END IF
1357
END IF
1358
IF (.Not.ASSOCIATED(Bulk)) THEN
1359
WRITE(Message,'(a,i0)')'No face or bulk element associated to edge no:', t
1360
CALL FATAL(SolverName, Message)
1361
END IF
1362
1363
IF ( Bulk % BodyId /= body_id ) THEN
1364
body_id = Bulk % bodyId
1365
Material => GetMaterial( Bulk )
1366
IF (.NOT.ASSOCIATED(Material)) THEN
1367
WRITE (Message,'(A,I3)') 'No Material found for edge no. ', t
1368
CALL FATAL(SolverName,Message)
1369
ELSE
1370
material_id = GetMaterialId( Bulk, Found)
1371
IF(.NOT.Found) THEN
1372
WRITE (Message,'(A,I3)') 'No Material ID found for edge no. ', t
1373
CALL FATAL(SolverName,Message)
1374
END IF
1375
END IF
1376
END IF
1377
1378
CALL GetParametersChannel( Edge, Material, n, SheetConductivity, &
1379
ChannelConductivity, alphac, betac, alphas, betas, IceDensity, &
1380
Snn, Ac, ng, CCt, CCw, lc )
1381
1382
Phi0 = 0.0_dp
1383
Afactor = 0.0_dp
1384
Bfactor = 0.0_dp
1385
Phi0 = 0.0_dp
1386
Phim = 0.0_dp
1387
DO i=1,N
1388
IF ( ASSOCIATED( ZbSol )) THEN
1389
zb = ZbSolution(ZbPerm(Edge % NodeIndexes(i)))
1390
ELSE
1391
IF (dimSheet==1) THEN
1392
zb = Mesh % Nodes % y(Edge % NodeIndexes(i))
1393
ELSE
1394
zb = Mesh % Nodes % z(Edge % NodeIndexes(i))
1395
END IF
1396
END If
1397
Phim(i) = gravity*WaterDensity*zb
1398
Phi0(i) = Snn(i) + Phim(i)
1399
IF (.NOT. NeglectH) THEN
1400
k = ThickPerm(Edge % NodeIndexes(i))
1401
Phi0(i) = Phi0(i) + gravity*WaterDensity*ThickSolution(k)
1402
END IF
1403
Afactor(i) = CCt(i) * CCw(i) * WaterDensity
1404
Bfactor(i) = 1.0/(Lw * IceDensity(i))
1405
END DO
1406
1407
IF (AreaPerm(M+t) <= 0 ) CYCLE
1408
ChannelArea = AreaSolution(AreaPerm(M+t))
1409
1410
! Compute the force term to evolve the channels area
1411
! Equation of the form dS/dt = S x ALPHA + BETA
1412
IF ( CurrentCoordinateSystem() == Cartesian ) THEN
1413
CALL GetEvolveChannel( ALPHA, BETA, Qc, ChannelArea, &
1414
HydPot(HydPotPerm(Edge % NodeIndexes(1:n))), &
1415
ThickSolution(ThickPerm(Edge % NodeIndexes(1:n))), &
1416
alphac, betac, ChannelConductivity, Phi0, Phim, Ac, lc, ng, &
1417
SheetConductivity, alphas, betas, Afactor, Bfactor, &
1418
EdgeTangent, Edge, n, EdgeNodes, LimitEffPres)
1419
ELSE
1420
WRITE(Message,'(A)')' Work only for cartesian coordinate'
1421
CALL FATAL( SolverName, Message)
1422
END IF
1423
1424
k = AreaPerm(M+t)
1425
IF ( k <= 0 ) CYCLE
1426
SELECT CASE(methodChannels)
1427
CASE('implicit')
1428
AreaSolution(k) = (AreaPrev(k,1) + dt*BETA)/(1.0_dp - dt*ALPHA)
1429
CASE('explicit')
1430
AreaSolution(k) = AreaPrev(k,1)*(1.0_dp + dt*ALPHA) + dt*BETA
1431
CASE('crank-nicolson')
1432
AreaSolution(k) = (AreaPrev(k,1)*(1.0_dp + 0.5*ALPHA*dt) + dt*BETA)/(1.0_dp - 0.5*dt*ALPHA)
1433
END SELECT
1434
1435
!CHANGE
1436
!To stop weird channel instability where some channels grow
1437
!exponentially to stupid levels and eventually mess up whole
1438
!mesh. Usually seems to be channels with limited fluxes that
1439
!shouldn't do much, so resetting to 0 seems safest
1440
!TODO Come up with a better way of fixing this
1441
IF(MABool) THEN
1442
IF(AreaPrev(k,1) /= 0.0) THEN
1443
IF(AreaSolution(k)>1.0 .AND. (AreaSolution(k)/AreaPrev(k,1))>5.0) THEN
1444
AreaSolution(k) = AreaPrev(k,1)
1445
END IF
1446
END IF
1447
IF(AreaSolution(k) > MaxArea) AreaSolution(k) = MaxArea
1448
IF(ISNAN(AreaSolution(k))) AreaSolution(k) = 0.0
1449
END IF
1450
1451
! Save Qc if variable exists
1452
IF (ASSOCIATED(QcSol)) THEN
1453
IF ( QcPerm(M+t) <= 0 ) CYCLE
1454
QcSolution(QcPerm(M+t)) = Qc
1455
END IF
1456
END DO
1457
1458
Norm = ChannelAreaNorm()
1459
t = Mesh % NumberOfEdges
1460
1461
IF ( PrevNorm + Norm /= 0.0d0 ) THEN
1462
RelativeChange = 2.0d0 * ABS( PrevNorm-Norm ) / (PrevNorm + Norm)
1463
ELSE
1464
RelativeChange = 0.0d0
1465
END IF
1466
1467
PrevNorm = Norm
1468
1469
WRITE( Message, * ) 'S (NRM,RELC) : ',iter, Norm, RelativeChange
1470
CALL Info( SolverName, Message, Level=3 )
1471
1472
! !----------------------
1473
! ! check for convergence
1474
! !----------------------
1475
IF ( RelativeChange < NonlinearTol .AND. iter > NonlinearIterMin ) EXIT
1476
END DO ! of the nonlinear iteration
1477
1478
1479
! Make sure Area >= 0
1480
AreaSolution = MAX(AreaSolution, 0.0_dp )
1481
1482
!Stop channels from expanding to eleventy-stupid
1483
IF(MABool) THEN
1484
AreaSolution = MIN(AreaSolution,MaxArea)
1485
END IF
1486
1487
END IF ! If Channels
1488
1489
! Check for convergence
1490
CoupledNorm = ComputeNorm( Solver, SIZE(HydPot), HydPot )
1491
1492
IF ( PrevCoupledNorm + CoupledNorm /= 0.0d0 ) THEN
1493
RelativeChange = 2.0d0 * ABS( PrevCoupledNorm-CoupledNorm ) / (PrevCoupledNorm + CoupledNorm)
1494
ELSE
1495
RelativeChange = 0.0d0
1496
END IF
1497
PrevCoupledNorm = CoupledNorm
1498
1499
WRITE( Message, * ) 'COUPLING LOOP (NRM,RELC) : ',iterC, CoupledNorm, RelativeChange
1500
CALL Info( SolverName, Message, Level=3 )
1501
1502
IF ((RelativeChange < CoupledTol).AND. (iterC > 1)) EXIT
1503
END DO ! iterC
1504
1505
!--------------------------------------------------------------------------------------------
1506
! Output some useful variables
1507
!--------------------------------------------------------------------------------------------
1508
! Already computed variables
1509
IF (ASSOCIATED(VSol)) THEN
1510
DO i=1, M
1511
IF ( VPerm(i) <= 0 ) CYCLE
1512
VSolution(VPerm(i)) = Vvar(i)
1513
ENDDO
1514
ENDIF
1515
1516
! Output the sheet discharge (dimension = dimSheet)
1517
IF (ASSOCIATED(qSol)) THEN
1518
Refq = 0.0_dp
1519
qSolution = 0.0_dp
1520
1521
! Loop over all elements are we need to compute grad(Phi)
1522
DO t=1,Solver % NumberOfActiveElements
1523
!CHANGE - necessary if using a 2D mesh as is otherwise set to 1 as
1524
!boundary elements are last in first loop where it's set
1525
dimSheet = Element % TYPE % DIMENSION
1526
Element => GetActiveElement(t,Solver)
1527
IF (ParEnv % myPe /= Element % partIndex) CYCLE
1528
1529
IF (.NOT.ASSOCIATED(Element)) CYCLE
1530
IF ( Element % BodyId /= body_id ) THEN
1531
body_id = Element % bodyId
1532
Material => GetMaterial()
1533
IF (.NOT.ASSOCIATED(Material)) THEN
1534
WRITE (Message,'(A,I3)') 'No Material found for boundary element no. ', t
1535
CALL FATAL(SolverName,Message)
1536
ELSE
1537
material_id = GetMaterialId( Element, Found)
1538
IF(.NOT.Found) THEN
1539
WRITE (Message,'(A,I3)') 'No Material ID found for boundary element no. ', t
1540
CALL FATAL(SolverName,Message)
1541
END IF
1542
END IF
1543
END IF
1544
1545
n = GetElementNOFNodes(Element)
1546
CALL GetElementNodes( ElementNodes )
1547
!If calving, cycle elements with ungrounded nodes and zero all
1548
!hydrology variables
1549
IF(Calving) THEN
1550
CycleElement = .FALSE.
1551
WorkVar => VariableGet(Mesh % Variables, "gmcheck", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
1552
WorkVar2 => VariableGet(Mesh % Variables, "groundedmask", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
1553
IF(ASSOCIATED(WorkVar)) THEN
1554
DO i=1, n
1555
IF(WorkVar % Values(WorkVar % Perm(Element % NodeIndexes(i)))>0.0) THEN
1556
!IF(WorkVar2 % Values(WorkVar2 % Perm(Element % NodeIndexes(i)))<0.0) THEN
1557
CycleElement = .TRUE.
1558
DO j=1,dimSheet
1559
k = dimSheet*(qPerm(Element % NodeIndexes(i))-1)+j
1560
qSolution(k) = 0.0
1561
Refq(k) = 0.0
1562
END DO
1563
EXIT
1564
!END IF
1565
END IF
1566
END DO
1567
END IF
1568
IF(ASSOCIATED(WorkVar2) .AND. .NOT. ASSOCIATED(WorkVar)) THEN
1569
DO i=1,n
1570
IF(WorkVar2 % Values(WorkVar2 % Perm(Element % NodeIndexes(i)))<0.0) THEN
1571
CycleElement = .TRUE.
1572
DO j=1,dimSheet
1573
k = dimSheet*(qPerm(Element % NodeIndexes(i))-1)+j
1574
qSolution(k) = 0.0
1575
Refq(k) = 0.0
1576
END DO
1577
EXIT
1578
END IF
1579
END DO
1580
END IF
1581
NULLIFY(WorkVar, WorkVar2)
1582
IF(CycleElement) CYCLE
1583
END IF
1584
1585
! we need the SheetConductivity, alphas, betas
1586
CALL GetParametersSheet( Element, Material, n, SheetConductivity, alphas, &
1587
betas, Ev, ub, Snn, lr, hr, Ar, ng )
1588
1589
! Go for all nodes of the element
1590
DO i=1,n
1591
Discharge = 0.0_dp
1592
CALL SheetDischargeCompute( &
1593
HydPot(HydPotPerm(Element % NodeIndexes(1:n))), &
1594
ThickSolution(ThickPerm(Element % NodeIndexes(i))), &
1595
SheetConductivity(i), alphas(i), betas(i), &
1596
Discharge, Element, n, ElementNodes, i )
1597
1598
! One more value for that node
1599
DO j=1,dimSheet
1600
k = dimSheet*(qPerm(Element % NodeIndexes(i))-1)+j
1601
Refq(k) = Refq(k) + 1.0_dp
1602
qSolution(k) = qSolution(k) + Discharge(j)
1603
END DO
1604
END DO
1605
END DO
1606
1607
! Mean nodal value
1608
DO i=1,n
1609
DO j=1,dimSheet
1610
k = dimSheet*(qPerm(Element % NodeIndexes(i))-1)+j
1611
IF ( Refq(k) > 0.0_dp ) THEN
1612
qSolution(k) = qSolution(k)/Refq(k)
1613
END IF
1614
END DO
1615
END DO
1616
1617
END IF
1618
1619
SubroutineVisited = .TRUE.
1620
1621
!CHANGE - to make sure PrevValues for added variables in calving updated
1622
IF(Calving) THEN
1623
WorkVar => VariableGet(Mesh % Variables, 'Sheet Thickness',ThisOnly=.TRUE.)
1624
WorkVar % PrevValues(:,1) = WorkVar % Values
1625
WorkVar => VariableGet(Mesh % Variables, 'Channel Area',ThisOnly=.TRUE.)
1626
WorkVar % PrevValues(:,1) = WorkVar % Values
1627
NULLIFY(WorkVar)
1628
END IF
1629
1630
CONTAINS
1631
1632
! Compute consistent channel norm only considering the edges that also have hydrology defined on the nodes.
1633
! In parallel only consider the edges in the partition where it is active.
1634
!----------------------------------------------------------------------------------------------------------
1635
FUNCTION ChannelAreaNorm() RESULT( AreaNorm )
1636
REAL(KIND=dp) :: AreaNorm
1637
1638
INTEGER :: t,i,n,ncount
1639
REAL(KIND=dp) :: s, ssum, smin, smax
1640
1641
ncount = 0
1642
smin = HUGE(smin)
1643
smax = 0.0_dp
1644
ssum = 0.0_dp
1645
1646
DO t=1, Mesh % NumberOfEdges
1647
i = AreaPerm(Mesh % NumberOfNodes + t)
1648
IF(i==0) CYCLE
1649
1650
IF (ParEnv % PEs > 1) THEN
1651
IF (ParEnv % myPe /= Mesh % ParallelInfo % EdgeNeighbourList(t) % Neighbours(1)) CYCLE
1652
END IF
1653
1654
Edge => Mesh % Edges(t)
1655
n = Edge % TYPE % NumberOfNodes
1656
IF (ANY(HydPotPerm(Edge % NodeIndexes(1:n))==0)) CYCLE
1657
1658
s = AreaSolution(i)
1659
1660
ssum = ssum + s**2
1661
smin = MIN(smin,s)
1662
smax = MAX(smax,s)
1663
1664
ncount = ncount + 1
1665
END DO
1666
1667
IF( ParEnv % PEs > 1 ) THEN
1668
ncount = ParallelReduction(ncount)
1669
ssum = ParallelReduction(ssum)
1670
smin = ParallelReduction(smin,1)
1671
smax = ParallelReduction(smax,2)
1672
END IF
1673
1674
WRITE( Message, * ) 'Range S:', smin, smax
1675
CALL Info( SolverName, Message )
1676
1677
AreaNorm = SQRT(ssum / ncount )
1678
1679
END FUNCTION ChannelAreaNorm
1680
1681
1682
1683
!------------------------------------------------------------------------------
1684
SUBROUTINE SheetCompose( MassMatrix, StiffMatrix, ForceVector, &
1685
LoadVector, NodalH, NodalHydPot, NodalCT, NodalC2, Nodalalphas, &
1686
Nodalbetas, NodalPhi0, NodalAr, NodalNg, Element, n, Nodes )
1687
!------------------------------------------------------------------------------
1688
USE MaterialModels
1689
USE Integration
1690
USE Differentials
1691
1692
IMPLICIT NONE
1693
1694
REAL(KIND=dp), DIMENSION(:) :: ForceVector, LoadVector
1695
REAL(KIND=dp), DIMENSION(:,:) :: MassMatrix, StiffMatrix
1696
REAL(KIND=dp) :: NodalHydPot(:), Nodalalphas(:), NodalBetas(:)
1697
REAL(KIND=dp) :: NodalCT(:), NodalC2(:), NodalH(:)
1698
REAL(KIND=dp) :: NodalPhi0(:), NodalAr(:), NodalNg(:)
1699
1700
INTEGER :: n
1701
1702
TYPE(Nodes_t) :: Nodes
1703
TYPE(Element_t), POINTER :: Element
1704
1705
!------------------------------------------------------------------------------
1706
! Local variables
1707
!------------------------------------------------------------------------------
1708
1709
REAL(KIND=dp) :: dBasisdx(n,3), detJ
1710
REAL(KIND=dp) :: Basis(n)
1711
1712
REAL(KIND=dp) :: Force
1713
1714
REAL(KIND=dp) :: A, M
1715
REAL(KIND=dp) :: Load
1716
1717
REAL(KIND=dp) :: x, y, z
1718
1719
INTEGER :: i, j, k, c, p, q, t, dim, N_Integ, NBasis
1720
1721
TYPE(GaussIntegrationPoints_t), TARGET :: IntegStuff
1722
REAL(KIND=dp) :: s, u, v, w
1723
1724
REAL(KIND=dp) :: CT, C2, Vfactor, Phi0, PhiG, LoadAtIP
1725
1726
REAL(KIND=dp) :: gradPhi(3), Ngrad, na, nb, ng, hsheet
1727
1728
REAL(KIND=dp), DIMENSION(:), POINTER :: U_Integ, V_Integ, W_Integ, S_Integ
1729
1730
LOGICAL :: Found, Transient, stat
1731
1732
!------------------------------------------------------------------------------
1733
1734
Transient = GetString(GetSimulation(),'Simulation type',Found)=='transient'
1735
1736
! the dimension for this solver is given by the dim of the elements
1737
! should work for 2D and 3D general problem
1738
dim = Element % TYPE % DIMENSION
1739
1740
ForceVector = 0.0_dp
1741
StiffMatrix = 0.0_dp
1742
MassMatrix = 0.0_dp
1743
Load = 0.0_dp
1744
1745
NBasis = n
1746
1747
!------------------------------------------------------------------------------
1748
! Integration stuff
1749
!------------------------------------------------------------------------------
1750
IntegStuff = GaussPoints( element )
1751
U_Integ => IntegStuff % u
1752
V_Integ => IntegStuff % v
1753
W_Integ => IntegStuff % w
1754
S_Integ => IntegStuff % s
1755
N_Integ = IntegStuff % n
1756
1757
1758
!------------------------------------------------------------------------------
1759
! Now we start integrating
1760
!------------------------------------------------------------------------------
1761
DO t=1,N_Integ
1762
u = U_Integ(t)
1763
v = V_Integ(t)
1764
w = W_Integ(t)
1765
1766
!------------------------------------------------------------------------------
1767
! Basis function values & derivatives at the integration point
1768
!------------------------------------------------------------------------------
1769
stat = ElementInfo( Element, Nodes, u, v, w, detJ, Basis, dBasisdx )
1770
1771
s = detJ * S_Integ(t)
1772
!------------------------------------------------------------------------------
1773
! Coefficient of derivative terms
1774
! at the integration point
1775
!------------------------------------------------------------------------------
1776
CT = SUM( NodalCT(1:n) * Basis(1:n) )
1777
!------------------------------------------------------------------------------
1778
! Compute the effective conductivity K = k h |grad Phi|^{beta-2}
1779
!------------------------------------------------------------------------------
1780
gradPhi = 0.0_dp
1781
Do i=1, dim
1782
gradPhi(i) = SUM(NodalHydPot(1:n)*dBasisdx(1:n,i))
1783
END DO
1784
Ngrad = SQRT(SUM(gradPhi(1:dim)*gradPhi(1:dim)))
1785
IF (Ngrad < AEPS) Ngrad = AEPS
1786
nb = SUM(NodalBetas(1:n)*Basis(1:n))
1787
na = SUM(Nodalalphas(1:n)*Basis(1:n))
1788
hsheet = SUM(NodalH(1:n)*Basis(1:n))
1789
1790
C2 = SUM( NodalC2(1:n) * Basis(1:n))
1791
C2 = C2 * hsheet**na
1792
C2 = C2 * Ngrad**(nb-2.0)
1793
1794
! Vclose velocity is split into Vfactor . (Phi0 - Phi)^(n-1)
1795
PhiG = SUM(NodalHydPot(1:n)*Basis(1:n))
1796
Phi0 = SUM(NodalPhi0(1:n)*Basis(1:n))
1797
Vfactor = SUM(NodalAr(1:n)*Basis(1:n)) * hsheet
1798
ng = SUM(NodalNg(1:n)*Basis(1:n))
1799
Vfactor = Vfactor * ABS(Phi0-PhiG)**(ng-1.0_dp)
1800
1801
Force = SUM( LoadVector(1:n)*Basis(1:n) )
1802
! contribution from volume source (using handle)
1803
LoadAtIP = ListGetElementReal( Load_h, Basis, Element, Found, GaussPoint=t)
1804
IF (Found) THEN
1805
Force = Force + LoadAtIP
1806
END IF
1807
Force = Force + Vfactor * (Phi0 + (ng - 1.0_dp) * PhiG)
1808
1809
!------------------------------------------------------------------------------
1810
! Loop over basis functions of both unknowns and weights
1811
!------------------------------------------------------------------------------
1812
DO p=1,NBasis
1813
DO q=1,NBasis
1814
!------------------------------------------------------------------------------
1815
! The diffusive-convective equation without stabilization
1816
!------------------------------------------------------------------------------
1817
M = CT * Basis(q) * Basis(p)
1818
!------------------------------------------------------------------------------
1819
! The diffusion term
1820
!------------------------------------------------------------------------------
1821
A = C2 * SUM( dBasisdx(q,1:dim) * dBasisdx(p,1:dim))
1822
A = A + Vfactor * ng * Basis(q) * Basis(p)
1823
1824
StiffMatrix(p,q) = StiffMatrix(p,q) + s * A
1825
MassMatrix(p,q) = MassMatrix(p,q) + s * M
1826
END DO
1827
ForceVector(p) = ForceVector(p) + s * Force * Basis(p)
1828
END DO
1829
END DO
1830
1831
!------------------------------------------------------------------------------
1832
END SUBROUTINE SheetCompose
1833
!------------------------------------------------------------------------------
1834
1835
1836
!------------------------------------------------------------------------------
1837
!> Return element local matrices and RSH vector for boundary conditions
1838
!> of diffusion convection equation:
1839
!------------------------------------------------------------------------------
1840
SUBROUTINE SheetBoundary( BoundaryMatrix, BoundaryVector, &
1841
LoadVector, Element, n, Nodes )
1842
!------------------------------------------------------------------------------
1843
USE MaterialModels
1844
USE Integration
1845
USE Differentials
1846
1847
IMPLICIT NONE
1848
REAL(KIND=dp) :: BoundaryMatrix(:,:), BoundaryVector(:), LoadVector(:)
1849
TYPE(Nodes_t) :: Nodes
1850
TYPE(Element_t) :: Element
1851
1852
INTEGER :: n
1853
1854
REAL(KIND=dp) :: Basis(n)
1855
REAL(KIND=dp) :: dBasisdx(n,3), detJ
1856
1857
REAL(KIND=dp) :: U, V, W, S
1858
REAL(KIND=dp) :: Force
1859
REAL(KIND=dp), POINTER :: U_Integ(:), V_Integ(:), W_Integ(:), S_Integ(:)
1860
1861
INTEGER :: i, t, q, p, N_Integ
1862
1863
TYPE(GaussIntegrationPoints_t), TARGET :: IntegStuff
1864
1865
LOGICAL :: stat
1866
!------------------------------------------------------------------------------
1867
BoundaryVector = 0.0_dp
1868
BoundaryMatrix = 0.0_dp
1869
!------------------------------------------------------------------------------
1870
! Integration stuff
1871
!------------------------------------------------------------------------------
1872
IntegStuff = GaussPoints( Element )
1873
U_Integ => IntegStuff % u
1874
V_Integ => IntegStuff % v
1875
W_Integ => IntegStuff % w
1876
S_Integ => IntegStuff % s
1877
N_Integ = IntegStuff % n
1878
1879
!------------------------------------------------------------------------------
1880
! Now we start integrating
1881
!------------------------------------------------------------------------------
1882
DO t=1,N_Integ
1883
U = U_Integ(t)
1884
V = V_Integ(t)
1885
W = W_Integ(t)
1886
!------------------------------------------------------------------------------
1887
! Basis function values & derivatives at the integration point
1888
!------------------------------------------------------------------------------
1889
stat = ElementInfo( Element, Nodes, u, v, w, detJ, &
1890
Basis, dBasisdx )
1891
1892
S = detJ * S_Integ(t)
1893
!------------------------------------------------------------------------------
1894
Force = SUM( LoadVector(1:n)*Basis(1:n) )
1895
1896
DO q=1,n
1897
BoundaryVector(q) = BoundaryVector(q) + s * Basis(q) * Force
1898
END DO
1899
END DO
1900
END SUBROUTINE SheetBoundary
1901
1902
!------------------------------------------------------------------------------
1903
SUBROUTINE ChannelCompose( MassMatrix, StiffMatrix, ForceVector, &
1904
NodalH, NodalHydPot, CArea, NodalKc, NodalAlphac, NodalBetac, NodalPhi0, NodalPhim, &
1905
NodalAc, Nodallc, Nodalng, NodalKs, NodalAlphas, NodalBetas, &
1906
NodalAfactor, NodalBfactor, EdgeTangent, Element, n, Nodes )
1907
!------------------------------------------------------------------------------
1908
USE MaterialModels
1909
USE Integration
1910
USE Differentials
1911
1912
IMPLICIT NONE
1913
1914
REAL(KIND=dp), DIMENSION(:) :: ForceVector
1915
REAL(KIND=dp), DIMENSION(:,:) :: MassMatrix, StiffMatrix
1916
REAL(KIND=dp) :: NodalHydPot(:), NodalBetas(:), NodalAlphas(:)
1917
REAL(KIND=dp) :: NodalH(:), CArea, EdgeTangent(3)
1918
REAL(KIND=dp) :: NodalPhi0(:), NodalPhim(:), NodalNg(:), NodalAfactor(:)
1919
REAL(KIND=dp) :: NodalKc(:), NodalAlphac(:), NodalAc(:), Nodallc(:)
1920
REAL(KIND=dp) :: NodalBetac(:), NodalKs(:), NodalBfactor(:)
1921
1922
INTEGER :: n
1923
1924
TYPE(Nodes_t) :: Nodes
1925
TYPE(Element_t), POINTER :: Element
1926
1927
!------------------------------------------------------------------------------
1928
! Local variables
1929
!------------------------------------------------------------------------------
1930
1931
REAL(KIND=dp) :: dBasisdx(n,3), detJ
1932
REAL(KIND=dp) :: Basis(n), dBasisds(n)
1933
1934
REAL(KIND=dp) :: Force
1935
1936
REAL(KIND=dp) :: A, M
1937
REAL(KIND=dp) :: Load
1938
1939
REAL(KIND=dp) :: x, y, z
1940
1941
INTEGER :: i, j, k, c, p, q, t, N_Integ, NBasis
1942
1943
TYPE(GaussIntegrationPoints_t), TARGET :: IntegStuff
1944
REAL(KIND=dp) :: s, u, v, w
1945
1946
REAL(KIND=dp) :: Vfactor, Phi0, PhiG, Afactor, Bfactor, GradPhim, dPw, Ffactor
1947
1948
REAL(KIND=dp) :: GradPhi, Ngrad, nbc, nbs, nas, nac, hsheet, ng, qc, Kc, Ks, lc
1949
REAL(KIND=dp), DIMENSION(:), POINTER :: U_Integ, V_Integ, W_Integ, S_Integ
1950
1951
LOGICAL :: Vms, Found, Transient, stat
1952
TYPE(ValueList_t), POINTER :: BodyForce
1953
1954
!------------------------------------------------------------------------------
1955
1956
Transient = GetString(GetSimulation(),'Simulation type',Found)=='transient'
1957
1958
ForceVector = 0.0_dp
1959
StiffMatrix = 0.0_dp
1960
MassMatrix = 0.0_dp
1961
Load = 0.0_dp
1962
1963
NBasis = n
1964
1965
!------------------------------------------------------------------------------
1966
! Integration stuff
1967
!------------------------------------------------------------------------------
1968
IntegStuff = GaussPoints( element )
1969
U_Integ => IntegStuff % u
1970
V_Integ => IntegStuff % v
1971
W_Integ => IntegStuff % w
1972
S_Integ => IntegStuff % s
1973
N_Integ = IntegStuff % n
1974
1975
!------------------------------------------------------------------------------
1976
! Now we start integrating
1977
!------------------------------------------------------------------------------
1978
DO t=1,N_Integ
1979
1980
u = U_Integ(t)
1981
v = V_Integ(t)
1982
w = W_Integ(t)
1983
1984
!------------------------------------------------------------------------------
1985
! Basis function values & derivatives at the integration point
1986
!------------------------------------------------------------------------------
1987
stat = ElementInfo( Element, Nodes, u, v, w, detJ, &
1988
Basis, dBasisdx )
1989
1990
s = detJ * S_Integ(t)
1991
1992
! derivative along the edge
1993
DO p=1, n
1994
dBasisds(p) = SUM(dBasisdx(p,1:3)*EdgeTangent(1:3))
1995
END DO
1996
!
1997
!------------------------------------------------------------------------------
1998
! Compute the effective conductivity K = k h^alpha |grad Phi|^{beta-2}
1999
! in the sheet ks and in the Channel Kc
2000
! gradPhi is here a scalar
2001
!------------------------------------------------------------------------------
2002
GradPhi = SUM(NodalHydPot(1:n)*dBasisds(1:n))
2003
Ngrad = ABS(GradPhi)
2004
IF (Ngrad < AEPS) Ngrad = AEPS
2005
nas = SUM(NodalAlphas(1:n)*Basis(1:n))
2006
nbs = SUM(NodalBetas(1:n)*Basis(1:n))
2007
nac = SUM(NodalAlphac(1:n)*Basis(1:n))
2008
nbc = SUM(NodalBetac(1:n)*Basis(1:n))
2009
hsheet = SUM(NodalH(1:n)*Basis(1:n))
2010
2011
Ks = SUM( NodalKs(1:n)*Basis(1:n))
2012
Ks = Ks * hsheet**nas
2013
Ks = Ks * Ngrad**(nbs-2.0)
2014
2015
Kc = SUM( NodalKc(1:n)*Basis(1:n))
2016
Kc = Kc * CArea**nac
2017
Kc = Kc * Ngrad**(nbc-2.0)
2018
2019
! Vclose velocity is split into Ac . S . (Phi0 - Phi)^n
2020
PhiG = SUM(NodalHydPot(1:n)*Basis(1:n))
2021
Phi0 = SUM(NodalPhi0(1:n)*Basis(1:n))
2022
2023
ng = SUM(NodalNg(1:n)*Basis(1:n))
2024
Vfactor = CArea*SUM(NodalAc(1:n)*Basis(1:n))
2025
Vfactor = Vfactor*ABS(Phi0-PhiG)**(ng-1.0_dp)
2026
2027
Afactor = SUM(NodalAfactor(1:n)*Basis(1:n))
2028
Bfactor = SUM(NodalBfactor(1:n)*Basis(1:n))
2029
Afactor = Afactor * Bfactor
2030
lc = SUM(Nodallc(1:n)*Basis(1:n))
2031
2032
qc = -Ks * GradPhi
2033
2034
GradPhim = SUM(NodalPhim(1:n)*dBasisds(1:n))
2035
dPw = GradPhi - GradPhim
2036
2037
IF ((CArea>0.0).OR.(qc*dPw>0.0)) THEN
2038
Ffactor = Afactor * lc * qc
2039
ELSE
2040
Ffactor = 0.0_dp
2041
END IF
2042
2043
Bfactor = Bfactor * SIGN((ABS(-Kc*GradPhi)+ABS(lc*qc)),GradPhi)
2044
2045
Force = Ffactor * GradPhim
2046
Force = Force + Vfactor*(Phi0+(ng-1.0_dp)*PhiG)
2047
2048
!------------------------------------------------------------------------------
2049
! Loop over basis functions of both unknowns and weights
2050
!------------------------------------------------------------------------------
2051
DO p=1,NBasis
2052
2053
Load = Force * Basis(p)
2054
ForceVector(p) = ForceVector(p) + s * Load
2055
2056
DO q=1,NBasis
2057
!------------------------------------------------------------------------------
2058
! The diffusive-convective equation without stabilization
2059
!------------------------------------------------------------------------------
2060
A = 0.0_dp
2061
!------------------------------------------------------------------------------
2062
! The diffusion term
2063
!------------------------------------------------------------------------------
2064
A = A + Kc * dBasisds(p) * dBasisds(q)
2065
A = A - Afactor * Kc * dPw * Basis(p) * dBasisds(q)
2066
A = A + Ffactor * Basis(p) * dBasisds(q)
2067
A = A + Vfactor*ng*Basis(p)*Basis(q)
2068
A = A + Bfactor * Basis(p) * dBasisds(q)
2069
2070
StiffMatrix(p,q) = StiffMatrix(p,q) + s * A
2071
END DO
2072
END DO
2073
2074
END DO
2075
!------------------------------------------------------------------------------
2076
!------------------------------------------------------------------------------
2077
END SUBROUTINE ChannelCompose
2078
!------------------------------------------------------------------------------
2079
2080
!------------------------------------------------------------------------------
2081
SUBROUTINE GetEvolveChannel(ALPHA, BETA, Qcc, CArea, NodalHydPot, NodalH, &
2082
NodalAlphac, NodalBetac, NodalKc, NodalPhi0, NodalPhim, NodalAc, Nodallc, Nodalng, &
2083
NodalKs, NodalAlphas, NodalBetas, NodalAfactor, NodalBfactor, &
2084
Tangent, Element, n, Nodes, LimitEffPres)
2085
!------------------------------------------------------------------------------
2086
USE MaterialModels
2087
USE Integration
2088
USE Differentials
2089
2090
IMPLICIT NONE
2091
2092
2093
REAL(KIND=dp) :: ALPHA, BETA, Qcc
2094
REAL(KIND=dp) :: NodalHydPot(:), NodalAlphas(:), NodalBetas(:)
2095
REAL(KIND=dp) :: NodalH(:), CArea, Tangent(3)
2096
REAL(KIND=dp) :: NodalPhi0(:), NodalPhim(:), NodalNg(:), NodalAfactor(:)
2097
REAL(KIND=dp) :: NodalKc(:), Nodalalphac(:), NodalAc(:), Nodallc(:)
2098
REAL(KIND=dp) :: NodalBetac(:), NodalKs(:), NodalBfactor(:)
2099
2100
INTEGER :: n
2101
2102
TYPE(Nodes_t) :: Nodes
2103
TYPE(Element_t), POINTER :: Element
2104
2105
LOGICAL :: LimitEffPres
2106
2107
!------------------------------------------------------------------------------
2108
! Local variables
2109
!------------------------------------------------------------------------------
2110
2111
REAL(KIND=dp) :: dBasisdx(n,3), detJ
2112
REAL(KIND=dp) :: Basis(n), dBasisds(n)
2113
2114
2115
REAL(KIND=dp) :: A, M
2116
REAL(KIND=dp) :: Load
2117
2118
REAL(KIND=dp) :: x, y, z
2119
2120
INTEGER :: i, j, k, c, p, q, t, N_Integ,NBasis
2121
2122
TYPE(GaussIntegrationPoints_t), TARGET :: IntegStuff
2123
REAL(KIND=dp) :: s, u, v, w
2124
2125
REAL(KIND=dp) :: Phi0, PhiG, EffPressatIP, Afactor, Bfactor, GradPhim, dPw, Ffactor
2126
2127
REAL(KIND=dp) :: GradPhi, Ngrad, nbc, hsheet, nas, nbs, nac, ng, qc, Kc, Ks, lc
2128
2129
REAL(KIND=dp), DIMENSION(:), POINTER :: U_Integ, V_Integ, W_Integ, S_Integ
2130
2131
REAL(KIND=dp) :: Xi, Pii, Nef, Vc
2132
2133
LOGICAL :: Vms, Found, Transient, stat
2134
2135
!------------------------------------------------------------------------------
2136
2137
Transient = GetString(GetSimulation(),'Simulation type',Found)=='transient'
2138
2139
NBasis = n
2140
2141
!------------------------------------------------------------------------------
2142
! Integration stuff
2143
!------------------------------------------------------------------------------
2144
IntegStuff = GaussPoints( element )
2145
U_Integ => IntegStuff % u
2146
V_Integ => IntegStuff % v
2147
W_Integ => IntegStuff % w
2148
S_Integ => IntegStuff % s
2149
N_Integ = IntegStuff % n
2150
2151
! Compute the force at the middle of the Edge element (u=0)
2152
u = 0.0_dp
2153
v = 0.0_dp
2154
w = 0.0_dp
2155
2156
!------------------------------------------------------------------------------
2157
! Basis function values & derivatives at the integration point
2158
!------------------------------------------------------------------------------
2159
stat = ElementInfo( Element, Nodes, u, v, w, detJ, &
2160
Basis, dBasisdx )
2161
2162
2163
! derivative along the edge
2164
DO p=1, n
2165
dBasisds(p) = SUM(dBasisdx(p,1:3)*EdgeTangent(1:3))
2166
END DO
2167
2168
!------------------------------------------------------------------------------
2169
! Compute the effective conductivity K = k h |grad Phi|^{beta-2}
2170
! in the sheet ks and in the Channel Kc
2171
! gradPhi is here a scalar
2172
!------------------------------------------------------------------------------
2173
!
2174
gradPhi = SUM(NodalHydPot(1:n)*dBasisds(1:n))
2175
Ngrad = ABS(GradPhi)
2176
IF (Ngrad < AEPS) Ngrad = AEPS
2177
2178
nas = SUM(NodalAlphas(1:n)*Basis(1:n))
2179
nbs = SUM(NodalBetas(1:n)*Basis(1:n))
2180
nbc = SUM(NodalBetac(1:n)*Basis(1:n))
2181
nac = SUM(NodalAlphac(1:n)*Basis(1:n))
2182
hsheet = SUM(NodalH(1:n)*Basis(1:n))
2183
2184
Ks = SUM( NodalKs(1:n) * Basis(1:n))
2185
Ks = Ks * hsheet**nas
2186
Ks = Ks * Ngrad**(nbs-2.0_dp)
2187
2188
Kc = SUM( NodalKc(1:n) * Basis(1:n))
2189
Kc = Kc * MAX(CArea,0.0)**(nac-1.0_dp)
2190
Kc = Kc * Ngrad**(nbc-2.0_dp)
2191
2192
PhiG = SUM(NodalHydPot(1:n)*Basis(1:n))
2193
Phi0 = SUM(NodalPhi0(1:n)*Basis(1:n))
2194
2195
ng = SUM(NodalNg(1:n)*Basis(1:n))
2196
Vc = SUM(NodalAc(1:n)*Basis(1:n))
2197
2198
IF (LimitEffPres) THEN
2199
EffPressatIP = MAX(Phi0-PhiG, 0.0_dp)
2200
ELSE
2201
EffPressatIP = Phi0-PhiG
2202
END IF
2203
2204
Vc = Vc*ABS(EffPressatIP)**(ng-1.0_dp)
2205
Vc = Vc*(EffPressatIP)
2206
2207
Afactor = SUM(NodalAfactor(1:n)*Basis(1:n))
2208
Bfactor = SUM(NodalBfactor(1:n)*Basis(1:n))
2209
lc = SUM(Nodallc(1:n)*Basis(1:n))
2210
2211
qc = -Ks * GradPhi
2212
2213
GradPhim = SUM(NodalPhim(1:n)*dBasisds(1:n))
2214
dPw = GradPhi - GradPhim
2215
2216
IF ((CArea>0.0).OR.(qc*dPw>0.0)) THEN
2217
Ffactor = lc * qc
2218
ELSE
2219
Ffactor = 0.0_dp
2220
END IF
2221
2222
2223
! Terms in ALPHA
2224
Xi = ABS(-Kc*GradPhi*GradPhi)
2225
Pii = -Afactor*(-Kc*GradPhi)*dPw
2226
ALPHA = Bfactor*(Xi - Pii) - Vc
2227
2228
! Terms in BETA
2229
Xi = ABS(lc*qc*GradPhi)
2230
Pii = -Afactor*(Ffactor)*dPw
2231
BETA = Bfactor*(Xi - Pii)
2232
2233
! Channel flux for output
2234
Qcc = ABS(MAX(CArea,0.0)*Kc*GradPhi)
2235
2236
!------------------------------------------------------------------------------
2237
END SUBROUTINE GetEvolveChannel
2238
!------------------------------------------------------------------------------
2239
2240
!------------------------------------------------------------------------------
2241
SUBROUTINE GetParametersSheet( Element, Material, N, SheetConductivity, alphas, &
2242
betas, Ev, ub, Snn, lr, hr, Ar, ng )
2243
!------------------------------------------------------------------------------
2244
USE MaterialModels
2245
USE Integration
2246
USE Differentials
2247
2248
IMPLICIT NONE
2249
REAL(KIND=dp) :: SheetConductivity(:), alphas(:), betas(:), Ev(:), ub(:), &
2250
Snn(:), lr(:), hr(:), Ar(:), ng(:)
2251
INTEGER :: N
2252
LOGICAL :: Found = .FALSE.
2253
TYPE(Element_t), POINTER :: Element
2254
TYPE(ValueList_t), POINTER :: Material
2255
2256
!------------------------------------------------------------------------------
2257
SheetConductivity = 0.0_dp
2258
SheetConductivity = ListGetReal(Material, 'Sheet Conductivity', n, Element % NodeIndexes, &
2259
Found, UnfoundFatal = .TRUE. )
2260
2261
alphas = 0.0_dp
2262
alphas(1:N) = ListGetReal( Material, 'Sheet Flow Exponent alpha', n, Element % NodeIndexes, &
2263
Found, UnfoundFatal = .TRUE. )
2264
2265
betas = 0.0_dp
2266
betas(1:N) = ListGetReal( Material, 'Sheet Flow Exponent beta', n, Element % NodeIndexes, &
2267
Found, UnfoundFatal = .TRUE. )
2268
2269
Ev = 0.0_dp
2270
Ev(1:N) = ListGetReal( Material, 'Englacial Void Ratio', n, Element % NodeIndexes, &
2271
Found, UnfoundFatal = .TRUE. )
2272
2273
ub = 0.0_dp
2274
ub(1:N) = ListGetReal( Material, 'Sliding Velocity', n, Element % NodeIndexes, &
2275
Found, UnfoundFatal = .TRUE. )
2276
2277
Snn = 0.0_dp
2278
Snn(1:N) = ListGetReal( Material, 'Ice Normal Stress', N, Element % NodeIndexes, &
2279
Found, UnfoundFatal = .TRUE. )
2280
IF (ANY(Snn(1:N) < 0.0)) THEN
2281
WRITE(Message,'(A)')'The Ice Normal Stress (overburden pressure) must be positive'
2282
CALL FATAL(SolverName, Message)
2283
END IF
2284
2285
lr = 0.0_dp
2286
lr(1:N) = ListGetReal( Material, 'Bedrock Bump Length', N, Element % NodeIndexes, &
2287
Found, UnfoundFatal = .TRUE. )
2288
2289
hr = 0.0_dp
2290
hr(1:N) = ListGetReal( Material, 'Bedrock Bump High', N, Element % NodeIndexes, &
2291
Found, UnfoundFatal = .TRUE. )
2292
2293
Ar = 0.0_dp
2294
Ar(1:N) = ListGetReal( Material, 'Sheet Closure Coefficient', N, Element % NodeIndexes, &
2295
Found, UnfoundFatal = .TRUE. )
2296
2297
ng = 0.0_dp
2298
ng(1:N) = ListGetReal( Material, 'Glen Exponent', N, Element % NodeIndexes, &
2299
Found, UnfoundFatal = .TRUE. )
2300
!------------------------------------------------------------------------------
2301
END SUBROUTINE GetParametersSheet
2302
!------------------------------------------------------------------------------
2303
2304
!------------------------------------------------------------------------------
2305
SUBROUTINE GetParametersChannel( Edge, Material, N, SheetConductivity, &
2306
ChannelConductivity, alphac, betac, alphas, betas, IceDensity, &
2307
Snn, Ac, ng, CCt, CCw, lc )
2308
!------------------------------------------------------------------------------
2309
USE MaterialModels
2310
USE Integration
2311
USE Differentials
2312
2313
IMPLICIT NONE
2314
REAL(KIND=dp) :: SheetConductivity(:), ChannelConductivity(:), alphac(:), &
2315
betac(:), alphas(:), betas(:), IceDensity(:), &
2316
Snn(:), Ac(:), ng(:), CCt(:), CCw(:), lc(:)
2317
INTEGER :: N
2318
LOGICAL :: Found = .FALSE.
2319
2320
TYPE(Element_t), POINTER :: Edge
2321
TYPE(ValueList_t), POINTER :: Material
2322
2323
!------------------------------------------------------------------------------
2324
2325
SheetConductivity = 0.0_dp
2326
SheetConductivity(1:n) = ListGetReal(Material, 'Sheet Conductivity', n, Edge % NodeIndexes, &
2327
Found, UnfoundFatal = .TRUE. )
2328
2329
ChannelConductivity = 0.0_dp
2330
ChannelConductivity(1:n) = ListGetReal(Material, 'Channel Conductivity', n, Edge % NodeIndexes, &
2331
Found, UnfoundFatal = .TRUE. )
2332
2333
alphac = 0.0_dp
2334
alphac(1:n) = ListGetReal( Material, 'Channel Flow Exponent Alpha', n, Edge % NodeIndexes, &
2335
Found, UnfoundFatal = .TRUE. )
2336
2337
betac = 0.0_dp
2338
betac(1:n) = ListGetReal( Material, 'Channel Flow Exponent Beta', n, Edge % NodeIndexes, &
2339
Found, UnfoundFatal = .TRUE. )
2340
2341
alphas = 0.0_dp
2342
alphas(1:n) = ListGetReal( Material, 'Sheet Flow Exponent alpha', n, Edge % NodeIndexes, &
2343
Found, UnfoundFatal = .TRUE. )
2344
2345
betas = 0.0_dp
2346
betas(1:n) = ListGetReal( Material, 'Sheet Flow Exponent beta', n, Edge % NodeIndexes, &
2347
Found, UnfoundFatal = .TRUE. )
2348
2349
IceDensity = 0.0_dp
2350
IceDensity(1:n) = ListGetReal( Material, 'Density', N, Edge % NodeIndexes, &
2351
Found, UnfoundFatal = .TRUE. )
2352
2353
Snn = 0.0_dp
2354
Snn(1:n) = ListGetReal( Material, 'Ice Normal Stress', N, Edge % NodeIndexes, &
2355
Found, UnfoundFatal = .TRUE. )
2356
IF (ANY(Snn(1:n) < 0.0)) THEN
2357
WRITE(Message,'(A)')'The Ice Normal Stress (overburden pressure) must be positive'
2358
CALL FATAL(SolverName, Message)
2359
END IF
2360
2361
Ac = 0.0_dp
2362
Ac(1:n) = ListGetReal( Material, 'Channel Closure Coefficient', N, Edge % NodeIndexes, &
2363
Found, UnfoundFatal = .TRUE. )
2364
2365
ng = 0.0_dp
2366
ng(1:n) = ListGetReal( Material, 'Glen Exponent', N, Edge % NodeIndexes, &
2367
Found, UnfoundFatal = .TRUE. )
2368
2369
CCt = 0.0_dp
2370
CCt(1:n) = ListGetReal( Material, 'Pressure Melting Coefficient', N, Edge % NodeIndexes, &
2371
Found, UnfoundFatal = .TRUE. )
2372
2373
CCw = 0.0_dp
2374
CCw(1:n) = ListGetReal( Material, 'Water Heat Capacity', N, Edge % NodeIndexes, &
2375
Found, UnfoundFatal = .TRUE. )
2376
2377
lc = 0.0_dp
2378
lc(1:n) = ListGetReal( Material, 'Sheet Width Over Channel', N, Edge % NodeIndexes, &
2379
Found, UnfoundFatal = .TRUE. )
2380
!------------------------------------------------------------------------------
2381
END SUBROUTINE GetParametersChannel
2382
!------------------------------------------------------------------------------
2383
2384
!------------------------------------------------------------------------------
2385
SUBROUTINE SheetDischargeCompute( &
2386
NodalHydPot, hsheet, ks, na, nb, &
2387
Discharge, Element, n, Nodes, NodeNumber )
2388
!------------------------------------------------------------------------------
2389
USE MaterialModels
2390
USE Integration
2391
USE Differentials
2392
2393
IMPLICIT NONE
2394
REAL(KIND=dp) :: NodalHydPot(:), Discharge(:)
2395
REAL(KIND=dp) :: na, nb, ks, hsheet
2396
INTEGER :: n, NodeNumber
2397
TYPE(Nodes_t) :: Nodes
2398
TYPE(Element_t), POINTER :: Element
2399
2400
!------------------------------------------------------------------------------
2401
! Local variables
2402
!------------------------------------------------------------------------------
2403
2404
REAL(KIND=dp) :: dBasisdx(n,3), detJ
2405
REAL(KIND=dp) :: Basis(n)
2406
2407
INTEGER :: i, dim
2408
2409
REAL(KIND=dp) :: u, v, w
2410
REAL(KIND=dp) :: gradPhi(3), Ngrad
2411
LOGICAL :: stat
2412
2413
!------------------------------------------------------------------------------
2414
! the dimension for this solver is given by the dim of the elements
2415
! should work for 2D and 3D general problem
2416
dim = Element % TYPE % DIMENSION
2417
2418
u = Element % Type % NodeU(NodeNumber)
2419
v = Element % Type % NodeV(NodeNumber)
2420
w = Element % Type % NodeW(NodeNumber)
2421
2422
stat = ElementInfo( Element, Nodes, u, v, w, detJ, Basis, dBasisdx )
2423
2424
!------------------------------------------------------------------------------
2425
! Compute Sheet Discharge = k h^alphas |grad Phi|^{beta-2} grad Phi
2426
!------------------------------------------------------------------------------
2427
gradPhi = 0.0_dp
2428
DO i=1, dim
2429
gradPhi(i) = SUM(NodalHydPot(1:n)*dBasisdx(1:n,i))
2430
END DO
2431
Ngrad = SQRT(SUM(gradPhi(1:dim)*gradPhi(1:dim)))
2432
IF (Ngrad < AEPS) Ngrad = AEPS
2433
2434
DO i=1,dim
2435
Discharge(i) = -ks * (hsheet**na) * (Ngrad**(nb-2.0_dp)) * gradPhi(i)
2436
END DO
2437
2438
!------------------------------------------------------------------------------
2439
END SUBROUTINE SheetDischargeCompute
2440
!------------------------------------------------------------------------------
2441
!------------------------------------------------------------------------------
2442
END SUBROUTINE GlaDSCoupledsolver
2443
!------------------------------------------------------------------------------
2444
2445
! *****************************************************************************/
2446
!> Dummy solver just to declare the Sheet Thickness variable
2447
RECURSIVE SUBROUTINE GlaDSsheetThickDummy( Model,Solver,Timestep,TransientSimulation )
2448
!******************************************************************************
2449
!******************************************************************************
2450
USE Differentials
2451
USE MaterialModels
2452
USE DefUtils
2453
2454
!------------------------------------------------------------------------------
2455
IMPLICIT NONE
2456
!------------------------------------------------------------------------------
2457
!------------------------------------------------------------------------------
2458
! External variables
2459
!------------------------------------------------------------------------------
2460
TYPE(Model_t) :: Model
2461
TYPE(Solver_t), TARGET :: Solver
2462
LOGICAL :: TransientSimulation
2463
REAL(KIND=dp) :: Timestep
2464
2465
RETURN
2466
END SUBROUTINE GlaDSsheetThickDummy
2467
!------------------------------------------------------------------------------
2468
2469