Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/BasalMelt3D.F90
3204 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 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
! * This is a (3D) improvement of FrontalMelt (USF_Frontal) with basic plume shape etc
24
! * Plume locations are defined by a point in (x,y). When the front moves,
25
! * plumes are assumed to move normal to the average front parallel.
26
!
27
! * Plumes are defined in BC section, e.g.:
28
! * Plume Count = 1
29
! * Plume 1 X = 10550.0
30
! * Plume 1 Y = -96651.0
31
! ******************************************************************************
32
! *
33
! * Authors: Joe Todd
34
! * Email: [email protected]
35
! * Web: http://www.csc.fi/elmer
36
! * Address: CSC - IT Center for Science Ltd.
37
! * Keilaranta 14
38
! * 02101 Espoo, Finland
39
! *
40
! * Original Date: 19.01.2016
41
! *
42
! ****************************************************************************/
43
44
SUBROUTINE BasalMelt3D (Model, Solver, dt, TransientSimulation)
45
USE Types
46
USE CoordinateSystems
47
USE DefUtils
48
USE ElementDescription
49
USE CalvingGeometry
50
51
IMPLICIT NONE
52
53
TYPE(Model_t) :: Model
54
TYPE(Solver_t) :: Solver
55
REAL(KIND=dp) :: dt
56
LOGICAL :: TransientSimulation
57
!-----------------------------------
58
TYPE(Mesh_t), POINTER :: Mesh
59
TYPE(Matrix_t), POINTER :: Matrix
60
TYPE(Variable_t), POINTER :: Var, GroundedVar
61
TYPE(ValueList_t), POINTER :: Params
62
TYPE(CrevasseGroup3D_t), POINTER :: FloatGroups, CurrentGroup, DelGroup
63
TYPE(Element_t), POINTER :: Element
64
TYPE(Nodes_t) :: ElementNodes
65
TYPE(GaussIntegrationPoints_t) :: IntegStuff
66
67
REAL(KIND=dp) :: MeltRate, SMeltRate, WMeltRate, SStart, SStop, &
68
TotalArea, TotalBMelt, ElemBMelt, s, t, season,&
69
SqrtElementMetric,U,V,W,Basis(Model % MaxElementNodes)
70
#ifdef ELMER_BROKEN_MPI_IN_PLACE
71
REAL(KIND=dp) :: buffer
72
#endif
73
INTEGER :: DIM, NoNodes, i,j,n, FaceNodeCount, GroupNodeCount, county, &
74
Active, ierr, k, FoundNew, AllFoundNew
75
INTEGER, PARAMETER :: FileUnit = 75
76
INTEGER, POINTER :: Perm(:), InvPerm(:), FrontPerm(:)=>NULL(), Neighbours(:,:), &
77
NeighbourHolder(:), NoNeighbours(:), NodeIndexes(:)
78
INTEGER, ALLOCATABLE :: AllGroupNodes(:), PartNodeCount(:), AllPartGroupNodes(:), &
79
disps(:)
80
LOGICAL :: Found, OutputStats, Visited=.FALSE., Debug, stat, Summer
81
CHARACTER(LEN=MAX_NAME_LEN) :: SolverName, GMaskVarName, FrontMaskName, OutfileName, mode
82
83
Debug = .FALSE.
84
85
SolverName = "BasalMelt3D"
86
Params => Solver % Values
87
Mesh => Solver % Mesh
88
89
DIM = CoordinateSystemDimension()
90
IF(DIM /= 3) CALL Fatal(SolverName, "This solver only works in 3D!")
91
92
t = GetTime()
93
season = t - FLOOR(t)
94
95
mode = ListGetString( Params, 'Basal Melt Mode', Found, UnfoundFatal=.TRUE.)
96
mode = TRIM(mode)
97
98
!Get output file name for stats
99
OutfileName = ListGetString(Params,"Basal Melt Stats File", OutputStats, UnfoundFatal=.TRUE.)
100
101
!Identify nodes on the front
102
FrontMaskName = "Calving Front Mask"
103
CALL MakePermUsingMask( Model, Solver, Mesh, FrontMaskName, &
104
.FALSE., FrontPerm, FaceNodeCount)
105
106
!Need the matrix for finding neighbours
107
Matrix => Solver % Matrix
108
109
Var => Solver % Variable
110
IF(.NOT. ASSOCIATED(Var)) CALL Fatal(SolverName, "Solver needs a variable!")
111
Perm => Var % Perm
112
Var % Values = 0.0_dp
113
114
NoNodes = COUNT(Perm > 0)
115
116
GMaskVarName = ListGetString(Params, "GroundedMask Variable", Found)
117
IF(.NOT. Found) GMaskVarName = "GroundedMask"
118
GroundedVar => VariableGet(Mesh % Variables, GMaskVarName, .TRUE., UnfoundFatal=.TRUE.)
119
120
SELECT CASE(mode)
121
CASE("seasonal")
122
SMeltRate = ListGetConstReal(Params, "Basal Melt Summer Rate", UnfoundFatal=.TRUE.)
123
WMeltRate = ListGetConstReal(Params, "Basal Melt Winter Rate", UnfoundFatal=.TRUE.)
124
SStart = ListGetConstReal(Params, "Basal Melt Summer Start", UnfoundFatal=.TRUE.)
125
SStop = ListGetConstReal(Params, "Basal Melt Summer Stop", UnfoundFatal=.TRUE.)
126
127
Summer = .FALSE.
128
IF(SStop > SStart) THEN
129
IF(season > SStart .AND. season < SStop) Summer = .TRUE.
130
ELSE
131
IF(season > SStart .OR. season < SStop) Summer = .TRUE.
132
END IF
133
134
IF(Summer) THEN
135
MeltRate = SMeltRate
136
ELSE
137
MeltRate = WMeltRate
138
END IF
139
CASE("off")
140
MeltRate = 0.0_dp
141
CASE DEFAULT
142
CALL Fatal(SolverName, "Unknown basal melt mode, valid options are 'seasonal' and 'off'.")
143
END SELECT
144
145
!Set up inverse perm for FindNodeNeighbours
146
InvPerm => CreateInvPerm(Matrix % Perm) !Create inverse perm for neighbour search
147
ALLOCATE(Neighbours(Mesh % NumberOfNodes, 10), NoNeighbours(Mesh % NumberOfNodes))
148
Neighbours = 0
149
150
!Find neighbours for each node on the bed
151
DO i=1, Mesh % NumberOfNodes
152
IF(Perm(i) <= 0) CYCLE
153
154
NeighbourHolder => FindNodeNeighbours(i, Matrix, &
155
Matrix % Perm, 1, InvPerm)
156
157
Neighbours(i,1:SIZE(NeighbourHolder)) = NeighbourHolder
158
NoNeighbours(i) = SIZE(NeighbourHolder)
159
DEALLOCATE(NeighbourHolder)
160
END DO
161
162
!Reuse some old calving code
163
!Find groups of connected floating nodes on the base
164
FloatGroups => NULL()
165
CALL FindCrevasseGroups(Mesh, GroundedVar, Neighbours, &
166
-0.5_dp, FloatGroups)
167
168
!Check groups are valid (connected to front)
169
CurrentGroup => FloatGroups
170
DO WHILE(ASSOCIATED(CurrentGroup))
171
172
CurrentGroup % FrontConnected = .FALSE.
173
DO i=1, CurrentGroup % NumberOfNodes
174
175
IF(FrontPerm(CurrentGroup % NodeNumbers(i)) > 0) THEN
176
CurrentGroup % FrontConnected = .TRUE.
177
EXIT
178
END IF
179
END DO
180
CurrentGroup => CurrentGroup % Next
181
END DO
182
183
DO k=1,1000
184
FoundNew = 0
185
186
!Count and gather nodes from all valid groups
187
GroupNodeCount = 0
188
county = 0
189
DO i=1,2
190
IF(i==2) ALLOCATE(AllGroupNodes(GroupNodeCount))
191
192
CurrentGroup => FloatGroups
193
DO WHILE(ASSOCIATED(CurrentGroup))
194
IF(CurrentGroup % FrontConnected) THEN
195
196
IF(i==1) THEN
197
GroupNodeCount = GroupNodeCount + CurrentGroup % NumberOfNodes
198
ELSE
199
DO j=1, CurrentGroup % NumberOfNodes
200
county = county + 1
201
AllGroupNodes(county) = Mesh % ParallelInfo % GlobalDOFs(CurrentGroup % NodeNumbers(j))
202
END DO
203
END IF
204
END IF
205
CurrentGroup => CurrentGroup % Next
206
END DO
207
END DO
208
209
!Distribute info to/from all partitions about groups connected to front
210
ALLOCATE(PartNodeCount(ParEnv % PEs))
211
212
CALL MPI_ALLGATHER(GroupNodeCount, 1, MPI_INTEGER, PartNodeCount, 1, &
213
MPI_INTEGER, MPI_COMM_WORLD, ierr)
214
215
ALLOCATE(AllPartGroupNodes(SUM(PartNodeCount)), disps(ParEnv % PEs))
216
disps(1) = 0
217
DO i=2,ParEnv % PEs
218
disps(i) = disps(i-1) + PartNodeCount(i-1)
219
END DO
220
221
CALL MPI_ALLGATHERV(AllGroupNodes, GroupNodeCount, MPI_INTEGER, &
222
AllPartGroupNodes, PartNodeCount, disps, MPI_INTEGER, MPI_COMM_WORLD, ierr)
223
224
!Cycle unconnected groups, looking for partition boundary in connected groups
225
CurrentGroup => FloatGroups
226
DO WHILE(ASSOCIATED(CurrentGroup))
227
IF(.NOT. CurrentGroup % FrontConnected) THEN
228
DO i=1,CurrentGroup % NumberOfNodes
229
230
IF(ANY(Mesh % ParallelInfo % GlobalDOFs(CurrentGroup % NodeNumbers(i)) == &
231
AllPartGroupNodes)) THEN
232
CurrentGroup % FrontConnected = .TRUE.
233
FoundNew = 1
234
END IF
235
236
END DO
237
END IF
238
CurrentGroup => CurrentGroup % Next
239
END DO
240
CALL MPI_ALLREDUCE(FoundNew, AllFoundNew, 1, MPI_INTEGER, MPI_MAX, ELMER_COMM_WORLD, ierr)
241
IF(AllFoundNew == 1) THEN
242
DEALLOCATE(AllGroupNodes, PartNodeCount, AllPartGroupNodes, disps)
243
ELSE
244
EXIT
245
END IF
246
END DO !k
247
248
!Cycle all connected groups, setting melt rate
249
CurrentGroup => FloatGroups
250
DO WHILE(ASSOCIATED(CurrentGroup))
251
IF(CurrentGroup % FrontConnected) THEN
252
DO i=1,CurrentGroup % NumberOfNodes
253
Var % Values(Var % Perm(CurrentGroup % NodeNumbers(i))) = MeltRate
254
END DO
255
END IF
256
CurrentGroup => CurrentGroup % Next
257
END DO
258
259
IF(OutputStats) THEN
260
261
IF ( CurrentCoordinateSystem() /= Cartesian ) &
262
CALL Fatal(SolverName, "Only cartesian coordinate system supported.")
263
264
n = Mesh % MaxElementNodes
265
ALLOCATE(ElementNodes % x(n),&
266
ElementNodes % y(n),&
267
ElementNodes % z(n))
268
269
!Integrate melt rate and area
270
TotalBMelt = 0.0_dp
271
TotalArea = 0.0_dp
272
273
Active = GetNOFActive()
274
DO i=1,Active
275
276
Element => GetActiveElement(i)
277
ElemBMelt = 0.0_dp
278
279
n = Element % TYPE % NumberOfNodes
280
NodeIndexes => Element % NodeIndexes
281
282
!Not interested in area/melt calcs for grounded elements
283
IF(ALL(GroundedVar % Values(GroundedVar % Perm(NodeIndexes)) >= 0)) CYCLE
284
285
ElementNodes % x(1:n) = Mesh % Nodes % x(NodeIndexes(1:n))
286
ElementNodes % y(1:n) = Mesh % Nodes % y(NodeIndexes(1:n))
287
ElementNodes % z(1:n) = Mesh % Nodes % z(NodeIndexes(1:n))
288
289
IntegStuff = GaussPoints( Element )
290
291
DO j=1,IntegStuff % n
292
293
U = IntegStuff % u(j)
294
V = IntegStuff % v(j)
295
W = IntegStuff % w(j)
296
297
!------------------------------------------------------------------------------
298
! Basis function values at the integration point
299
!------------------------------------------------------------------------------
300
stat = ElementInfo( Element,ElementNodes,U,V,W,SqrtElementMetric, &
301
Basis )
302
303
!assume cartesian here
304
s = SqrtElementMetric * IntegStuff % s(j)
305
306
!Check here for grounded
307
ElemBMelt = ElemBMelt + s * SUM(Var % Values(Var % Perm(NodeIndexes)) * Basis(1:n))
308
TotalArea = TotalArea + s
309
END DO
310
311
TotalBMelt = TotalBMelt + ElemBMelt
312
END DO
313
DEALLOCATE(ElementNodes % x, ElementNodes % y, ElementNodes % z)
314
315
IF(Debug) THEN
316
PRINT *, 'BasalMelt3D: total submarine area: ',TotalArea
317
PRINT *, 'BasalMelt3D: total background melt: ',TotalBMelt
318
END IF
319
320
#ifdef ELMER_BROKEN_MPI_IN_PLACE
321
buffer = TotalArea
322
CALL MPI_AllReduce(buffer, &
323
#else
324
CALL MPI_AllReduce(MPI_IN_PLACE, &
325
#endif
326
TotalArea, 1, MPI_DOUBLE_PRECISION, MPI_SUM, MPI_COMM_WORLD, ierr)
327
328
#ifdef ELMER_BROKEN_MPI_IN_PLACE
329
buffer = TotalBMelt
330
CALL MPI_AllReduce(buffer, &
331
#else
332
CALL MPI_AllReduce(MPI_IN_PLACE, &
333
#endif
334
TotalBMelt, 1, MPI_DOUBLE_PRECISION, MPI_SUM, MPI_COMM_WORLD, ierr)
335
336
IF(ParEnv % MyPE == 0) THEN
337
IF(.NOT. Visited) THEN
338
Visited = .TRUE.
339
OPEN( UNIT=FileUnit, File=OutfileName, STATUS='UNKNOWN')
340
WRITE(FileUnit, '(A)') "Timestep, Time, Ungrounded Area, &
341
&Total Basal Melt (m^3)"
342
ELSE
343
OPEN( UNIT=FileUnit, File=OutfileName, STATUS='UNKNOWN', POSITION='APPEND' )
344
END IF
345
346
WRITE(FileUnit, '(I0,ES20.11,ES20.11,ES20.11)') &
347
GetTimestep(), GetTime(), TotalArea, TotalBMelt
348
349
CLOSE( FileUnit )
350
END IF
351
352
! IF(AverageMelt) THEN
353
! scale = Target_BMelt_Average / BMelt_Average
354
! BMeltRate = BMeltRate * scale
355
! !Also scale total value for output
356
! TotalBMelt = TotalBMelt * scale
357
358
! IF(Debug) PRINT *,'Plume, Scaling background melt by factor: ', scale
359
360
! scale = Target_PMelt_Average / PMelt_Average
361
! PMeltRate = PMeltRate * scale
362
! !Also scale total value for output
363
! TotalPMelt = TotalPMelt * scale
364
365
! IF(Debug) PRINT *,'Plume, Scaling plume melt by factor: ', scale
366
! END IF
367
END IF
368
369
!Deallocate floatgroups linked list
370
CurrentGroup => FloatGroups
371
DO WHILE(ASSOCIATED(CurrentGroup))
372
DelGroup => CurrentGroup
373
CurrentGroup => CurrentGroup % Next
374
375
IF(ASSOCIATED(DelGroup % NodeNumbers)) DEALLOCATE(DelGroup % NodeNumbers)
376
IF(ASSOCIATED(DelGroup % FrontNodes)) DEALLOCATE(DelGroup % FrontNodes)
377
IF(ASSOCIATED(DelGroup % BoundaryNodes)) DEALLOCATE(DelGroup % BoundaryNodes)
378
DEALLOCATE(DelGroup)
379
END DO
380
381
DEALLOCATE(Neighbours, NoNeighbours, FrontPerm, InvPerm)
382
END SUBROUTINE BasalMelt3D
383
384