Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/UserFunctions/USF_GlacierMeshMetric.F90
3196 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: Joe Todd
26
! * Email:
27
! * Web: http://elmerice.elmerfem.org
28
! *
29
! * Original Date: 18/10/19
30
! *
31
! *****************************************************************************
32
!> Computes anisotropic target element size based on distance from calving front
33
SUBROUTINE GlacierMeshMetricAniso(Model, nodenumber, y, TargetLength)
34
35
USE DefUtils
36
37
IMPLICIT NONE
38
39
TYPE(Model_t) :: Model
40
INTEGER :: nodenumber
41
REAL(KIND=dp) :: y, TargetLength(:)
42
!----------------------------------------------------------
43
TYPE(Mesh_t), POINTER :: Mesh
44
TYPE(ValueList_t), POINTER :: Material
45
TYPE(Variable_t), POINTER :: TimeVar
46
TYPE(Solver_t), POINTER :: Solver
47
REAL(KIND=dp) :: xx,yy,zz,t,told, this_dist, MinDist2, Dist,&
48
lc_mindist, lc_maxdist, lc_min, lc_max,s,dx,dz,NodeDepth,NodeElev
49
REAL(KIND=dp), DIMENSION(3) :: Point
50
INTEGER, POINTER :: FrontPerm(:),BottomPerm(:),SurfacePerm(:),Nodeindexes(:)
51
INTEGER :: i,NNodes, NFront, layers, nbottom, n, BCTag, nsurface
52
LOGICAL :: NewTime,FirstTime=.TRUE., Debug, Found, ExtrudeLayers, ThisBC
53
LOGICAL, ALLOCATABLE :: BottomElemMask(:), SurfElemMask(:)
54
CHARACTER(LEN=MAX_NAME_LEN) :: FrontMaskName,BottomMaskName,SurfaceMaskName
55
56
SAVE :: FirstTime, told, FrontPerm, Mesh, NNodes, nfront, lc_maxdist, lc_mindist,&
57
lc_max, lc_min, dz, newtime, ExtrudeLayers, layers, BottomElemMask, BottomPerm,&
58
SurfElemMask, SurfacePerm
59
60
Debug = .FALSE.
61
Timevar => VariableGet( Model % Variables,'Time')
62
t = TimeVar % Values(1)
63
Solver => Model % Solver
64
FrontMaskName="Calving Front Mask"
65
BottomMaskName="Bottom Surface Mask"
66
SurfaceMaskName='Top Surface Mask'
67
68
IF (FirstTime) THEN
69
FirstTime = .FALSE.
70
NewTime = .TRUE.
71
told = t
72
73
Mesh => Model % Mesh
74
Material => GetMaterial(Mesh % Elements(1)) !TODO, this is not generalised
75
76
lc_maxdist = ListGetConstReal(Material, "GlacierMeshMetric Max Distance", DefValue=2000.0_dp)
77
lc_mindist = ListGetConstReal(Material, "GlacierMeshMetric Min Distance", DefValue=200.0_dp)
78
lc_max = ListGetConstReal(Material, "GlacierMeshMetric Max LC", DefValue=500.0_dp)
79
lc_min = ListGetConstReal(Material, "GlacierMeshMetric Min LC", DefValue=75.0_dp)
80
ExtrudeLayers = ListGetLogical(Material,"GlacierMeshMetric Vertical From Layers", DefValue=.FALSE.)
81
IF(ExtrudeLayers) THEN
82
layers = ListGetInteger(Material, "GlacierMeshMetric Vertical Layers", Found=Found)
83
IF(.NOT. Found) CALL FATAL('GlacierMeshMetric', 'Vertical requested by layers but number of layers not given')
84
ELSE
85
dz = ListGetConstReal(Material, "GlacierMeshMetric Vertical LC", DefValue=50.0_dp)
86
END IF
87
END IF
88
89
IF(t > told) NewTime = .TRUE. !TODO - replace this with Samuel's mesh counter logic
90
IF(NewTime) THEN
91
told = t
92
NewTime = .FALSE.
93
94
Mesh => Model % Mesh
95
NNodes = Mesh % NumberOfNodes
96
97
!mask is the most computationally expense element of this routine
98
IF(ASSOCIATED(FrontPerm)) DEALLOCATE(FrontPerm)
99
CALL MakePermUsingMask( Model, Solver, Mesh, FrontMaskName, &
100
.FALSE., FrontPerm, nfront, ParallelComm = .FALSE.)
101
102
IF(ExtrudeLayers) THEN
103
104
! create top and bottom perms
105
IF(ASSOCIATED(BottomPerm)) DEALLOCATE(BottomPerm)
106
CALL MakePermUsingMask( Model, Solver, Mesh, BottomMaskName, &
107
.FALSE., BottomPerm, nbottom, ParallelComm = .FALSE.)
108
IF(ASSOCIATED(SurfacePerm)) DEALLOCATE(SurfacePerm)
109
CALL MakePermUsingMask( Model, Solver, Mesh, SurfaceMaskName, &
110
.FALSE., SurfacePerm, nsurface, ParallelComm = .FALSE.)
111
112
!create mask of elems as with an unstructred mesh all nodes can be in mask but not elem
113
DO i=1,Model % NumberOfBCs
114
ThisBC = ListGetLogical(Model % BCs(i) % Values, BottomMaskName, Found)
115
IF((.NOT. Found) .OR. (.NOT. ThisBC)) CYCLE
116
BCtag = Model % BCs(i) % Tag
117
EXIT
118
END DO
119
120
IF(ALLOCATED(BottomElemMask)) DEALLOCATE(BottomElemMask)
121
ALLOCATE(BottomElemMask(Mesh % NumberOfBulkElements &
122
+ Mesh % NumberOfBoundaryElements))
123
BottomElemMask = .TRUE.
124
DO i=Mesh % NumberOfBulkElements+1, &
125
Mesh % NumberOfBulkElements+Mesh % NumberOfBoundaryElements
126
IF(Mesh % Elements(i) % BoundaryInfo % constraint == BCTag) &
127
BottomElemMask(i) = .FALSE.
128
END DO
129
130
!create mask of elems as with an unstructred mesh all nodes can be in mask but not elem
131
DO i=1,Model % NumberOfBCs
132
ThisBC = ListGetLogical(Model % BCs(i) % Values, SurfaceMaskName, Found)
133
IF((.NOT. Found) .OR. (.NOT. ThisBC)) CYCLE
134
BCtag = Model % BCs(i) % Tag
135
EXIT
136
END DO
137
138
IF(ALLOCATED(SurfElemMask)) DEALLOCATE(SurfElemMask)
139
ALLOCATE(SurfElemMask(Mesh % NumberOfBulkElements &
140
+ Mesh % NumberOfBoundaryElements))
141
SurfElemMask = .TRUE.
142
DO i=Mesh % NumberOfBulkElements+1, &
143
Mesh % NumberOfBulkElements+Mesh % NumberOfBoundaryElements
144
IF(Mesh % Elements(i) % BoundaryInfo % constraint == BCTag) &
145
SurfElemMask(i) = .FALSE.
146
END DO
147
END IF
148
149
END IF
150
151
xx = Mesh % Nodes % x(nodenumber)
152
yy = Mesh % Nodes % y(nodenumber)
153
zz = Mesh % Nodes % z(nodenumber)
154
155
MinDist2 = HUGE(MinDist2)
156
DO i=1,NNodes
157
IF(FrontPerm(i) == 0) CYCLE
158
!Note - sqrt is an expensive FLOP so only do it once...
159
this_dist = ((xx - Mesh % Nodes % x(i))**2.0) + &
160
((yy - Mesh % Nodes % y(i))**2.0) + &
161
((zz - Mesh % Nodes % z(i))**2.0)
162
MinDist2 = MIN(this_dist, MinDist2)
163
END DO
164
Dist = SQRT(MinDist2)
165
166
!Apply caps to this distance:
167
Dist = MAX(Dist,lc_mindist)
168
Dist = MIN(Dist,lc_maxdist)
169
170
s = (Dist - lc_mindist) / (lc_maxdist - lc_mindist)
171
dx = s*lc_max + (1-s)*lc_min
172
173
TargetLength(1) = dx
174
TargetLength(2) = dx
175
176
IF(ExtrudeLayers) THEN
177
178
Point(1) = xx
179
Point(2) = yy
180
Point(3) = 0.0_dp
181
182
NodeDepth = GetZFromMask(Mesh, Point, BottomPerm, BottomElemMask)
183
NodeElev = GetZFromMask(Mesh, Point, SurfacePerm, SurfElemMask)
184
185
dz = (NodeElev-NodeDepth)/(layers-1)
186
187
TargetLength(3) = dz
188
ELSE
189
TargetLength(3) = dz
190
END IF
191
192
IF(Debug) PRINT *,'Node ',nodenumber,'TargetLength: ',TargetLength,' dist: ',Dist,' s: ',s
193
194
CONTAINS
195
196
FUNCTION GetZFromMask(Mesh, Point, NodePerm, ElemMask) RESULT(NodeDepth)
197
198
TYPE(Mesh_t), POINTER :: Mesh
199
REAL(KIND=dp), DIMENSION(3) :: Point
200
INTEGER, POINTER :: NodePerm(:)
201
LOGICAL, ALLOCATABLE :: ElemMask(:)
202
REAL(KIND=dp) :: NodeDepth
203
!-----------------------------------------
204
TYPE(Element_t),POINTER :: Element
205
TYPE(Nodes_t) :: ElementNodes
206
REAL(KIND=dp), POINTER :: ElementValues(:)
207
REAL(KIND=dp), DIMENSION(3) :: NodeCoord, LocalCoordinates
208
REAL(KIND=dp), DIMENSION(2) :: Distances, Depths, Weights
209
REAL(KIND=dp) :: eps_global_limit, eps_local_limit,&
210
eps_global, eps_local, eps_numeric
211
REAL(KIND=dp) :: MinDist,MinDist2,dist
212
INTEGER :: i,n,NodeIndx,NodeIndx2
213
LOGICAL :: Found
214
215
eps_global = 2.0e-10_dp
216
eps_local = 1.0e-10_dp
217
eps_numeric = 1.0e-10_dp
218
eps_global_limit = 1.0E-2_dp
219
eps_local_limit = 1.0E-2_dp
220
221
n = Mesh % MaxElementNodes
222
ALLOCATE( ElementNodes % x(n), ElementNodes % y(n), &
223
ElementNodes % z(n), ElementValues(n) )
224
225
DO WHILE(.TRUE.)
226
DO i=1, Mesh % NumberOfBulkElements + Mesh % NumberOfBoundaryElements
227
228
IF(ElemMask(i)) CYCLE
229
230
Element => Mesh % Elements(i)
231
n = Element % TYPE % NumberOfNodes
232
NodeIndexes => Element % NodeIndexes
233
234
ElementNodes % x(1:n) = Mesh % Nodes % x(NodeIndexes)
235
ElementNodes % y(1:n) = Mesh % Nodes % y(NodeIndexes)
236
ElementNodes % z = 0.0_dp
237
Found = PointInElement( Element, ElementNodes, &
238
Point, LocalCoordinates, eps_global, eps_local, eps_numeric)
239
IF( Found ) EXIT
240
END DO
241
IF( Found ) EXIT
242
243
eps_global = eps_global * 10.0_dp
244
eps_local = eps_local * 10.0_dp
245
IF(eps_global > eps_global_limit) EXIT
246
IF(eps_local > eps_local_limit) EXIT
247
END DO
248
249
IF(.NOT. Found) THEN
250
251
MinDist = HUGE(1.0_dp); MinDist2 = HUGE(1.0_dp)
252
DO i=1,NNodes
253
254
IF(NodePerm(i) == 0) CYCLE
255
256
NodeCoord(1) = Mesh % Nodes % x(i)
257
NodeCoord(2) = Mesh % Nodes % y(i)
258
NodeCoord(3) = 0.0_dp
259
260
Dist = SUM( ( Point(:2) - NodeCoord(:2) )**2 )
261
IF( Dist < MinDist ) THEN
262
IF(MinDist < MinDist2) THEN
263
MinDist2 = MinDist
264
NodeIndx2 = NodeIndx
265
END IF
266
MinDist = Dist
267
NodeIndx = i
268
ELSE IF( Dist < MinDist2) THEN
269
MinDist2 = Dist
270
NodeIndx2 = i
271
END IF
272
END DO
273
274
Distances(1) = MinDist ** 0.5
275
Distances(2) = MinDist2 ** 0.5
276
277
Weights(1) = Distances(1) ** (-1.0_dp)
278
Weights(2) = Distances(2) ** (-1.0_dp)
279
280
Depths(1) = Mesh % Nodes % z(NodeIndx) * Weights(1)
281
Depths(2) = Mesh % Nodes % z(NodeIndx2) * Weights(2)
282
283
NodeDepth = SUM(Depths)/SUM(Weights)
284
ELSE
285
ElementValues(1:n) = Mesh % Nodes % z(NodeIndexes)
286
287
NodeDepth = InterpolateInElement( &
288
Element, ElementValues, LocalCoordinates(1), &
289
LocalCoordinates(2), LocalCoordinates(3) )
290
END IF
291
END FUNCTION GetZFromMask
292
293
END SUBROUTINE GlacierMeshMetricAniso
294
295