Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Utils/ComputeFluxUtils.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
27
! * Email: [email protected]
28
! * Web: http://elmerice.elmerfem.org
29
! *
30
! * Original Date: May 2022
31
! *
32
! ******************************************************************************/
33
!--------------------------------------------------------------------------------
34
!> Module containing utility routines to compute fluxes e.g. at the GL
35
!--------------------------------------------------------------------------------
36
MODULE ComputeFluxUtils
37
USE DefUtils
38
39
IMPLICIT NONE
40
CONTAINS
41
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
42
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
43
!! Compute grounding line flux for 2D applications
44
!! the mean flow velocity should be the main solver variable (e.g. ssavelocity)
45
!! required variable groundemask,H
46
!! output variable ligroundf: the element mean GL Flux
47
!!
48
!! GL flux is the sum of all fluxes from the GL_Edges of a partially
49
!! grounded element, i.e. which contain the True GL.
50
!! a GL_Edge has 2 Groundedmask==0 (so limited to linear elements for now)
51
!! a partially grounded element has at least one GL_Edge and one floating node
52
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
53
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
54
SUBROUTINE ComputeGLFlux_2D(Solver,FillValue)
55
TYPE(Solver_t) :: Solver
56
REAL(KIND=dp), OPTIONAL :: FillValue
57
58
Type(Mesh_t), POINTER :: Mesh
59
Type(Variable_t), POINTER :: GMask,FlowVar,HVar,EFluxVar
60
Type(Element_t), POINTER :: Element,Edge
61
TYPE(Nodes_t),SAVE :: EdgeNodes,ElementNodes
62
INTEGER :: tt,ii,jj,kk
63
INTEGER :: M,n,nEdges
64
INTEGER :: ngl
65
INTEGER :: DIM
66
INTEGER, POINTER :: NodeIndexes(:)
67
LOGICAL, SAVE :: FirstTime=.TRUE.
68
CHARACTER(LEN=MAX_NAME_LEN) :: Caller="ComputeGLFlux_2D"
69
70
REAL(KIND=dp), ALLOCATABLE,SAVE :: NodalGM(:)
71
REAL(KIND=dp), ALLOCATABLE,SAVE :: Basis(:)
72
TYPE(GaussIntegrationPoints_t) :: IntegStuff
73
REAL(KIND=dp) :: U,V,W,detJ
74
REAL(KIND=dp),DIMENSION(3) :: Normal,Flow
75
REAL(KIND=dp) :: Flux,area,H
76
INTEGER :: EIndex
77
LOGICAL :: stat
78
79
IF (FirstTime) THEN
80
M = CurrentModel % MaxElementNodes
81
ALLOCATE(NodalGM(M), Basis(M))
82
FirstTime=.FALSE.
83
END IF
84
85
!! get required variables
86
EFluxVar => VariableGet(Solver%Mesh%Variables,'ligroundf',UnfoundFatal=.TRUE.)
87
IF (EFluxVar % TYPE /= Variable_on_elements) &
88
CALL FATAL(Caller,"ligroundf type should be on_elements")
89
90
!! min horizontal velocity; SSA velocity in general....
91
FlowVar => Solver % Variable
92
DIM = FlowVar % DOFs
93
IF (DIM /= 2) &
94
CALL Fatal(Caller,"Can't handle but 2D flow variable, sorry")
95
!! grounded mask
96
GMask => VariableGet(Solver%Mesh%Variables,'GroundedMask',UnfoundFatal=.TRUE.)
97
98
!! thickness
99
HVar => VariableGet(Solver%Mesh%Variables,'H',UnfoundFatal=.TRUE.)
100
101
Mesh => Solver % Mesh
102
103
! Edges will be required....
104
CALL FindMeshEdges(Mesh,FindFaces=.FALSE.)
105
106
IF (PRESENT(FillValue)) THEN
107
EFluxVar % Values = FillValue
108
ELSE
109
EFluxVar % Values = 0._dp
110
END IF
111
112
DO tt=1,Solver % NumberOfActiveElements
113
Element => GetActiveElement(tt)
114
115
IF (Element % TYPE % BasisFunctionDegree>1) &
116
CALL Fatal(Caller,"Can't handle but linear elements, sorry.")
117
118
n = GetElementNOFNodes(Element)
119
NodeIndexes => Element % NodeIndexes
120
121
NodalGM(1:n) = GMask % Values ( GMask % Perm ( NodeIndexes(1:n) ) )
122
123
! we have an edge GL if at least 2 nodes are GL
124
! and we have a least one floating node
125
ngl=COUNT(NodalGM == 0)
126
IF (ngl < 2) CYCLE
127
IF (.NOT.ANY(NodalGM(1:n).LT.0._dp)) CYCLE
128
129
!! compute total flux from edges
130
nEdges = Element % Type % NumberOfEdges
131
Flux = 0._dp
132
DO ii=1,nEdges
133
Edge => Mesh%Edges(Element % EdgeIndexes(ii))
134
n = GetElementNOFNodes(Edge)
135
NodeIndexes => Edge % NodeIndexes
136
NodalGM(1:n) = GMask % Values ( GMask % Perm ( NodeIndexes(1:n) ) )
137
! Edge is GL if all GM=0
138
IF ( ANY( abs(NodalGM(1:n)) .GT. AEPS ) ) CYCLE
139
140
CALL GetElementNodes(EdgeNodes, Edge)
141
142
IntegStuff = GaussPoints( Edge )
143
DO kk=1,IntegStuff % n
144
U = IntegStuff % u(kk)
145
V = IntegStuff % v(kk)
146
W = IntegStuff % w(kk)
147
stat = ElementInfo(Edge,EdgeNodes,U,V,W,detJ,Basis)
148
149
! normal will poingt ou of the parent
150
Normal = -NormalVector(Edge,EdgeNodes,U,V,.FALSE.,Element)
151
152
DO jj=1,DIM
153
Flow(jj) = SUM( FlowVar % Values ( DIM*(FlowVar % Perm ( NodeIndexes(1:n) ) - 1) + jj ) * Basis(1:n))
154
END DO
155
H = SUM (HVar % Values ( HVar % Perm ( NodeIndexes(1:n) ) ) * Basis(1:n))
156
157
Flux = Flux + detJ * IntegStuff % s(kk) * h * SUM(Normal(1:DIM)*Flow(1:DIM))
158
END DO
159
END DO
160
161
CALL GetElementNodes(ElementNodes, Element)
162
! compute element area
163
IntegStuff = GaussPoints( Element )
164
area=0._dp
165
DO kk=1,IntegStuff % n
166
U = IntegStuff % u(kk)
167
V = IntegStuff % v(kk)
168
W = IntegStuff % w(kk)
169
stat = ElementInfo(Element,ElementNodes,U,V,W,detJ,Basis)
170
area=area+IntegStuff % s(kk)*detJ
171
END DO
172
173
! mean flux
174
EIndex=Element % ElementIndex
175
IF (ASSOCIATED(EFluxVar % Perm)) EIndex=EFluxVar % Perm (EIndex)
176
IF (EIndex > 0) EFluxVar % Values ( EIndex ) = Flux / area
177
178
END DO
179
180
END SUBROUTINE ComputeGLFlux_2D
181
182
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
183
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
184
!! Compute Calving Front flux for 2D applications
185
!! the mean flow velocity should be the main solver variable (e.g. ssavelocity)
186
!! required variable H
187
!! output variable : calving_front_flux the parent element mean Calving Front flux
188
!!
189
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
190
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
191
SUBROUTINE ComputeCalvingFrontFlux_2D(Solver,FillValue)
192
TYPE(Solver_t) :: Solver
193
REAL(KIND=dp), OPTIONAL :: FillValue
194
195
Type(Variable_t), POINTER :: FlowVar,HVar,CFluxVar
196
TYPE(ValueList_t), POINTER :: BC
197
TYPE(GaussIntegrationPoints_t) :: IntegStuff
198
TYPE(Element_t), POINTER :: Element,Parent
199
TYPE(Nodes_t),SAVE :: ElementNodes,ParentNodes
200
201
REAL(KIND=dp), ALLOCATABLE,SAVE :: Basis(:)
202
REAL(KIND=dp) :: U,V,W,detJ
203
REAL(KIND=dp) :: Normal(3),Flow(3)
204
REAL(KIND=dp) :: CalvingFlux,H
205
REAL(KIND=dp) :: area
206
207
INTEGER,POINTER :: NodeIndexes(:)
208
INTEGER :: t,i,j,k
209
INTEGER :: n
210
INTEGER :: M
211
INTEGER :: EIndex,NofActive
212
INTEGER :: DIM
213
214
LOGICAL :: CalvingFront
215
LOGICAL :: Found
216
LOGICAL :: stat
217
LOGICAL,SAVE :: FirstTime=.TRUE.
218
LOGICAL,ALLOCATABLE :: VisitedParent(:)
219
220
CHARACTER(LEN=MAX_NAME_LEN) :: Caller="ComputeCalvingFrontFlux_2D"
221
222
IF (FirstTime) THEN
223
M = CurrentModel % MaxElementNodes
224
ALLOCATE(Basis(M))
225
FirstTime=.FALSE.
226
END IF
227
228
229
!! get required variables
230
CFluxVar => VariableGet(Solver%Mesh%Variables,'calving_front_flux',UnfoundFatal=.TRUE.)
231
IF (CFluxVar % TYPE /= Variable_on_elements) &
232
CALL FATAL(Caller,"calving_front_flux type should be on_elements")
233
234
IF (PRESENT(FillValue)) THEN
235
CFluxVar % Values = FillValue
236
ELSE
237
CFluxVar % Values = 0._dp
238
END IF
239
240
NofActive = Solver % Mesh % NumberOfBulkElements
241
ALLOCATE(VisitedParent(NofActive))
242
VisitedParent=.FALSE.
243
244
!! min horizontal velocity; SSA velocity in general....
245
FlowVar => Solver % Variable
246
DIM = FlowVar % DOFs
247
IF (DIM /= 2) &
248
CALL Fatal(Caller,"Can't handle but 2D flow variable, sorry")
249
250
!! thickness
251
HVar => VariableGet(Solver%Mesh%Variables,'H',UnfoundFatal=.TRUE.)
252
253
254
DO t = 1,GetNOFBoundaryElements()
255
Element => GetBoundaryElement(t)
256
IF ( .NOT. ActiveBoundaryElement(Element,Solver) ) CYCLE
257
IF ( GetElementFamily(Element) == 1 ) CYCLE
258
259
BC => GetBC()
260
IF ( .NOT. ASSOCIATED(BC) ) CYCLE
261
CalvingFront=.FALSE.
262
CalvingFront=ListGetLogical(BC,'Calving Front', Found)
263
IF (.NOT.CalvingFront) CYCLE
264
265
n = GetElementNOFNodes(Element)
266
NodeIndexes => Element % NodeIndexes
267
CALL GetElementNodes( ElementNodes )
268
269
IntegStuff = GaussPoints( Element )
270
CalvingFlux = 0._dp
271
DO i=1,IntegStuff % n
272
U = IntegStuff % u(i)
273
V = IntegStuff % v(i)
274
W = IntegStuff % w(i)
275
stat = ElementInfo(Element,ElementNodes,U,V,W,detJ,Basis)
276
277
Normal=0._dp
278
Normal = NormalVector( Element,ElementNodes,u,v,.TRUE. )
279
280
Flow=0._dp
281
DO j=1,DIM
282
Flow(j) = SUM( FlowVar % Values(DIM*(FlowVar % Perm(NodeIndexes(1:n))-1)+j) * Basis(1:n) )
283
END DO
284
285
H = SUM (HVar % Values ( HVar % Perm ( NodeIndexes(1:n) ) ) * Basis(1:n))
286
287
CalvingFlux=CalvingFlux+&
288
H*SUM(Normal * Flow)*detJ*IntegStuff % s(i)
289
END DO
290
291
! attribute the flux to the active parent
292
Parent => Element % BoundaryInfo % Right
293
IF (ASSOCIATED(Parent)) THEN
294
! we can have a passive/active BC=> we attribute the flux to
295
! the active parent
296
IF (CheckPassiveElement( Parent )) &
297
Parent => Element % BoundaryInfo % Left
298
ELSE
299
Parent => Element % BoundaryInfo % Left
300
END IF
301
IF (.NOT.ASSOCIATED(Parent)) CYCLE
302
IF (ParEnv % myPe .NE. Parent % partIndex) CYCLE
303
304
CALL GetElementNodes(ParentNodes,Parent)
305
! compute element area
306
IntegStuff = GaussPoints( Parent )
307
area=0._dp
308
DO k=1,IntegStuff % n
309
U = IntegStuff % u(k)
310
V = IntegStuff % v(k)
311
W = IntegStuff % w(k)
312
stat = ElementInfo(Parent,ParentNodes,U,V,W,detJ,Basis)
313
area=area+IntegStuff % s(k)*detJ
314
END DO
315
316
! mean flux
317
EIndex=Parent % ElementIndex
318
IF (ASSOCIATED(CFluxVar % Perm)) EIndex=CFluxVar % Perm (EIndex)
319
IF (EIndex > 0) THEN
320
IF (VisitedParent(Parent % ElementIndex)) THEN
321
CFluxVar % Values ( EIndex ) = CFluxVar % Values ( EIndex ) + CalvingFlux / area
322
ELSE
323
CFluxVar % Values ( EIndex ) = CalvingFlux / area
324
IF (Parent % ElementIndex.GT.NofActive) &
325
CALL FATAL(Caller,"Pb with VisitedParent allocated size")
326
VisitedParent(Parent % ElementIndex)=.TRUE.
327
END IF
328
END IF
329
330
END DO
331
332
DEALLOCATE(VisitedParent)
333
334
End
335
336
END MODULE
337
338