Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/IceSheet/Greenland/SSA/Scalar_OUTPUT.F90
3206 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
! * Author: F. Gillet-Chaulet (IGE)
26
! * Email: [email protected]
27
! * Web: http://elmerice.elmerfem.org
28
! *
29
! * Original Date: 03-2018,
30
! *****************************************************************************
31
!!! Compute standard 1D variables:
32
! 1: Time
33
! 2: Volume
34
! 3: Volume Above Floatation
35
! 4: Volume rate of change
36
! 5: SMB Flux
37
! 6: BMB Flux
38
! 7: Residual Flux
39
! 8: Ice Discharge
40
! 9: Ice flux at Grounding Line
41
! 10: Grounded ice area
42
! 11: Floating ice area
43
! 12: Ice Free area
44
! *****************************************************************************
45
SUBROUTINE Scalar_OUTPUT( Model,Solver,dt,TransientSimulation )
46
USE DefUtils
47
IMPLICIT NONE
48
49
TYPE(Model_t) :: Model
50
TYPE(Solver_t):: Solver
51
REAL(KIND=dp) :: dt
52
LOGICAL :: TransientSimulation
53
54
TYPE(Variable_t),POINTER :: GMVAR,FlowVar,HVar,HRVar,BedVar,DHDTVar
55
INTEGER,POINTER :: Permutation(:)
56
57
REAL(KIND=dp) :: Volume,VAF
58
REAL(KIND=dp) :: DHDTFlux,SMBFlux,BMBFlux,HMinFlux
59
REAL(KIND=dp) :: GroundedArea,FloatingArea,FreeArea
60
REAL(KIND=dp) :: CalvingFlux
61
REAL(KIND=dp) :: GLFlux
62
REAL(KIND=dp),SAVE :: zsea,rhow
63
64
REAL (KIND=dp), ALLOCATABLE, DIMENSION(:),SAVE :: NodeArea
65
REAL (KIND=dp), ALLOCATABLE, DIMENSION(:),SAVE :: LocalArea
66
REAL (KIND=dp), ALLOCATABLE, DIMENSION(:),SAVE :: NodalH,NodalDHDT,MinH,NodalGM
67
REAL (KIND=dp), ALLOCATABLE, DIMENSION(:),SAVE :: NodalSMB,NodalBMB,NodalMB
68
REAL (KIND=dp), ALLOCATABLE, DIMENSION(:),SAVE :: NodalHf
69
REAL (KIND=dp), ALLOCATABLE, DIMENSION(:),SAVE :: rhoi
70
REAL (KIND=dp), ALLOCATABLE, DIMENSION(:),SAVE :: Val,ParVal
71
REAL(KIND=dp),ALLOCATABLE,SAVE :: Basis(:), dBasisdx(:,:)
72
73
INTEGER :: i
74
INTEGER :: ierr
75
INTEGER,PARAMETER :: NVal=11
76
INTEGER, PARAMETER :: io=12
77
INTEGER,PARAMETER :: DIM=2 !dimension of the pb restricted to 2 currently
78
79
INTEGER :: FlowDofs
80
81
LOGICAL,SAVE :: Firsttime=.TRUE.
82
83
CHARACTER(LEN=MAX_NAME_LEN) :: SolverName='INITMIP_Scalar_OUTPUT'
84
CHARACTER(LEN=MAX_NAME_LEN),SAVE :: OUTPUT_FName
85
CHARACTER(LEN=MAX_NAME_LEN),ALLOCATABLE,SAVE :: ValueNames(:)
86
87
CALL GET_VARIABLES()
88
89
IF (Firsttime.OR.Solver%Mesh%Changed) THEN
90
91
IF (.NOT.ASSOCIATED(Solver%Variable)) &
92
CALL FATAL(SolverName,'Solver%Variable Not associated')
93
IF (.NOT.ASSOCIATED(Solver%Matrix)) &
94
CALL FATAL(SolverName,'Solver%Matrix Not associated')
95
96
IF ( CurrentCoordinateSystem() /= Cartesian ) &
97
CALL FATAL(SolverName,'Only For cartesian system')
98
99
IF ( Model % Mesh % MeshDim /= DIM ) &
100
CALL FATAL(SolverName,'Only For 2D plan view')
101
102
!## DO SOME ALLOCATION
103
CALL DO_ALLOCATION(Firsttime)
104
105
!## Name of Saved variables
106
ValueNames(1)='Volume'
107
ValueNames(2)='Volume Above Floatation'
108
ValueNames(3)='Volume rate of change'
109
ValueNames(4)='SMB Flux'
110
ValueNames(5)='BMB Flux'
111
ValueNames(6)='Residual Flux'
112
ValueNames(7)='Ice Discharge'
113
ValueNames(8)='Ice flux at Grounding Line'
114
ValueNames(9)='Grounded ice area'
115
ValueNames(10)='Floating ice area'
116
ValueNames(11)='Ice Free area'
117
118
IF (Firsttime) CALL GET_CONSTANTS(zsea,rhow)
119
IF (Firsttime) CALL INIT_OUTPUT_FILE(OUTPUT_FName)
120
IF (Firsttime) CALL COMPUTE_NodeArea(NodeArea)
121
Firsttime=.FALSE.
122
END IF
123
124
125
CALL BODY_INTEGRATION(Volume,VAF,DHDTFlux,SMBFlux,BMBFlux,HMinFlux,&
126
GroundedArea,FloatingArea,FreeArea)
127
128
CALL BC_INTEGRATION(CalvingFlux)
129
130
CALL COMPUTE_GL_FLUX(GLFlux)
131
132
133
Val(1)=Volume
134
Val(2)=VAF
135
136
Val(3)=DHDTFlux
137
Val(4)=SMBFlux
138
Val(5)=BMBFlux
139
Val(6)=HMinFlux
140
141
Val(7)=CalvingFlux
142
Val(8)= GLFlux
143
144
Val(9)=GroundedArea
145
Val(10)=FloatingArea
146
Val(11)=FreeArea
147
148
IF (ParEnv % PEs > 1 ) THEN
149
DO i=1,NVal
150
CALL MPI_ALLREDUCE(Val(i),ParVal(i),1,&
151
MPI_DOUBLE_PRECISION,MPI_SUM,MPI_COMM_WORLD,ierr)
152
END DO
153
Val(1:NVal)=ParVal(1:NVal)
154
END IF
155
156
IF ((ParEnv % PEs > 1 ).AND.(ParEnv % MyPe.NE.0)) RETURN
157
158
IF( Solver % TimesVisited > 0 ) THEN
159
OPEN(io,file=TRIM(OUTPUT_FName),position='append')
160
ELSE
161
OPEN(io,file=TRIM(OUTPUT_FName))
162
END IF
163
164
write(io,'(ES22.12E3)',advance='no') GetTime()
165
Do i=1,NVal-1
166
write(io,'(ES22.12E3)',advance='no') Val(i)
167
End do
168
write(io,'(ES22.12E3)') Val(NVal)
169
CLOSE(io)
170
171
CONTAINS
172
173
SUBROUTINE DO_ALLOCATION(Firsttime)
174
LOGICAL,INTENT(IN) :: Firsttime
175
INTEGER :: M
176
INTEGER :: N
177
IF (.NOT.Firsttime) &
178
DEALLOCATE(NodalH,NodalDHDT,NodalHf,MinH,NodalGM,NodalSMB,NodalBMB,NodalMB,rhoi,&
179
LocalArea, &
180
Basis,dBasisdx,&
181
Val,ParVal,ValueNames,&
182
NodeArea)
183
N=Model % Mesh % NumberOfNodes
184
M=Model % MaxElementNodes
185
ALLOCATE(Basis(M),&
186
dBasisdx(M,3),&
187
NodalH(M),&
188
NodalDHDT(M),&
189
NodalHf(M),&
190
MinH(M),&
191
NodalGM(M),&
192
NodalSMB(M),&
193
NodalBMB(M),&
194
NodalMB(M),&
195
rhoi(M),&
196
LocalArea(M),&
197
Val(NVal),ParVal(NVal),ValueNames(NVal),&
198
NodeArea(N))
199
END SUBROUTINE DO_ALLOCATION
200
201
SUBROUTINE GET_CONSTANTS(zsea,rhow)
202
IMPLICIT NONE
203
REAL(KIND=dp),INTENT(OUT) :: zsea,rhow
204
LOGICAL :: Found
205
206
zsea = GetCReal( Model % Constants, 'Sea Level', Found )
207
IF (.NOT.Found) CALL FATAL(SolverName,'<Sea Level> not found')
208
rhow = GetCReal( Model % Constants, 'water density', Found )
209
IF (.NOT.Found) CALL FATAL(SolverName,'<water density not found')
210
END SUBROUTINE GET_CONSTANTS
211
212
SUBROUTINE INIT_OUTPUT_FILE(OUTPUT_FName)
213
USE GeneralUtils
214
IMPLICIT NONE
215
CHARACTER(LEN=MAX_NAME_LEN),INTENT(OUT) :: OUTPUT_FName
216
217
CHARACTER(LEN=MAX_NAME_LEN) ::NamesFile,&
218
OUTPUT_FName_D='INITMIP_Scalar_OUTPUT.dat'
219
220
CHARACTER(LEN=MAX_NAME_LEN) :: DateStr
221
TYPE(ValueList_t), POINTER :: SolverParams
222
LOGICAL :: Found
223
INTEGER :: i
224
225
SolverParams=>GetSolverParams(Solver)
226
OUTPUT_FName = ListGetString(SolverParams,'File Name',Found)
227
IF (.NOT.Found) OUTPUT_FName=OUTPUT_FName_D
228
229
NamesFile = TRIM(OUTPUT_FName) // '.' // TRIM("names")
230
231
IF ((ParEnv % PEs >1).AND.(ParEnv%MyPe.NE.0)) RETURN
232
233
DateStr = FormatDate()
234
235
OPEN(io,file=TRIM(NamesFile))
236
WRITE(io,'(A)') 'File started at: '//TRIM(DateStr)
237
WRITE(io,'(A)') ' '
238
WRITE(io,'(A)') 'Elmer version: '//TRIM(GetVersion())
239
WRITE(io,'(A)') 'Elmer revision: '//TRIM(GetRevision())
240
WRITE(io,'(A)') 'Elmer Compilation Date: '//TRIM(GetCompilationDate())
241
WRITE(io,'(A)') ' '
242
WRITE(io,'(A)') 'Variables in columns of matrix:'//TRIM(OUTPUT_FName)
243
WRITE(io,'(I4,": ",A)') 1,'Time'
244
DO i=1,NVal
245
WRITE(io,'(I4,": ",A)') i+1,TRIM(ValueNames(i))
246
END DO
247
CLOSE(io)
248
END SUBROUTINE INIT_OUTPUT_FILE
249
250
SUBROUTINE GET_VARIABLES()
251
HVar => VariableGet(Solver%Mesh%Variables,'h',UnfoundFatal=.TRUE.)
252
253
DHDTVar => VariableGet(Solver%Mesh%Variables,'dhdt',UnfoundFatal=.TRUE.)
254
255
HRVar => VariableGet(Solver%Mesh%Variables,'h loads')
256
IF (.NOT.ASSOCIATED(HRVar)) &
257
HRVar => VariableGet(Solver%Mesh%Variables,'h residual',UnfoundFatal=.TRUE.)
258
259
BedVar => VariableGet(Solver%Mesh%Variables,'bedrock',UnfoundFatal=.TRUE.)
260
261
GMVar => VariableGet(Solver%Mesh%Variables,'GroundedMask',UnfoundFatal=.TRUE.)
262
263
FlowVar => VariableGet(Solver%Mesh%Variables,'SSAVelocity',UnfoundFatal=.TRUE.)
264
FlowDofs = FlowVar % DOFs
265
266
Permutation => Solver%Variable%Perm
267
END SUBROUTINE GET_VARIABLES
268
269
SUBROUTINE COMPUTE_NodeArea(NodeArea)
270
IMPLICIT NONE
271
REAL(KIND=dp),INTENT(OUT) :: NodeArea(:)
272
273
TYPE(Element_t), POINTER :: Element
274
TYPE(Nodes_t),SAVE :: ElementNodes
275
TYPE(GaussIntegrationPoints_t) :: IntegStuff
276
REAL(KIND=dp) :: U,V,W,SqrtElementMetric
277
INTEGER,POINTER :: Indexes(:)
278
INTEGER :: n
279
INTEGER :: t,i
280
LOGICAL :: stat
281
282
283
NodeArea=0._dp
284
285
Do t=1,GetNOFActive()
286
287
Element => GetActiveElement(t)
288
n = GetElementNOFNodes(Element)
289
Indexes => Element % NodeIndexes
290
CALL GetElementNodes( ElementNodes, Element )
291
IntegStuff = GaussPoints( Element )
292
293
Do i=1,IntegStuff % n
294
U = IntegStuff % u(i)
295
V = IntegStuff % v(i)
296
W = IntegStuff % w(i)
297
stat = ElementInfo(Element,ElementNodes,U,V,W,SqrtElementMetric, &
298
Basis,dBasisdx )
299
300
NodeArea(Permutation(Indexes(1:n)))=NodeArea(Permutation(Indexes(1:n)))+&
301
SqrtElementMetric*IntegStuff % s(i) * Basis(1:n)
302
303
End do
304
End do
305
IF (ParEnv % PEs > 1 ) CALL ParallelSumVector( Solver % Matrix, NodeArea, 0 )
306
307
END SUBROUTINE COMPUTE_NodeArea
308
309
SUBROUTINE BODY_INTEGRATION(Volume,VAF,DHDTFlux,SMBFlux,BMBFlux,HMinFlux,&
310
GroundedArea,FloatingArea,FreeArea)
311
IMPLICIT NONE
312
REAL(KIND=dp),INTENT(OUT) :: Volume,VAF,&
313
DHDTFlux,SMBFlux,BMBFlux,HMinFlux,&
314
GroundedArea,FloatingArea,FreeArea
315
REAL(KIND=dp),parameter :: Fsmall=100.0*EPSILON(1.0)
316
317
TYPE(Element_t),POINTER :: Element
318
TYPE(ValueList_t), POINTER :: BodyForce,Material
319
TYPE(GaussIntegrationPoints_t) :: IntegStuff
320
TYPE(Nodes_t),SAVE :: ElementNodes
321
322
REAL(KIND=dp) :: U,V,W,SqrtElementMetric
323
REAL(KIND=dp) :: Normal(3),Flow(3)
324
REAL(KIND=dp) :: cellarea
325
REAL(KIND=dp) :: HAtIP,SMBAtIP,BMBAtIP
326
327
LOGICAL :: CalvingFront
328
LOGICAL :: IsFloating,IceFree
329
LOGICAL :: stat
330
331
INTEGER,POINTER :: NodeIndexes(:)
332
INTEGER :: t
333
INTEGER :: i
334
INTEGER :: n
335
INTEGER :: ne
336
337
ne=GetNOFActive()
338
339
Volume=0._dp
340
VAF=0._dp
341
342
DHDTFlux=0._dp
343
SMBFlux=0._dp
344
BMBFlux=0._dp
345
HMinFlux=0._dp
346
347
GroundedArea=0._dp
348
FloatingArea=0._dp
349
FreeArea=0._dp
350
351
DO t = 1,ne
352
353
Element => GetActiveElement(t)
354
355
IF ( CheckPassiveElement(Element) ) CYCLE
356
357
n = GetElementNOFNodes(Element)
358
NodeIndexes => Element % NodeIndexes
359
CALL GetElementNodes( ElementNodes )
360
361
BodyForce => GetBodyForce(Element)
362
IF (.NOT.ASSOCIATED(BodyForce)) &
363
CALL FATAL(SolverName,'No BodyForce Found')
364
Material => GetMaterial(Element)
365
IF (.NOT.ASSOCIATED(Material)) &
366
CALL FATAL(SolverName,'No Material Found')
367
368
NodalH(1:n) = HVar%Values(HVar%Perm(NodeIndexes(1:n)))
369
NodalDHDT(1:n) = DHDTVar%Values(DHDTVar%Perm(NodeIndexes(1:n)))
370
371
rhoi(1:n) = ListGetReal(Material,'SSA Mean Density',n,NodeIndexes,UnfoundFatal=.TRUE. )
372
373
Do i=1,n
374
NodalHf(i)=Max(0._dp,NodalH(i)-&
375
Max(0._dp,(zsea-BedVar%Values(BedVar%Perm(NodeIndexes(i))))*rhow/rhoi(i)))
376
End do
377
378
MinH=0._dp
379
MinH(1:n) = ListGetReal(Material,'Min H',n,NodeIndexes,UnfoundFatal=.TRUE. )
380
381
382
! FLOATING OR GROUNDED CELL
383
NodalGM(1:n) = GMVar%Values(GMVar%Perm(NodeIndexes(1:n)))
384
IsFloating=ANY(NodalGM(1:n).LT.0._dp)
385
386
! TOP ACCUMULATION
387
NodalSMB=0._dp
388
NodalSMB(1:n) = &
389
ListGetReal(BodyForce,'Top Surface Accumulation', n,NodeIndexes,UnfoundFatal=.TRUE. )
390
391
! Bottom ACCUMULATION
392
NodalBMB=0._dp
393
NodalBMB(1:n) = &
394
ListGetReal(BodyForce,'Bottom Surface Accumulation', n,NodeIndexes,UnfoundFatal=.TRUE. )
395
396
! Total ACCUMULATION
397
NodalMB(1:n) = NodalSMB(1:n) + NodalBMB(1:n)
398
399
! CELL IS NOT ACTIVE ALL H VALUES BELOW MinH Value
400
IceFree=.FALSE.
401
IF (ALL((NodalH(1:n)-MinH(1:n)).LE.Fsmall).AND.ALL(NodalMB(1:n).LT.0._dp)) IceFree=.TRUE.
402
403
! GO TO INTEGRATION
404
cellarea=0._dp
405
LocalArea=0._dp
406
407
IntegStuff = GaussPoints( Element )
408
DO i=1,IntegStuff % n
409
U = IntegStuff % u(i)
410
V = IntegStuff % v(i)
411
W = IntegStuff % w(i)
412
413
stat = ElementInfo(Element,ElementNodes,U,V,W,SqrtElementMetric, &
414
Basis,dBasisdx )
415
! cell area
416
cellarea=cellarea+SqrtElementMetric*IntegStuff % s(i)
417
! the area seen by each node
418
LocalArea(1:n)=LocalArea(1:n)+SqrtElementMetric*IntegStuff % s(i) * Basis(1:n)
419
420
IF (IceFree) CYCLE
421
422
! Integrate H
423
HAtIP=SUM(NodalH(1:n)*Basis(1:n))
424
Volume=Volume+HAtIP*SqrtElementMetric*IntegStuff % s(i)
425
426
VAF=VAF+SUM(NodalHf(1:n)*Basis(1:n))*SqrtElementMetric*IntegStuff % s(i)
427
428
SMBAtIP=SUM(NodalSMB(1:n)*Basis(1:n))
429
BMBAtIP=SUM(NodalBMB(1:n)*Basis(1:n))
430
431
DHDTFlux=DHDTFlux+SUM(NodalDHDT(1:n)*Basis(1:n))*SqrtElementMetric*IntegStuff % s(i)
432
SMBFlux=SMBFlux+SMBAtIP*SqrtElementMetric*IntegStuff % s(i)
433
BMBFlux=BMBFlux+BMBAtIP*SqrtElementMetric*IntegStuff % s(i)
434
435
End DO
436
437
IF (.NOT.IceFree) THEN
438
Do i=1,n
439
HMinFlux = HMinFlux + &
440
HRVar%Values(HRVar%Perm(NodeIndexes(i)))*LocalArea(i)/NodeArea(Permutation(NodeIndexes(i)))
441
End do
442
IF (IsFloating) THEN
443
FloatingArea=FloatingArea+cellarea
444
ELSE
445
GroundedArea=GroundedArea+cellarea
446
END IF
447
ELSE
448
FreeArea=FreeArea+cellarea
449
END IF
450
End do
451
END SUBROUTINE BODY_INTEGRATION
452
453
SUBROUTINE BC_INTEGRATION(CalvingFlux)
454
IMPLICIT NONE
455
REAL(KIND=dp),INTENT(OUT) :: CalvingFlux
456
457
TYPE(Element_t),POINTER :: Element
458
TYPE(ValueList_t), POINTER :: BC
459
TYPE(GaussIntegrationPoints_t) :: IntegStuff
460
TYPE(Nodes_t),SAVE :: ElementNodes
461
462
REAL(KIND=dp) :: U,V,W,SqrtElementMetric
463
REAL(KIND=dp) :: Normal(3),Flow(3)
464
465
LOGICAL :: CalvingFront
466
LOGICAL :: Found
467
LOGICAL :: stat
468
469
INTEGER,POINTER :: NodeIndexes(:)
470
INTEGER :: t
471
INTEGER :: i,j
472
INTEGER :: n
473
474
CalvingFlux=0._dp
475
DO t = 1,GetNOFBoundaryElements()
476
Element => GetBoundaryElement(t)
477
478
IF ( .NOT. ActiveBoundaryElement() ) CYCLE
479
IF ( GetElementFamily() == 1 ) CYCLE
480
481
BC => GetBC()
482
IF ( .NOT. ASSOCIATED(BC) ) CYCLE
483
CalvingFront=.FALSE.
484
CalvingFront=ListGetLogical(BC,'Calving Front', Found)
485
IF (.NOT.CalvingFront) CYCLE
486
487
n = GetElementNOFNodes()
488
NodeIndexes => Element % NodeIndexes
489
CALL GetElementNodes( ElementNodes )
490
491
NodalH(1:n) = HVar%Values(HVar%Perm(NodeIndexes(1:n)))
492
493
IntegStuff = GaussPoints( Element )
494
DO i=1,IntegStuff % n
495
U = IntegStuff % u(i)
496
V = IntegStuff % v(i)
497
W = IntegStuff % w(i)
498
stat = ElementInfo(Element,ElementNodes,U,V,W,SqrtElementMetric, &
499
Basis,dBasisdx )
500
Normal=0._dp
501
Normal = NormalVector( Element,ElementNodes,u,v,.TRUE. )
502
503
Flow=0._dp
504
DO j=1,FlowDofs
505
Flow(j) = SUM( FlowVar % Values(FlowDofs*(FlowVar % Perm(NodeIndexes(1:n)) -1)+j) * Basis(1:n) )
506
END DO
507
CalvingFlux=CalvingFlux+&
508
SUM(NodalH(1:n)*Basis(1:n))*SUM(Normal * Flow)*SqrtElementMetric*IntegStuff % s(i)
509
END DO
510
END DO
511
END SUBROUTINE BC_INTEGRATION
512
513
514
SUBROUTINE COMPUTE_GL_FLUX( GLFlux )
515
IMPLICIT NONE
516
REAL(KIND=DP),INTENT(OUT) :: GLFlux
517
518
TYPE(Mesh_t),POINTER :: Mesh
519
TYPE(Element_t),DIMENSION(:),POINTER :: Edges
520
TYPE(Element_t),POINTER :: Edge,Parent
521
522
REAL(KIND=DP),ALLOCATABLE,SAVE :: LocalGM(:),LocalFlow(:,:),LocalH(:)
523
524
INTEGER, POINTER :: NodeIndexes(:)
525
INTEGER :: Ne
526
INTEGER :: n
527
INTEGER :: i,j
528
INTEGER :: M
529
530
LOGICAL, SAVE :: Firsttime=.TRUE.
531
532
533
IF (Firsttime) THEN
534
M=Model % MaxElementNodes
535
ALLOCATE(LocalGM(M),LocalFlow(3,M),LocalH(M))
536
Firsttime=.FALSE.
537
END IF
538
539
Mesh => GetMesh()
540
541
542
CALL FindMeshEdges(Mesh,.FALSE.)
543
544
Edges => Mesh % Edges
545
Ne = Mesh % NumberOfEdges
546
547
GLFlux=0._dp
548
549
DO i=1,Ne
550
Edge => Edges(i)
551
n=Edge % TYPE % NumberOfNodes
552
NodeIndexes(1:n) => Edge % NodeIndexes(1:n)
553
554
LocalGM(1:n)=GMVar % Values ( GMVar % Perm ( NodeIndexes(1:n) ) )
555
! Edge is GL if all GM=0
556
IF ( ANY( abs(LocalGM(1:n)) .GT. AEPS ) ) CYCLE
557
558
DO j=1,DIM
559
LocalFlow(j,1:n) = FlowVar % Values ( DIM*(FlowVar % Perm ( NodeIndexes(1:n) ) - 1) + j )
560
END DO
561
LocalH(1:n) = HVar % Values ( HVar % Perm ( NodeIndexes(1:n) ) )
562
563
Parent => Edge % BoundaryInfo % Right
564
CALL AddLocalFlux(GLFlux,LocalFlow,LocalH,Edge,Parent,Mesh)
565
Parent => Edge % BoundaryInfo % Left
566
CALL AddLocalFlux(GLFlux,LocalFlow,LocalH,Edge,Parent,Mesh)
567
END DO
568
569
END SUBROUTINE COMPUTE_GL_FLUX
570
571
SUBROUTINE AddLocalFlux(Flux,LocalFlow,LocalH,Edge,Parent,Mesh)
572
IMPLICIT NONE
573
TYPE(Element_t),POINTER :: Edge,Parent
574
TYPE(Mesh_t), POINTER :: Mesh
575
REAL(KIND=dp),INTENT(INOUT) :: Flux
576
REAL(KIND=dp),INTENT(IN) :: LocalFlow(:,:),LocalH(:)
577
578
TYPE(Nodes_t),SAVE :: EdgeNodes
579
TYPE(GaussIntegrationPoints_t) :: IntegStuff
580
REAL(KIND=dp) :: U,V,W,SqrtElementMetric
581
REAL(KIND=dp),ALLOCATABLE,SAVE :: Basis(:), dBasisdx(:,:)
582
583
REAL(KIND=dp),DIMENSION(3) :: dx, Normal,Flow
584
REAL(KIND=dp) :: h
585
586
INTEGER :: i,j
587
INTEGER :: n,np
588
INTEGER :: M
589
590
LOGICAL :: stat
591
LOGICAL,SAVE :: FirstVisit=.TRUE.
592
593
IF (FirstVisit) THEN
594
M=Model % MaxElementNodes
595
ALLOCATE(Basis(M),dBasisdx(M,3))
596
FirstVisit=.FALSE.
597
END IF
598
599
! Parent not associated
600
IF (.NOT.ASSOCIATED(Parent)) RETURN
601
! Parent is halo element
602
IF( Parent % PartIndex /= ParEnv % MyPe ) RETURN
603
!
604
n = Edge % TYPE % NumberOfNodes
605
np = Parent % TYPE % NumberOfNodes
606
607
! GL could be a boundary; compute flux from gounded parent
608
! Parent is Grounded if ANY GM > 0
609
IF (.NOT.( ANY( GMVar % Values( GMVar % Perm( Parent % NodeIndexes(1:np) ) ) .GT. AEPS ) ) ) RETURN
610
! a vector from the center of the edge to the center of the parent to check that normal points outside parent
611
dx = ElementCenter(Mesh,Parent) - ElementCenter(Mesh,Edge)
612
613
CALL GetElementNodes(EdgeNodes, Edge)
614
615
IntegStuff = GaussPoints( Edge )
616
DO i=1,IntegStuff % n
617
U = IntegStuff % u(i)
618
V = IntegStuff % v(i)
619
W = IntegStuff % w(i)
620
stat = ElementInfo( Edge,EdgeNodes,U,V,W,SqrtElementMetric, &
621
Basis,dBasisdx )
622
623
DO j=1,DIM
624
Flow(j) = SUM(LocalFlow(j,1:n)*Basis(1:n))
625
END DO
626
h = SUM(LocalH(1:n)*Basis(1:n))
627
628
Normal = NormalVector( Edge,EdgeNodes,U,V,.FALSE. )
629
630
IF ( SUM(dx(1:DIM)*Normal(1:DIM)).GT.0._dp ) Normal=-Normal
631
632
Flux = Flux + SqrtElementMetric * IntegStuff % s(i) * h * SUM(Normal(1:DIM)*Flow(1:DIM))
633
END DO
634
635
END SUBROUTINE AddLocalFlux
636
!
637
!
638
FUNCTION ElementCenter(Mesh,Element) RESULT(xc)
639
IMPLICIT NONE
640
TYPE(Mesh_t), POINTER :: Mesh
641
TYPE(Element_t),POINTER :: Element
642
REAL(KIND=dp),DIMENSION(3) :: xc
643
INTEGER :: n
644
645
n = Element % TYPE % NumberOfNodes
646
xc=0._dp
647
SELECT CASE( Element % TYPE % ElementCode / 100 )
648
CASE(2,4,8)
649
xc(1) = InterpolateInElement( Element, Mesh % Nodes % x(Element % NodeIndexes(1:n)), 0.0d0, 0.0d0, 0.0d0 )
650
xc(2) = InterpolateInElement( Element, Mesh % Nodes % y(Element % NodeIndexes(1:n)), 0.0d0, 0.0d0, 0.0d0 )
651
CASE(3)
652
xc(1) = InterpolateInElement( Element, Mesh % Nodes % x(Element % NodeIndexes(1:n)), 1.0d0/3, 1.0d0/3, 0.0d0 )
653
xc(2) = InterpolateInElement( Element, Mesh % Nodes % y(Element % NodeIndexes(1:n)), 1.0d0/3, 1.0d0/3, 0.0d0 )
654
CASE DEFAULT
655
CALL FATAL(SolverName,'Element type not supported')
656
END SELECT
657
658
END FUNCTION ElementCenter
659
660
661
662
663
END
664
665