Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Utils/SSAMaterialModels.F90
3203 views
1
!/*****************************************************************************/
2
! *
3
! * Elmer, A Finite Element Software for Multiphysical Problems
4
! *
5
! * Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland
6
! *
7
! * This library is free software; you can redistribute it and/or
8
! * modify it under the terms of the GNU Lesser General Public
9
! * License as published by the Free Software Foundation; either
10
! * version 2.1 of the License, or (at your option) any later version.
11
! *
12
! * This library is distributed in the hope that it will be useful,
13
! * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
! * Lesser General Public License for more details.
16
! *
17
! * You should have received a copy of the GNU Lesser General Public
18
! * License along with this library (in file ../LGPL-2.1); if not, write
19
! * to the Free Software Foundation, Inc., 51 Franklin Street,
20
! * Fifth Floor, Boston, MA 02110-1301 USA
21
! *
22
! *****************************************************************************/
23
!
24
!/******************************************************************************
25
! *
26
! * Authors: fabien Gillet-Chaulet, Rupert Gladstone
27
! * Email: [email protected]
28
! * [email protected]
29
! * Web: http://elmerice.elmerfem.org
30
! *
31
! * Original Date: May 2022
32
! *
33
! ******************************************************************************/
34
!--------------------------------------------------------------------------------
35
!> Module containing utility routines for the SSA
36
!--------------------------------------------------------------------------------
37
MODULE SSAMaterialModels
38
39
USE DefUtils
40
41
IMPLICIT NONE
42
43
CONTAINS
44
45
!--------------------------------------------------------------------------------
46
!> Return the effective friction coefficient
47
!--------------------------------------------------------------------------------
48
FUNCTION SSAEffectiveFriction(Element,n,Basis,ub,SEP,PartlyGrounded,h,rho,rhow,sealevel,SlipDer) RESULT(Slip)
49
IMPLICIT NONE
50
REAL(KIND=dp) :: Slip ! the effective friction coefficient
51
TYPE(Element_t), POINTER :: Element ! the current element
52
INTEGER :: n ! number of nodes
53
REAL(KIND=dp) :: Basis(:) ! basis functions
54
REAL(KIND=dp) :: ub ! the velocity for non-linear friction laws
55
LOGICAL :: SEP ! Sub-Element Parametrisation of the friction
56
LOGICAL :: PartlyGrounded ! is the GL within the current element?
57
REAL(KIND=dp) :: h ! for SEP: the ice thickness at current location
58
REAL(KIND=dp) :: rho,rhow,sealevel ! density, sea-water density, sea-level
59
REAL(KIND=dp),OPTIONAL :: SlipDer ! dSlip/du=dSlip/dv if ub=(u^2+v^2)^1/2 ! required to compute the Jacobian
60
61
62
63
INTEGER :: iFriction
64
INTEGER, PARAMETER :: LINEAR = 1
65
INTEGER, PARAMETER :: WEERTMAN = 2
66
INTEGER, PARAMETER :: BUDD = 5
67
INTEGER, PARAMETER :: REG_COULOMB_GAG = 3 ! Schoof 2005 & Gagliardini 2007
68
INTEGER, PARAMETER :: REG_COULOMB_JOU = 4 ! Joughin 2019
69
70
TYPE(ValueList_t), POINTER :: Material, Constants, pMaterial
71
TYPE(Variable_t), POINTER :: GMSol,BedrockSol,NSol
72
INTEGER, POINTER :: NodeIndexes(:)
73
CHARACTER(LEN=MAX_NAME_LEN) :: Friction
74
REAL(KIND=dp) :: Slip2, gravity, qq, hafq
75
REAL(KIND=dp) :: fm,fq,MinN,U0
76
REAL(KIND=dp) :: alpha,beta,fB
77
INTEGER :: GLnIP
78
79
REAL(KIND=dp),DIMENSION(n) :: NodalBeta, NodalGM, NodalBed, NodalLinVelo,NodalC,NodalN
80
REAL(KIND=dp) :: bedrock,Hf,fC,fN,LinVelo
81
LOGICAL :: Found
82
TYPE(Solver_t), POINTER :: pSolver => NULL()
83
84
SAVE :: GLnIP, GMSol, BedRockSol, pSolver
85
86
! Sub - element GL parameterisation
87
IF (SEP) THEN
88
! If we have adaptive rule then GLnIP keyword is not given.
89
IF(.NOT. ASSOCIATED(pSolver, CurrentModel % Solver ) ) THEN
90
pSolver => CurrentModel % Solver
91
GLnIP=ListGetInteger( pSolver % Values, &
92
'GL integration points number',Found)
93
IF(GLnIP > 0) THEN
94
GMSol => VariableGet( CurrentModel % Variables, 'GroundedMask',UnFoundFatal=.TRUE. )
95
END IF
96
BedrockSol => VariableGet( CurrentModel % Variables, 'bedrock',UnFoundFatal=.TRUE. )
97
END IF
98
IF(GLnIP > 0) THEN
99
CALL GetLocalSolution( NodalGM,UElement=Element,UVariable=GMSol)
100
END IF
101
CALL GetLocalSolution( NodalBed,UElement=Element,UVariable= BedrockSol)
102
END IF
103
104
! Friction law
105
Material => GetMaterial(Element)
106
NodeIndexes => Element % NodeIndexes
107
108
Friction = ListGetString(Material, 'SSA Friction Law',Found, UnFoundFatal=.TRUE.)
109
SELECT CASE(Friction)
110
CASE('linear')
111
iFriction = LINEAR
112
fm = 1.0_dp
113
CASE('weertman')
114
iFriction = WEERTMAN
115
CASE('budd')
116
iFriction = BUDD
117
CASE('coulomb')
118
iFriction = REG_COULOMB_GAG
119
CASE('regularized coulomb')
120
iFriction = REG_COULOMB_JOU
121
CASE DEFAULT
122
CALL FATAL("SSAEffectiveFriction",'Friction choice not recognised')
123
END SELECT
124
125
! coefficient for all friction parameterisations
126
NodalBeta(1:n) = ListGetReal( &
127
Material, 'SSA Friction Parameter', n, NodeIndexes(1:n), Found,&
128
UnFoundFatal=.TRUE.)
129
130
! for nonlinear powers of sliding velocity
131
SELECT CASE (iFriction)
132
CASE(REG_COULOMB_JOU,REG_COULOMB_GAG,WEERTMAN,BUDD)
133
fm = ListGetConstReal( Material, 'SSA Friction Exponent', Found , UnFoundFatal=.TRUE.)
134
NodalLinVelo(1:n) = ListGetReal( &
135
Material, 'SSA Friction Linear Velocity', n, NodeIndexes(1:n), Found,&
136
UnFoundFatal=.TRUE.)
137
CASE DEFAULT
138
END SELECT
139
140
! where explicit dependence on effective pressure is present...
141
SELECT CASE (iFriction)
142
CASE(REG_COULOMB_GAG,BUDD)
143
NSol => VariableGet( CurrentModel % Variables, 'Effective Pressure', UnFoundFatal=.TRUE. )
144
CALL GetLocalSolution( NodalN,UElement=Element, UVariable=NSol)
145
MinN = ListGetConstReal( Material, 'SSA Min Effective Pressure', Found, UnFoundFatal=.TRUE.)
146
fN = SUM( NodalN(1:n) * Basis(1:n) )
147
! Effective pressure should be >0 (for the friction law)
148
fN = MAX(fN, MinN)
149
END SELECT
150
151
! parameters unique to one sliding parameterisation
152
SELECT CASE (iFriction)
153
154
CASE(BUDD)
155
Constants => GetConstants()
156
gravity = ListGetConstReal( Constants, 'Gravity Norm', UnFoundFatal=.TRUE. )
157
! calculate haf from N = rho_i g z*
158
qq = ListGetConstReal( Material, 'SSA Haf Exponent', Found, UnFoundFatal=.TRUE.)
159
hafq = ( fN / (gravity * rho) ) ** qq
160
161
CASE(REG_COULOMB_GAG)
162
fq = ListGetConstReal( Material, 'SSA Friction Post-Peak', Found, UnFoundFatal=.TRUE. )
163
NodalC = 0.0_dp
164
NodalC(1:n) = ListGetReal( &
165
Material, 'SSA Friction Maximum Value', n, NodeIndexes(1:n), Found,&
166
UnFoundFatal=.TRUE.)
167
fC = SUM( NodalC(1:n) * Basis(1:n) )
168
169
CASE(REG_COULOMB_JOU)
170
U0 = ListGetConstReal( Material, 'SSA Friction Threshold Velocity', Found, UnFoundFatal=.TRUE.)
171
172
END SELECT
173
174
Beta=SUM(Basis(1:n)*NodalBeta(1:n))
175
176
IF (SEP) THEN
177
! Floating
178
IF (PartlyGrounded .OR. GLnIP==0) THEN
179
bedrock = SUM( NodalBed(1:n) * Basis(1:n) )
180
Hf = rhow * (sealevel-bedrock) / rho
181
if (h < Hf) beta = 0._dp
182
ELSE IF (ALL(NodalGM(1:n) < 0._dp)) THEN
183
beta = 0._dp
184
END IF
185
END IF
186
187
Slip2=0.0_dp
188
IF (iFriction .NE. LINEAR) THEN
189
LinVelo = SUM( NodalLinVelo(1:n) * Basis(1:n) )
190
IF ((iFriction == WEERTMAN).AND.(fm==1.0_dp)) iFriction=LINEAR
191
Slip2=1.0_dp
192
IF (ub < LinVelo) then
193
ub = LinVelo
194
Slip2=0.0_dp
195
ENDIF
196
END IF
197
198
SELECT CASE (iFriction)
199
200
CASE(LINEAR)
201
Slip = beta
202
IF (PRESENT(SlipDer)) SlipDer = 0._dp
203
204
CASE(WEERTMAN)
205
Slip = beta * ub**(fm-1.0_dp)
206
IF (PRESENT(SlipDer)) SlipDer = Slip2*Slip*(fm-1.0_dp)/(ub*ub)
207
208
CASE(BUDD)
209
Slip = beta * hafq * ub**(fm-1.0_dp)
210
! TODO:
211
! IF (PRESENT(SlipDer)) SlipDer =
212
213
CASE(REG_COULOMB_GAG)
214
IF (fq.NE.1.0_dp) THEN
215
alpha = (fq-1.0_dp)**(fq-1.0_dp) / fq**fq
216
ELSE
217
alpha = 1.0_dp
218
END IF
219
fB = alpha * (beta / (fC*fN))**(fq/fm)
220
Slip = beta * ub**(fm-1.0_dp) / (1.0_dp + fB * ub**fq)**fm
221
IF (PRESENT(SlipDer)) SlipDer = Slip2 * Slip * ((fm-1.0_dp) / (ub*ub) - &
222
fm*fq*fB*ub**(fq-2.0_dp)/(1.0_dp+fB*ub**fq))
223
224
CASE(REG_COULOMB_JOU)
225
Slip = beta * ub**(fm-1.0_dp) / (ub + U0)**fm
226
IF (PRESENT(SlipDer)) SlipDer = Slip2 * Slip * ((fm-1.0_dp) / (ub*ub) - &
227
fm*ub**(-1.0_dp)/(ub+U0))
228
229
END SELECT
230
231
END FUNCTION SSAEffectiveFriction
232
233
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
234
! Compute the element averaged friction
235
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
236
FUNCTION ComputeMeanFriction(Element,n,ElementNodes,STDOFs,NodalU,NodalV,NodalZs,NodalZb,MinH, &
237
NodalDensity,SEP,GLnIP,sealevel,rhow) RESULT(strbasemag)
238
REAL(KIND=dp) :: strbasemag
239
TYPE(Element_t), POINTER :: Element
240
INTEGER :: n
241
TYPE(Nodes_t) :: ElementNodes
242
INTEGER :: STDOFs
243
REAL(KIND=dp) :: NodalU(n),NodalV(n),NodalZs(n),NodalZb(n),NodalDensity(n)
244
REAL(KIND=dp) :: MinH
245
LOGICAL :: SEP
246
INTEGER :: GLnIP
247
REAL(KIND=dp) :: sealevel,rhow
248
249
LOGICAL :: PartlyGroundedElement
250
TYPE(Variable_t),POINTER :: GMSol
251
REAL(KIND=dp) :: NodalGM(n)
252
TYPE(GaussIntegrationPoints_t) :: IP
253
REAL(KIND=dp) :: Basis(n), detJ
254
REAL(KIND=dp) :: h,ub,rho,Velo(2)
255
REAL(KIND=dp) :: area,tb
256
REAL(KIND=dp) :: Ceff
257
LOGICAL :: stat
258
INTEGER :: t
259
260
strbasemag=0._dp
261
IF (SEP) THEN
262
GMSol => VariableGet( CurrentModel % Variables, 'GroundedMask',UnFoundFatal=.TRUE. )
263
CALL GetLocalSolution( NodalGM,UElement=Element,UVariable=GMSol)
264
PartlyGroundedElement=(ANY(NodalGM(1:n).GE.0._dp).AND.ANY(NodalGM(1:n) < 0._dp))
265
IF (PartlyGroundedElement .AND. GLnIP > 0 ) THEN
266
IP = GaussPoints( Element , np=GLnIP )
267
ELSE
268
IP = GaussPoints( Element )
269
ENDIF
270
ELSE
271
IP = GaussPoints( Element )
272
ENDIF
273
274
area=0._dp
275
tb=0._dp
276
DO t=1,IP % n
277
stat = ElementInfo( Element, ElementNodes, IP % U(t), IP % V(t), &
278
IP % W(t), detJ, Basis )
279
280
h = SUM( (NodalZs(1:n)-NodalZb(1:n)) * Basis(1:n) )
281
h=max(h,MinH)
282
283
rho = SUM( NodalDensity(1:n) * Basis(1:n) )
284
285
Velo = 0.0_dp
286
Velo(1) = SUM(NodalU(1:n) * Basis(1:n))
287
IF (STDOFs == 2) Velo(2) = SUM(NodalV(1:n) * Basis(1:n))
288
ub = SQRT(Velo(1)*Velo(1)+Velo(2)*Velo(2))
289
290
Ceff=SSAEffectiveFriction(Element,n,Basis,ub,SEP,PartlyGroundedElement,h,rho,rhow,sealevel)
291
292
area=area+detJ*IP % s(t)
293
tb=tb+Ceff*ub*detJ*IP % s(t)
294
END DO
295
296
strbasemag=tb/area
297
298
END FUNCTION ComputeMeanFriction
299
300
!--------------------------------------------------------------------------------
301
!> Return the effective basal mass balance (to be called separately for each IP in
302
!> a partly grounded element)
303
!--------------------------------------------------------------------------------
304
FUNCTION SSAEffectiveBMB(Element,nn,Basis,SEM,BMB,hh,FIPcount,rho,rhow,sealevel,FAF) RESULT(BMBatIP)
305
306
IMPLICIT NONE
307
308
REAL(KIND=dp) :: BMBatIP ! the effective basal melt rate at integration point
309
310
INTEGER,INTENT(IN) :: nn ! element number of nodes
311
REAL(KIND=dp), INTENT(IN) :: BMB(:) ! basal mass balance
312
LOGICAL, INTENT(IN) :: SEM ! Sub-Element Parametrisation (requires interpolation of floatation on IPs)
313
REAL(KIND=dp),INTENT(IN) :: hh ! the ice thickness at current location
314
REAL(KIND=dp),INTENT(IN) :: Basis(:)
315
TYPE(Element_t),POINTER,INTENT(IN) :: Element
316
317
! optional arguments, depending on melt param
318
INTEGER,INTENT(INOUT),OPTIONAL :: FIPcount
319
REAL(KIND=dp),INTENT(IN),OPTIONAL :: rho,rhow,sealevel ! to calculate floatation for SEM3
320
REAL(KIND=dp),INTENT(IN),OPTIONAL :: FAF ! Floating area fraction for SEM1
321
322
TYPE(ValueList_t), POINTER :: Material
323
TYPE(Variable_t), POINTER :: GMSol,BedrockSol
324
CHARACTER(LEN=MAX_NAME_LEN) :: MeltParam
325
326
REAL(KIND=dp),DIMENSION(nn) :: NodalBeta, NodalGM, NodalBed, NodalLinVelo,NodalC
327
REAL(KIND=dp) :: bedrock,Hf
328
329
LOGICAL :: Found
330
331
! Sub - element GL parameterisation
332
IF (SEM) THEN
333
GMSol => VariableGet( CurrentModel % Variables, 'GroundedMask',UnFoundFatal=.TRUE. )
334
CALL GetLocalSolution( NodalGM,UElement=Element,UVariable=GMSol )
335
BedrockSol => VariableGet( CurrentModel % Variables, 'bedrock',UnFoundFatal=.TRUE. )
336
CALL GetLocalSolution( NodalBed,UElement=Element,UVariable= BedrockSol )
337
END IF
338
339
Material => GetMaterial(Element)
340
MeltParam = ListGetString(Material, 'SSA Melt Param',Found, UnFoundFatal=.TRUE.)
341
342
BMBatIP=SUM(Basis(1:nn)*BMB(1:nn))
343
344
SELECT CASE(MeltParam)
345
346
CASE('FMP','fmp')
347
348
CASE('NMP','nmp')
349
BMBatIP = 0.0_dp
350
351
CASE('SEM1','sem1')
352
! check element type is triangular (would need to modify
353
! CalcFloatingAreaFraction to allow other element types)
354
IF (element % type % ElementCode .NE. 303) THEN
355
CALL Fatal('SSAEffectiveBMB','Expecting element type 303!')
356
END IF
357
358
IF (PRESENT(FAF)) THEN
359
BMBatIP = BMBatIP * FAF
360
ELSE
361
CALL Fatal('SSAEffectiveBMB','FAF (floating area fraction) not present!')
362
END IF
363
364
CASE('SEM3','sem3')
365
bedrock = SUM( NodalBed(1:nn) * Basis(1:nn) )
366
Hf= rhow * (sealevel-bedrock) / rho
367
IF (hh > Hf) THEN
368
BMBatIP = 0.0_dp
369
ELSE
370
IF (PRESENT(FIPcount)) FIPcount = FIPcount + 1
371
END IF
372
373
CASE DEFAULT
374
WRITE( Message, * ) 'SSA Melt Param not recognised:', MeltParam
375
CALL FATAL("SSAEffectiveBMB",Message)
376
377
END SELECT
378
379
END FUNCTION SSAEffectiveBMB
380
381
!--------------------------------------------------------------------------------
382
!> Calculate the fractional floating area of a partly grounded element for SEM1.
383
!> For implementing SEP1 use (1-FAF) for grounded area fraction.
384
!> Written for element type 303.
385
!> To be called per element from ThicknessSolver for SEM1.
386
!> See Helene Seroussi TC papers from 2014 and 2018.
387
!> More notes here: https://www.overleaf.com/read/chpfpgzhwvjr
388
!--------------------------------------------------------------------------------
389
FUNCTION CalcFloatingAreaFraction(element,NodalGM,hhVar,sealevel,rho,rhow) RESULT(FAF)
390
391
IMPLICIT NONE
392
393
REAL(KIND=dp) :: FAF ! the area fraction of floating ice
394
395
TYPE(Element_t),POINTER,INTENT(IN) :: Element
396
REAL(KIND=dp),INTENT(IN) :: NodalGM(:)
397
TYPE(Variable_t),POINTER,INTENT(IN) :: hhVar
398
REAL(KIND=dp), INTENT(IN) :: rho,rhow,sealevel ! to calculate floatation
399
400
TYPE(Variable_t),POINTER :: bedVar
401
INTEGER,POINTER :: hhPerm(:),bedPerm(:)
402
REAL(KIND=dp),POINTER :: hh(:),bed(:)
403
404
! The following real vars use Yu's terminology (see overleaf linked above)
405
REAL(KIND=dp) :: ss,tt,A1,A2,x1,x2,x3,x4,x5,y1,y2,y3,y4,y5
406
REAL(KIND=dp) :: B1,B2,B3,Zb1,Zb2,Zb3
407
408
! NI refers to Node Index.
409
! NI2 is the sole node of its category (floating or GL, see Yu's notes);
410
! NI1 and NI3 are both in the other category.
411
! nn is the number of nodes for the current element (3 for triangles, which is assumed here)
412
INTEGER :: NumFLoatingNodes, nn, NI1, NI2, NI3
413
414
bedVar => VariableGet( CurrentModel % Variables, 'bedrock', UnFoundFatal=.TRUE. )
415
bedPerm => bedVar % Perm
416
bed => bedVar % Values
417
418
hhPerm => hhVar % Perm
419
hh => hhVar % Values
420
421
nn = GetElementNOFNodes()
422
NumFLoatingNodes = -SUM(NodalGM(1:nn))
423
424
IF (ANY(NodalGM(1:nn) > 0._dp)) THEN
425
CALL Fatal('CalcFloatingAreaFraction','Fully grounded nodes found!')
426
END IF
427
428
IF (NumFLoatingNodes < 1) THEN
429
CALL Fatal('CalcFloatingAreaFraction','Not enough floating nodes!')
430
431
ELSEIF (NumFLoatingNodes == 1) THEN
432
IF (NodalGM(1) == -1) THEN
433
NI2 = element % NodeIndexes(1)
434
NI1 = element % NodeIndexes(2)
435
NI3 = element % NodeIndexes(3)
436
ELSEIF (NodalGM(2) == -1) THEN
437
NI2 = element % NodeIndexes(2)
438
NI1 = element % NodeIndexes(1)
439
NI3 = element % NodeIndexes(3)
440
ELSEIF (NodalGM(3) == -1) THEN
441
NI2 = element % NodeIndexes(3)
442
NI1 = element % NodeIndexes(1)
443
NI3 = element % NodeIndexes(2)
444
END IF
445
446
ELSEIF (NumFLoatingNodes == 2) THEN
447
IF (NodalGM(1) == 0) THEN
448
NI2 = element % NodeIndexes(1)
449
NI1 = element % NodeIndexes(2)
450
NI3 = element % NodeIndexes(3)
451
ELSEIF (NodalGM(2) == 0) THEN
452
NI2 = element % NodeIndexes(2)
453
NI1 = element % NodeIndexes(1)
454
NI3 = element % NodeIndexes(3)
455
ELSEIF (NodalGM(3) == 0) THEN
456
NI2 = element % NodeIndexes(3)
457
NI1 = element % NodeIndexes(1)
458
NI3 = element % NodeIndexes(2)
459
END IF
460
461
ELSEIF (NumFLoatingNodes > 2) THEN
462
CALL Fatal('CalcFloatingAreaFraction','Too many floating nodes!')
463
464
END IF
465
466
x1 = CurrentModel % Mesh % Nodes % x(NI1)
467
x2 = CurrentModel % Mesh % Nodes % x(NI2)
468
x3 = CurrentModel % Mesh % Nodes % x(NI3)
469
470
y1 = CurrentModel % Mesh % Nodes % y(NI1)
471
y2 = CurrentModel % Mesh % Nodes % y(NI2)
472
y3 = CurrentModel % Mesh % Nodes % y(NI3)
473
474
B1 = bed(bedPerm(NI1))
475
B2 = bed(bedPerm(NI2))
476
B3 = bed(bedPerm(NI3))
477
478
Zb1= sealevel - hh(hhPerm(NI1)) * rho/rhow
479
Zb2= sealevel - hh(hhPerm(NI2)) * rho/rhow
480
Zb3= sealevel - hh(hhPerm(NI3)) * rho/rhow
481
482
ss = (Zb2-B2)/(B3-B2-Zb3+Zb2)
483
tt = (Zb1-B1)/(B2-B1-Zb2+Zb1)
484
485
x4 = x1 + tt*(x2-x1)
486
x5 = x2 + ss*(x3-x2)
487
y4 = y1 + tt*(y2-y1)
488
y5 = y2 + ss*(y3-y2)
489
490
A1 = 0.5_dp * ABS( x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2) )
491
A2 = 0.5_dp * ABS( x4*(y5-y2) + x5*(y2-y4) + x2*(y4-y5) )
492
493
FAF = A2/A1
494
495
IF (NumFLoatingNodes == 2) FAF = 1.0_dp - FAF ! Needed because FAF was grounded fraction
496
497
END FUNCTION CalcFloatingAreaFraction
498
499
END MODULE SSAMaterialModels
500
501
502