Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/FreeSurface.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
! * FreeSurface utilities
27
! ! TODO: Not quite finished
28
! ! TODO1: outdated should be removed... (12.12.2003, Juha)
29
! *
30
! ******************************************************************************
31
! *
32
! * Authors: Juha Ruokolainen
33
! * Email: [email protected]
34
! * Web: http://www.csc.fi/elmer
35
! * Address: CSC - IT Center for Science Ltd.
36
! * Keilaranta 14
37
! * 02101 Espoo, Finland
38
! *
39
! * Original Date: 02 Jun 1997
40
! *
41
! ****************************************************************************/
42
43
!> Internal free surface utilities.
44
!> \deprecated
45
!> \ingroup ElmerLib
46
!> \{
47
48
MODULE FreeSurface
49
50
USE DirectSolve
51
USE IterSolve
52
USE ElementUtils
53
USE ElementDescription, ONLY : FirstDerivativeInU2D, FirstDerivativeInV2D, &
54
NormalVector, CheckNormalDirection
55
56
IMPLICIT NONE
57
58
CONTAINS
59
!-------------------------------------------------------------------------------
60
!
61
!
62
SUBROUTINE MeanCurvature( Model )
63
!-------------------------------------------------------------------------------
64
TYPE(Model_t) :: Model
65
!-------------------------------------------------------------------------------
66
INTEGER :: i,j,k,n,t,BC,NodeIndexes(16)
67
INTEGER, POINTER :: Reorder(:),Visited(:)
68
LOGICAL :: L
69
70
REAL(KIND=dp) :: ddxddu,ddyddu,ddzddu,ddxdudv,ddydudv,ddzdudv, &
71
ddxddv,ddyddv,ddzddv,Auu,Auv,Avv,Buu,Buv,Bvv,detA,u,v,x,y,z
72
73
REAL(KIND=dp), ALLOCATABLE :: dxdu(:),dydu(:),dzdu(:)
74
REAL(KIND=dp), ALLOCATABLE :: dxdv(:),dydv(:),dzdv(:)
75
76
REAL(KIND=dp), TARGET :: nx(16),ny(16),nz(16),Nrm(3)
77
REAL(KIND=dp), POINTER :: Curvature(:)
78
79
REAL(KIND=dp) :: Basis(16),dBasisdx(16,3),ddBasisddx(16,3,3)
80
TYPE(Nodes_t) :: Nodes
81
TYPE(Element_t), POINTER :: Boundary
82
83
LOGICAL :: stat
84
85
REAL(KIND=dp) :: Metric(3,3),SqrtMetric,Symbols(3,3,3),dSymbols(3,3,3,3)
86
!-------------------------------------------------------------------------------
87
ALLOCATE( Visited(Model % NumberOfNodes) )
88
89
IF ( .NOT.ASSOCIATED( Model % FreeSurfaceNodes) ) THEN
90
ALLOCATE( Model % FreeSurfaceNodes( Model % NumberOfNodes ) )
91
Model % FreeSurfaceNodes = 0
92
END IF
93
Reorder => Model % FreeSurfaceNodes
94
95
! Count nodes on free boundaries, and make a permutation table for nodes,
96
! should perhaps be saved instead of recomputed every time:
97
!------------------------------------------------------------------------
98
Visited = 0
99
Reorder = 0
100
k = 0
101
DO BC = 1,Model % NumberOfBCs
102
IF (.NOT. ListGetLogical(Model % BCs(BC) % Values, 'Free Surface',L)) CYCLE
103
104
DO t=Model % NumberOfBulkElements+1,Model % NumberOfBulkElements + &
105
Model % NumberOfBoundaryElements
106
107
Boundary => Model % Elements(t)
108
IF ( Boundary % BoundaryInfo % Constraint /= BC ) CYCLE
109
110
n = Boundary % Type % NumberOfNodes
111
DO i=1,n
112
j = Boundary % NodeIndexes(i)
113
IF ( Visited(j) == 0 ) THEN
114
k = k + 1
115
Reorder(j) = k
116
END IF
117
Visited(j) = Visited(j) + 1
118
END DO
119
END DO
120
END DO
121
!-------------------------------------------------------------------------------
122
! If no free surfaces, return
123
!-------------------------------------------------------------------------------
124
IF ( k == 0 ) THEN
125
DEALLOCATE( Visited )
126
RETURN
127
END IF
128
!-------------------------------------------------------------------------------
129
! Allocate some memories...
130
!-------------------------------------------------------------------------------
131
IF ( .NOT.ASSOCIATED( Model % BoundaryCurvatures ) ) THEN
132
ALLOCATE( Model % BoundaryCurvatures(k) )
133
END IF
134
Curvature => Model % BoundaryCurvatures
135
Curvature = 0.0D0
136
137
ALLOCATE( dxdu(k),dydu(k),dzdu(k),dxdv(k),dydv(k),dzdv(k) )
138
dxdu = 0.0D0
139
dydu = 0.0D0
140
dzdu = 0.0D0
141
dxdv = 0.0D0
142
dydv = 0.0D0
143
dzdv = 0.0D0
144
!-------------------------------------------------------------------------------
145
! Compute sum of first derivatives on nodes of the boundaries
146
!-------------------------------------------------------------------------------
147
DO BC = 1,Model % NumberOfBCs
148
149
IF (.NOT. ListGetLogical(Model % BCs(BC) % Values, 'Free Surface',L)) CYCLE
150
151
DO t=Model % NumberOfBulkElements+1,Model % NumberOfBulkElements + &
152
Model % NumberOfBoundaryElements
153
154
Boundary => Model % Elements(t)
155
IF ( Boundary % BoundaryInfo % Constraint /= BC ) CYCLE
156
157
n = Boundary % Type % NumberOfNodes
158
nx(1:n) = Model % Nodes % x(Boundary % NodeIndexes)
159
ny(1:n) = Model % Nodes % y(Boundary % NodeIndexes)
160
nz(1:n) = Model % Nodes % z(Boundary % NodeIndexes)
161
#if 1
162
nodes % x => nx(1:n)
163
nodes % y => ny(1:n)
164
nodes % z => nz(1:n)
165
#endif
166
167
DO i=1,n
168
j = Reorder(Boundary % NodeIndexes(i))
169
170
IF ( Boundary % Type % Dimension == 1 ) THEN
171
u = Boundary % Type % NodeU(i)
172
173
#if 0
174
dxdu(j) = dxdu(j) + FirstDerivative1D( Boundary,nx(1:n),u )
175
dydu(j) = dydu(j) + FirstDerivative1D( Boundary,ny(1:n),u )
176
#else
177
stat = ElementInfo( Boundary, Nodes, u, 0.0d0, 0.0d0, detA, &
178
Basis, dBasisdx )
179
dydu(j) = dydu(j) + SUM( dBasisdx(1:n,1) * ny(1:n) )
180
#endif
181
ELSE
182
u = Boundary % Type % NodeU(i)
183
v = Boundary % Type % NodeV(i)
184
185
dxdu(j) = dxdu(j) + FirstDerivativeInU2D( Boundary,nx(1:n),u,v )
186
dydu(j) = dydu(j) + FirstDerivativeInU2D( Boundary,ny(1:n),u,v )
187
dzdu(j) = dzdu(j) + FirstDerivativeInU2D( Boundary,nz(1:n),u,v )
188
189
dxdv(j) = dxdv(j) + FirstDerivativeInV2D( Boundary,nx(1:n),u,v )
190
dydv(j) = dydv(j) + FirstDerivativeInV2D( Boundary,ny(1:n),u,v )
191
dzdv(j) = dzdv(j) + FirstDerivativeInV2D( Boundary,nz(1:n),u,v )
192
END IF
193
END DO
194
END DO
195
END DO
196
197
!-------------------------------------------------------------------------------
198
! Average of the derivatives at nodes...
199
!-------------------------------------------------------------------------------
200
DO BC=1,Model % NumberOfBCs
201
IF (.NOT. ListGetLogical(Model % BCs(BC) % Values, 'Free Surface',L)) CYCLE
202
203
DO t=Model % NumberOfBulkElements+1,Model % NumberOfBulkElements + &
204
Model % NumberOfBoundaryElements
205
206
Boundary => Model % Elements(t)
207
IF ( Boundary % BoundaryInfo % Constraint /= BC ) CYCLE
208
209
n = Boundary % Type % NumberOfNodes
210
DO i=1,n
211
j = Boundary % NodeIndexes(i)
212
IF ( Visited(j) > 0 ) THEN
213
dxdu(Reorder(j)) = dxdu(Reorder(j)) / Visited(j)
214
dydu(Reorder(j)) = dydu(Reorder(j)) / Visited(j)
215
dzdu(Reorder(j)) = dzdu(Reorder(j)) / Visited(j)
216
dxdv(Reorder(j)) = dxdu(Reorder(j)) / Visited(j)
217
dydv(Reorder(j)) = dydv(Reorder(j)) / Visited(j)
218
dzdv(Reorder(j)) = dzdv(Reorder(j)) / Visited(j)
219
Visited(j) = -Visited(j)
220
END IF
221
END DO
222
END DO
223
END DO
224
225
Visited = ABS( Visited )
226
227
!-------------------------------------------------------------------------------
228
! The curvature computation begins
229
!-------------------------------------------------------------------------------
230
DO BC=1,Model % NumberOfBCs
231
232
IF (.NOT. ListGetLogical(Model % BCs(BC) % Values, 'Free Surface',L)) CYCLE
233
234
DO t=Model % NumberOfBulkElements+1,Model % NumberOfBulkElements + &
235
Model % NumberOfBoundaryElements
236
237
Boundary => Model % Elements(t)
238
239
IF ( Boundary % BoundaryInfo % Constraint /= BC ) CYCLE
240
241
n = Boundary % Type % NumberOfNodes
242
NodeIndexes(1:n) = Boundary % NodeIndexes
243
!-------------------------------------------------------------------------------
244
! Go through element nodal points
245
!-------------------------------------------------------------------------------
246
#if 1
247
nx(1:n) = Model % Nodes % x(NodeIndexes(1:n))
248
ny(1:n) = Model % Nodes % y(NodeIndexes(1:n))
249
nz(1:n) = Model % Nodes % z(NodeIndexes(1:n))
250
nodes % x => nx(1:n)
251
nodes % y => ny(1:n)
252
nodes % z => nz(1:n)
253
#endif
254
DO i=1,n
255
j = Reorder( NodeIndexes(i) )
256
257
u = Boundary % Type % NodeU(i)
258
v = 0.0D0
259
IF ( Boundary % Type % Dimension > 1 ) v = Boundary % Type % NodeV(i)
260
261
SqrtMetric = 1.0D0
262
x = Model % Nodes % x(NodeIndexes(i))
263
y = Model % Nodes % y(NodeIndexes(i))
264
z = Model % Nodes % z(NodeIndexes(i))
265
266
IF (CurrentCoordinateSystem() /= Cartesian ) THEN
267
CALL CoordinateSystemInfo( Metric,SqrtMetric,Symbols,dSymbols,X,Y,Z )
268
END IF
269
!-------------------------------------------------------------------------------
270
! 2D case, compute the curvature
271
!-------------------------------------------------------------------------------
272
IF ( Boundary % Type % Dimension == 1 ) THEN
273
#if 0
274
!-------------------------------------------------------------------------------
275
! Second partial derivatives of the space coordinates with respect to
276
! curve coordinate
277
!-------------------------------------------------------------------------------
278
ddxddu = FirstDerivative1D( Boundary,dxdu(Reorder(NodeIndexes(1:n))),u )
279
ddyddu = FirstDerivative1D( Boundary,dydu(Reorder(NodeIndexes(1:n))),u )
280
!-------------------------------------------------------------------------------
281
! curve 'metric'
282
!-------------------------------------------------------------------------------
283
Auu = dxdu(j)*dxdu(j) + dydu(j)*dydu(j)
284
detA = 1.0d0 / SQRT(Auu)
285
286
Nrm(1) = -dydu(j)
287
Nrm(2) = dxdu(j)
288
Nrm(3) = 0.0D0
289
Nrm = Nrm / SQRT( SUM( Nrm**2 ) )
290
CALL CheckNormalDirection( Boundary,Nrm,x,y,z )
291
!-------------------------------------------------------------------------------
292
! and finally the curvature
293
!-------------------------------------------------------------------------------
294
Curvature(j) = Curvature(j) + &
295
0.5d0 * Auu * ( ddxddu*Nrm(1) + ddyddu*Nrm(2) )
296
#else
297
stat = ElementInfo( Boundary, Nodes, u, 0.0d0, 0.0d0, detA, &
298
Basis, dBasisdx, ddBasisddx, .TRUE. )
299
ddyddu = SUM( dBasisdx(1:n,1) * dydu(Reorder(NodeIndexes(1:n))) )
300
Curvature(j) = Curvature(j) + ( y * ddyddu - (1+dydu(j)**2) ) / ( y * ( 1+dydu(j)**2 )**(3.0d0/2.0d0) )
301
#endif
302
303
304
ELSE
305
!-------------------------------------------------------------------------------
306
! 3D case, compute the curvature
307
!-------------------------------------------------------------------------------
308
u = Boundary % Type % NodeU(i)
309
v = Boundary % Type % NodeV(i)
310
!-------------------------------------------------------------------------------
311
! Second partial derivatives of the space coordinates with respect to
312
! surface coordinates
313
!-------------------------------------------------------------------------------
314
ddxddu = FirstDerivativeInU2D( Boundary, dxdu(NodeIndexes(1:n)),u,v )
315
ddyddu = FirstDerivativeInU2D( Boundary, dydu(NodeIndexes(1:n)),u,v )
316
ddzddu = FirstDerivativeInU2D( Boundary, dzdu(NodeIndexes(1:n)),u,v )
317
318
ddxdudv = FirstDerivativeInU2D( Boundary, dxdv(NodeIndexes(1:n)),u,v )
319
ddydudv = FirstDerivativeInU2D( Boundary, dydv(NodeIndexes(1:n)),u,v )
320
ddzdudv = FirstDerivativeInU2D( Boundary, dzdv(NodeIndexes(1:n)),u,v )
321
322
ddxddv = FirstDerivativeInV2D( Boundary, dxdv(NodeIndexes(1:n)),u,v )
323
ddyddv = FirstDerivativeInV2D( Boundary, dydv(NodeIndexes(1:n)),u,v )
324
ddzddv = FirstDerivativeInV2D( Boundary, dzdv(NodeIndexes(1:n)),u,v )
325
!-------------------------------------------------------------------------------
326
! Surface metric
327
!-------------------------------------------------------------------------------
328
Auu = dxdu(k)*dxdu(k) + dydu(k)*dydu(k) + dzdu(k)*dzdu(k)
329
Auv = dxdu(k)*dxdv(k) + dydu(k)*dydv(k) + dzdu(k)*dzdv(k)
330
Avv = dxdv(k)*dxdv(k) + dydv(k)*dydv(k) + dzdv(k)*dzdv(k)
331
332
detA = 1.0D0 / SQRT(Auu*Avv - Auv*Auv)
333
!-------------------------------------------------------------------------------
334
! Change metric to contravariant form
335
!-------------------------------------------------------------------------------
336
u = Auu
337
Auu = Avv * detA
338
Auv = -Auv * detA
339
Avv = u * detA
340
!-------------------------------------------------------------------------------
341
! Normal vector to surface
342
!-------------------------------------------------------------------------------
343
Nrm(1) = (dydu(k) * dzdv(k) - dydv(k) * dzdu(k)) * detA
344
Nrm(2) = (dxdv(k) * dzdu(k) - dxdu(k) * dzdv(k)) * detA
345
Nrm(3) = (dxdu(k) * dydv(k) - dxdv(k) * dydu(k)) * detA
346
Nrm = Nrm / SQRT( SUM( Nrm**2 ) )
347
348
CALL CheckNormalDirection( Boundary,Nrm,x,y,z )
349
!-------------------------------------------------------------------------------
350
! The second fundamental form of the surface
351
!-------------------------------------------------------------------------------
352
Buu = ddxddu * Nrm(1) + ddyddu * Nrm(2) + ddzddu * Nrm(3)
353
Buv = ddxdudv * Nrm(1) + ddydudv * Nrm(2) + ddzdudv * Nrm(3)
354
Bvv = ddxddv * Nrm(1) + ddyddv * Nrm(2) + ddzddv * Nrm(3)
355
!-------------------------------------------------------------------------------
356
! And finally, the curvature
357
!-------------------------------------------------------------------------------
358
Curvature(j) = Curvature(j) + (Auu*Buu + 2*Auv*Buv + Avv*Bvv)
359
END IF
360
END DO
361
END DO
362
END DO
363
visited=abs(visited)
364
!-------------------------------------------------------------------------------
365
! Average to nodes
366
!-------------------------------------------------------------------------------
367
DO BC=1,Model % NumberOfBCs
368
IF (.NOT. ListGetLogical(Model % BCs(BC) % Values, 'Free Surface',L)) CYCLE
369
370
DO t=Model % NumberOfBulkElements+1,Model % NumberOfBulkElements + &
371
Model % NumberOfBoundaryElements
372
373
Boundary => Model % Elements(t)
374
IF ( Boundary % BoundaryInfo % Constraint /= BC ) CYCLE
375
376
n = Boundary % Type % NumberOfNodes
377
DO i=1,n
378
j = Boundary % NodeIndexes(i)
379
IF ( Visited(j) > 0 ) THEN
380
Curvature(Reorder(j)) = Curvature(Reorder(j)) / Visited(j)
381
write(*,*) j,curvature(Reorder(j))
382
Visited(j) = -Visited(j)
383
END IF
384
END DO
385
END DO
386
END DO
387
!-------------------------------------------------------------------------------
388
! We are done here.
389
!-------------------------------------------------------------------------------
390
DEALLOCATE( Visited,dxdu,dydu,dzdu,dxdv,dydv,dzdv )
391
print*,'----------------------'
392
!-------------------------------------------------------------------------------
393
END SUBROUTINE MeanCurvature
394
!-------------------------------------------------------------------------------
395
396
397
398
399
!-------------------------------------------------------------------------------
400
SUBROUTINE MoveBoundary( Model,Relax )
401
!-------------------------------------------------------------------------------
402
USE DefUtils
403
TYPE(Model_t) :: Model
404
REAL(KIND=dp) :: Relax
405
!-------------------------------------------------------------------------------
406
INTEGER :: i,ii,j,k,m,n,t,Which, FIter
407
LOGICAL, ALLOCATABLE :: Visited(:),Turned(:)
408
LOGICAL :: L
409
410
REAL(KIND=dp) :: Auu,Auv,Avv,Buu,Buv,Bvv,detA,u,v,x,y,z,S,R,Ux,Uy,Uz
411
412
REAL(KIND=dp) :: dxdu,dydu,dzdu, FEPS
413
REAL(KIND=dp) :: dxdv,dydv,dzdv,x1,x2,y1,y2,z1,z2
414
415
REAL(KIND=dp), TARGET :: N1,N2,N3,Nrm(3)
416
REAL(KIND=dp), POINTER :: Curvature(:)
417
418
TYPE(Element_t), POINTER :: Boundary, Element
419
TYPE(Nodes_t) :: BoundaryNodes, ElementNodes
420
421
REAL(KIND=dp), ALLOCATABLE :: XCoord(:),YCoord(:),ZCoord(:), AvarageNormal(:,:)
422
LOGICAL :: XMoved, YMoved, ZMoved
423
424
TYPE( Variable_t), POINTER :: Velocity1,Velocity2,Velocity3
425
426
TYPE(Mesh_t), POINTER :: Mesh
427
TYPE(ValueList_t), POINTER :: BC
428
429
REAL(KIND=dp) :: SqrtMetric, dLBasisdx(16,2),NodalBasis(16)
430
431
SAVE BoundaryNodes, ElementNodes
432
!-------------------------------------------------------------------------------
433
434
FEPS = ListGetConstReal( Model % Solver % Values, &
435
'Free Surface Convergence Tolerance', L )
436
IF ( .NOT. L ) FEPS = 1.0d-12
437
438
FIter = ListGetInteger( Model % Solver % Values, &
439
'Free Surface Max Iterations', L )
440
IF ( .NOT. L ) FIter = 100
441
442
Velocity1 => VariableGet( Model % Variables, 'Velocity 1' )
443
Velocity2 => VariableGet( Model % Variables, 'Velocity 2' )
444
Velocity3 => VariableGet( Model % Variables, 'Velocity 3' )
445
!-------------------------------------------------------------------------------
446
ALLOCATE( Visited(Model % NumberOfNodes),Turned(Model % NumberOfNodes) )
447
Visited = .FALSE.
448
Turned = .FALSE.
449
!-------------------------------------------------------------------------------
450
451
ALLOCATE( XCoord(Model % NumberOfNodes) )
452
XMoved = .FALSE.
453
XCoord = Model % Nodes % x
454
455
ALLOCATE( YCoord(Model % NumberOfNodes) )
456
YMoved = .FALSE.
457
YCoord = Model % Nodes % y
458
459
ALLOCATE( ZCoord(Model % NumberOfNodes) )
460
ZMoved = .FALSE.
461
ZCoord = Model % Nodes % z
462
463
ALLOCATE( AvarageNormal(Model % NumberOfBCs,3) )
464
AvarageNormal = 0
465
466
Ux = 0; Uy = 0; Uz = 0;
467
!-------------------------------------------------------------------------------
468
! Check normal direction first in a separate loop, cause within the node
469
! moving loop, the parent elements might be a little funny...!
470
!-------------------------------------------------------------------------------
471
Mesh => Model % Solver % Mesh
472
DO t = 1,Mesh % NumberOfBoundaryElements
473
Boundary => GetBoundaryElement(t)
474
BC => GetBC()
475
476
IF ( .NOT. ASSOCIATED(BC) ) CYCLE
477
IF ( .NOT.GetLogical(BC, 'Free Surface',L) ) CYCLE
478
IF ( .NOT. ActiveBoundaryElement() ) CYCLE
479
480
n = GetElementNOFNodes()
481
CALL GetElementNodes( BoundaryNodes )
482
!-------------------------------------------------------------------------------
483
! Go through boundary element nodes
484
!-------------------------------------------------------------------------------
485
DO i=1,n
486
k = Boundary % NodeIndexes(i)
487
488
IF ( Boundary % Type % Dimension == 1 ) THEN
489
IF ( i==1 ) THEN
490
j=2
491
ELSE
492
j=1
493
END IF
494
j = Boundary % NodeIndexes(j)
495
x1 = XCoord(j) - XCoord(k)
496
y1 = YCoord(j) - YCoord(k)
497
498
Ux = Velocity1 % Values( Velocity1 % Perm(k) )
499
Uy = Velocity2 % Values( Velocity2 % Perm(k) )
500
501
IF ( Ux*x1 + Uy*y1 > 0 ) CYCLE
502
END IF
503
504
!-------------------------------------------------------------------------------
505
! Should not move the same node twice,so check if already done
506
!-------------------------------------------------------------------------------
507
IF ( .NOT.Visited(k) ) THEN
508
Visited(k) = .TRUE.
509
!-------------------------------------------------------------------------------
510
! 2D case, compute normal
511
!-------------------------------------------------------------------------------
512
IF ( Boundary % Type % Dimension == 1 ) THEN
513
u = Boundary % Type % NodeU(i)
514
!------------------------------------------------------------------------------
515
! Basis function derivatives with respect to local coordinates
516
!------------------------------------------------------------------------------
517
NodalBasis(1:n) = 0.0d0
518
DO m=1,n
519
NodalBasis(m) = 1.0d0
520
dLBasisdx(m,1) = FirstDerivative1D( Boundary,NodalBasis,u )
521
NodalBasis(m) = 0.0d0
522
END DO
523
524
Nrm(1) = -SUM( BoundaryNodes % y(1:n)*dLBasisdx(1:n,1) )
525
Nrm(2) = SUM( BoundaryNodes % x(1:n)*dLBasisdx(1:n,1) )
526
Nrm(3) = 0.0D0
527
ELSE
528
!-------------------------------------------------------------------------------
529
! 3D case, compute normal
530
!-------------------------------------------------------------------------------
531
u = Boundary % Type % NodeU(i)
532
v = Boundary % Type % NodeV(i)
533
534
NodalBasis(1:n) = 0.0D0
535
DO m=1,N
536
NodalBasis(m) = 1.0D0
537
dLBasisdx(m,1) = FirstDerivativeInU2D( Boundary,NodalBasis,u,v )
538
dLBasisdx(m,2) = FirstDerivativeInV2D( Boundary,NodalBasis,u,v )
539
NodalBasis(m) = 0.0D0
540
END DO
541
542
dxdu = SUM( BoundaryNodes % x(1:n) * dLBasisdx(1:n,1) )
543
dydu = SUM( BoundaryNodes % y(1:n) * dLBasisdx(1:n,1) )
544
dzdu = SUM( BoundaryNodes % z(1:n) * dLBasisdx(1:n,1) )
545
546
dxdv = SUM( BoundaryNodes % x(1:n) * dLBasisdx(1:n,2) )
547
dydv = SUM( BoundaryNodes % y(1:n) * dLBasisdx(1:n,2) )
548
dzdv = SUM( BoundaryNodes % z(1:n) * dLBasisdx(1:n,2) )
549
550
Nrm(1) = dydu * dzdv - dydv * dzdu
551
Nrm(2) = dxdv * dzdu - dxdu * dzdv
552
Nrm(3) = dxdu * dydv - dxdv * dydu
553
END IF
554
!-------------------------------------------------------------------------------
555
! Turn the normal to point outwards, or towards less dense material
556
!-------------------------------------------------------------------------------
557
x = Model % Nodes % x(k)
558
y = Model % Nodes % y(k)
559
z = Model % Nodes % z(k)
560
CALL CheckNormalDirection( Boundary,Nrm,x,y,z,Turned(k) )
561
562
m = Boundary % BoundaryInfo % Constraint
563
R = SQRT(SUM(Nrm**2))
564
AvarageNormal(m,1:3) = AvarageNormal(m,1:3) + ABS(Nrm)/R
565
END IF
566
END DO
567
END DO
568
569
!-------------------------------------------------------------------------------
570
! Iterate until convergence
571
!-------------------------------------------------------------------------------
572
DO ii=1,FIter
573
S = 0.0d0
574
Visited = .FALSE.
575
576
DO t=1,Mesh % NumberOfBoundaryElements
577
Boundary => GetBoundaryElement(t)
578
BC => GetBC()
579
580
IF ( .NOT. ASSOCIATED(BC) ) CYCLE
581
IF (.NOT.GetLogical(BC, 'Free Surface',L)) CYCLE
582
IF ( .NOT. ActiveBoundaryElement() ) CYCLE
583
584
i = CoordinateSystemDimension()
585
Which = ListGetInteger( BC, 'Free Coordinate', L,minv=1, maxv=i )
586
IF ( .NOT. L ) THEN
587
i = Boundary % BoundaryInfo % Constraint
588
Nrm = AvarageNormal(i,:)
589
Which = 1
590
DO i=2,3
591
IF ( Nrm(i) > Nrm(Which) ) Which=i
592
END DO
593
END IF
594
595
n = GetElementNOFNOdes()
596
CALL GetElementNodes( BoundaryNodes )
597
598
DO i=1,n
599
k = Boundary % NodeIndexes(i)
600
601
IF ( Boundary % Type % Dimension == 1 ) THEN
602
IF ( i==1 ) THEN
603
j=2
604
ELSE
605
j=1
606
END IF
607
j = Boundary % NodeIndexes(j)
608
x1 = XCoord(j) - XCoord(k)
609
y1 = YCoord(j) - YCoord(k)
610
611
Ux = Velocity1 % Values( Velocity1 % Perm(k) )
612
Uy = Velocity2 % Values( Velocity2 % Perm(k) )
613
614
IF ( Ux*x1 + Uy*y1 > 0 ) CYCLE
615
END IF
616
617
!-------------------------------------------------------------------------------
618
! Should not move the same node twice,so check if already done
619
!-------------------------------------------------------------------------------
620
IF ( .NOT.Visited(k) ) THEN
621
Visited(k) = .TRUE.
622
!-------------------------------------------------------------------------------
623
! 2D case, compute normal
624
!-------------------------------------------------------------------------------
625
IF ( Boundary % Type % Dimension == 1 ) THEN
626
u = Boundary % Type % NodeU(i)
627
!------------------------------------------------------------------------------
628
! Basis function derivatives with respect to local coordinates
629
!------------------------------------------------------------------------------
630
NodalBasis(1:n) = 0.0D0
631
DO m=1,n
632
NodalBasis(m) = 1.0D0
633
dLBasisdx(m,1) = FirstDerivative1D( Boundary,NodalBasis,u )
634
NodalBasis(m) = 0.0D0
635
END DO
636
637
Nrm(1) = -SUM( BoundaryNodes % y(1:n)*dLBasisdx(1:n,1) )
638
Nrm(2) = SUM( BoundaryNodes % x(1:n)*dLBasisdx(1:n,1) )
639
Nrm(3) = 0.0D0
640
ELSE
641
!----------------------------------------------------------------------------
642
! 3D case, compute normal
643
!----------------------------------------------------------------------------
644
u = Boundary % Type % NodeU(i)
645
v = Boundary % Type % NodeV(i)
646
647
NodalBasis(1:n) = 0.0D0
648
DO j=1,n
649
NodalBasis(j) = 1.0D0
650
dLBasisdx(j,1) = FirstDerivativeInU2D( Boundary,NodalBasis,u,v )
651
dLBasisdx(j,2) = FirstDerivativeInV2D( Boundary,NodalBasis,u,v )
652
NodalBasis(j) = 0.0D0
653
END DO
654
655
dxdu = SUM( BoundaryNodes % x(1:n) * dLBasisdx(1:n,1) )
656
dydu = SUM( BoundaryNodes % y(1:n) * dLBasisdx(1:n,1) )
657
dzdu = SUM( BoundaryNodes % z(1:n) * dLBasisdx(1:n,1) )
658
659
dxdv = SUM( BoundaryNodes % x(1:n) * dLBasisdx(1:n,2) )
660
dydv = SUM( BoundaryNodes % y(1:n) * dLBasisdx(1:n,2) )
661
dzdv = SUM( BoundaryNodes % z(1:n) * dLBasisdx(1:n,2) )
662
663
Nrm(1) = dydu * dzdv - dydv * dzdu
664
Nrm(2) = dxdv * dzdu - dxdu * dzdv
665
Nrm(3) = dxdu * dydv - dxdv * dydu
666
END IF
667
!-------------------------------------------------------------------------------
668
! Turn the normal to point outwards, or towards less dense material
669
!-------------------------------------------------------------------------------
670
IF ( Turned(k) ) Nrm = -Nrm
671
!-------------------------------------------------------------------------------
672
! Now then, lets move the node so that u.n will be reduced.
673
!-------------------------------------------------------------------------------
674
IF ( Boundary % Type % Dimension == 1 ) THEN
675
!-------------------------------------------------------------------------------
676
! TODO :: This won't handle the three node line
677
! 2D case, move the nodes..
678
!-------------------------------------------------------------------------------
679
R = Ux * Nrm(1) + Uy * Nrm(2)
680
IF ( Which == 2 ) THEN
681
IF ( ABS(Ux) > AEPS ) THEN
682
IF ( Turned(k) ) THEN
683
Model % Nodes % y(k) = Model % Nodes % y(k) - &
684
R / ( Ux*dLBasisdx(i,1) )
685
ELSE
686
Model % Nodes % y(k) = Model % Nodes % y(k) + &
687
R / ( Ux*dLBasisdx(i,1) )
688
END IF
689
YMoved = .TRUE.
690
END IF
691
ELSE
692
IF ( ABS(Uy) > AEPS ) THEN
693
IF ( Turned(k) ) THEN
694
Model % Nodes % x(k) = Model % Nodes % x(k) + &
695
R / ( Uy*dLBasisdx(i,1) )
696
ELSE
697
Model % Nodes % x(k) = Model % Nodes % x(k) - &
698
R / ( Uy*dLBasisdx(i,1) )
699
END IF
700
XMoved = .TRUE.
701
END IF
702
END IF
703
ELSE
704
!-------------------------------------------------------------------------------
705
! 3D case, move the nodes..
706
! TODO :: This is just guesswork, no testing done...
707
!----------------------------------------------------------------------------
708
Ux = Velocity1 % Values( Velocity1 % Perm(k) )
709
Uy = Velocity2 % Values( Velocity2 % Perm(k) )
710
Uz = Velocity3 % Values( Velocity3 % Perm(k) )
711
712
R = Ux * Nrm(1) + Uy * Nrm(2) + Uz * Nrm(3)
713
IF ( Which == 1 ) THEN
714
IF ( ABS(Uy) > AEPS .OR. ABS(Uz) > AEPS ) THEN
715
Model % Nodes % x(k) = Model % Nodes % x(k) + R / &
716
( (dzdu*dLBasisdx(i,2) - dzdv*dLBasisdx(i,1))*Uy + &
717
(dydv*dLBasisdx(i,1) - dydu*dLBasisdx(i,2))*Uz )
718
XMoved = .TRUE.
719
END IF
720
ELSE IF ( Which == 2 ) THEN
721
IF ( ABS(Ux) > AEPS .OR. ABS(Uz) > AEPS ) THEN
722
Model % Nodes % y(k) = Model % Nodes % y(k) + R / &
723
( (dzdv*dLBasisdx(i,1) - dzdu*dLBasisdx(i,2))*Ux + &
724
(dxdu*dLBasisdx(i,2) - dxdv*dLBasisdx(i,1))*Uz )
725
YMoved = .TRUE.
726
END IF
727
ELSE
728
IF ( ABS(Ux) > AEPS .OR. ABS(Uy) > AEPS ) THEN
729
Model % Nodes % z(k) = Model % Nodes % z(k) + R / &
730
( (dydu*dLBasisdx(i,2) - dydv*dLBasisdx(i,1))*Ux + &
731
(dxdv*dLBasisdx(i,1) - dxdu*dLBasisdx(i,2))*Uy )
732
ZMoved = .TRUE.
733
END IF
734
END IF
735
END IF
736
!-------------------------------------------------------------------------------
737
S = S + ( (Ux*Nrm(1)+Uy*Nrm(2)+Uz*Nrm(3))/SQRT(SUM(Nrm**2)) )**2
738
!-------------------------------------------------------------------------------
739
END IF
740
END DO
741
END DO
742
!-------------------------------------------------------------------------------
743
S = SQRT(S)
744
WRITE( Message, '(a,i4,a,e21.12)' ) 'Iter: ', ii, ' Free surface Residual: ',S
745
CALL Info( 'FreeSurface', Message, Level=4 )
746
IF ( S < FEPS ) EXIT
747
END DO
748
!-------------------------------------------------------------------------------
749
IF ( XMoved ) THEN
750
CALL PoissonSolve( Model,XCoord,YCoord,ZCoord,Model % Nodes % x,1 )
751
IF ( Relax /= 1.0d0 ) &
752
Model % Nodes % x = Relax * Model % Nodes % x + (1-Relax)*XCoord
753
END IF
754
755
IF ( YMoved ) THEN
756
CALL PoissonSolve( Model,XCoord,YCoord,ZCoord,Model % Nodes % y,2 )
757
IF ( Relax /= 1.0d0 ) &
758
Model % Nodes % y = Relax * Model % Nodes % y + (1-Relax)*YCoord
759
END IF
760
761
IF ( ZMoved ) THEN
762
CALL PoissonSolve( Model,XCoord,YCoord,ZCoord,Model % Nodes % z,3 )
763
IF ( Relax /= 1.0d0 ) &
764
Model % Nodes % z = Relax * Model % Nodes % z + (1-Relax)*ZCoord
765
END IF
766
767
DEALLOCATE( Visited,Turned,XCoord,YCoord,ZCoord,AvarageNormal )
768
769
ALLOCATE( ElementNodes % x(Model % MaxElementNodes) )
770
ALLOCATE( ElementNodes % y(Model % MaxElementNodes) )
771
ALLOCATE( ElementNodes % z(Model % MaxElementNodes) )
772
773
DO i=1,Model % NumberOfBulkElements
774
Element => Model % Elements(i)
775
n = Element % Type % NumberOfNodes
776
ElementNodes % x(1:n) = Model % Nodes % x(Element % NodeIndexes)
777
ElementNodes % y(1:n) = Model % Nodes % y(Element % NodeIndexes)
778
ElementNodes % z(1:n) = Model % Nodes % z(Element % NodeIndexes)
779
CALL StabParam( Element, ElementNodes, n, &
780
Element % StabilizationMK, Element % hK )
781
END DO
782
783
DEALLOCATE( ElementNodes % x, ElementNodes % y, ElementNodes % z)
784
!-------------------------------------------------------------------------------
785
END SUBROUTINE MoveBoundary
786
!-------------------------------------------------------------------------------
787
788
789
790
!-------------------------------------------------------------------------------
791
SUBROUTINE PoissonSolve( Model,NX,NY,NZ,Solution,Moved )
792
!-------------------------------------------------------------------------------
793
TYPE(Model_t) :: Model
794
INTEGER :: Moved
795
REAL(KIND=dp) :: NX(:),NY(:),NZ(:),Solution(:)
796
!-------------------------------------------------------------------------------
797
798
TYPE(Matrix_t), POINTER :: CMatrix
799
INTEGER, POINTER :: CPerm(:)
800
801
LOGICAL :: FirstTime = .TRUE.
802
REAL(KIND=dp), ALLOCATABLE :: ForceVector(:)
803
804
REAL(KIND=dp) :: Basis(16),dBasisdx(16,3),ddBasisddx(16,3,3)
805
REAL(KIND=dp) :: SqrtElementMetric,u,v,w,s,A
806
LOGICAL :: Stat
807
808
INTEGER :: i,j,k,n,q,p,t,dim
809
810
TYPE(Solver_t), POINTER :: Solver
811
TYPE(Nodes_t) :: Nodes
812
TYPE(Element_t), POINTER :: Element
813
814
INTEGER :: N_Integ
815
816
REAL(KIND=dp), POINTER :: U_Integ(:),V_Integ(:),W_Integ(:),S_Integ(:), &
817
LocalMatrix(:,:)
818
819
TYPE(GaussIntegrationPoints_t), TARGET :: IntegStuff
820
821
SAVE CMatrix,CPerm,FirstTime,ForceVector,Solver,Nodes,LocalMatrix
822
!-------------------------------------------------------------------------------
823
824
IF ( FirstTime ) THEN
825
FirstTime = .FALSE.
826
827
ALLOCATE( Solver )
828
Solver % Values => ListAllocate()
829
Solver % Mesh => CurrentModel % Mesh
830
831
CALL ListAddString( Solver % Values, &
832
'Linear System Iterative Method', 'CGS' )
833
CALL ListAddInteger( Solver % Values, &
834
'Linear System Max Iterations', 500 )
835
CALL ListAddConstReal( Solver % Values, &
836
'Linear System Convergence Tolerance', 1.0D-9 )
837
CALL ListAddString( Solver % Values, &
838
'Linear System Preconditioning', 'ILU0' )
839
CALL ListAddInteger( Solver % Values, &
840
'Linear System Residual Output', 1 )
841
842
ALLOCATE( ForceVector( Model % NumberOfNodes ), &
843
CPerm( Model % NumberOfNodes) )
844
845
CMatrix => CreateMatrix( CurrentModel,Solver,Solver % Mesh,CPerm,1,MATRIX_CRS,.FALSE. )
846
847
ALLOCATE( LocalMatrix( Model % MaxElementNodes,Model % MaxElementNodes ) )
848
ALLOCATE( Nodes % x(Model % MaxElementNodes) )
849
ALLOCATE( Nodes % y(Model % MaxElementNodes) )
850
ALLOCATE( Nodes % z(Model % MaxElementNodes) )
851
852
Solver % TimeOrder = 0
853
END IF
854
855
!------------------------------------------------------------------------------
856
857
CALL CRS_ZeroMatrix( CMatrix )
858
ForceVector = 0.0D0
859
860
!------------------------------------------------------------------------------
861
DO i=1,Model % NumberOfBulkElements
862
!------------------------------------------------------------------------------
863
Element => Model % Elements(i)
864
865
dim = Element % Type % Dimension
866
n = Element % Type % NumberOfNodes
867
868
Nodes % x(1:n) = nx( Element % NodeIndexes )
869
Nodes % y(1:n) = ny( Element % NodeIndexes )
870
Nodes % z(1:n) = nz( Element % NodeIndexes )
871
872
IntegStuff = GaussPoints( Element )
873
U_Integ => IntegStuff % u
874
V_Integ => IntegStuff % v
875
W_Integ => IntegStuff % w
876
S_Integ => IntegStuff % s
877
N_Integ = IntegStuff % n
878
!------------------------------------------------------------------------------
879
LocalMatrix = 0.0D0
880
DO t=1,N_Integ
881
u = U_Integ(t)
882
v = V_Integ(t)
883
w = W_Integ(t)
884
!------------------------------------------------------------------------------
885
! Basis function values & derivatives at the integration point
886
!------------------------------------------------------------------------------
887
stat = ElementInfo( Element,Nodes,u,v,w,SqrtElementMetric, &
888
Basis,dBasisdx )
889
890
s = SqrtElementMetric * S_Integ(t)
891
DO p=1,N
892
DO q=1,N
893
A = dBasisdx(p,Moved) * dBasisdx(q,Moved)
894
LocalMatrix(p,q) = LocalMatrix(p,q) + s*A
895
END DO
896
END DO
897
END DO
898
899
CALL CRS_GlueLocalMatrix( CMatrix,n,1,Element % NodeIndexes,LocalMatrix )
900
END DO
901
902
!-------------------------------------------------------------------------------
903
DO t = Model % NumberOfBulkElements + 1, Model % NumberOfBulkElements + &
904
Model % NumberOfBoundaryElements
905
!-------------------------------------------------------------------------------
906
Element => Model % Elements(t)
907
n = Element % Type % NumberOfNodes
908
909
DO i=1,Model % NumberOfBCs
910
IF ( Element % BoundaryInfo % Constraint == Model % BCs(i) % Tag ) THEN
911
IF ( .NOT.ListGetLogical(Model % BCs(i) % Values,'Free Moving',stat) ) THEN
912
DO j=1,n
913
k = Element % NodeIndexes(j)
914
915
ForceVector(k) = Solution(k)
916
CALL CRS_ZeroRow( CMatrix,k )
917
CALL CRS_SetMatrixElement( CMatrix,k,k,1.0D0 )
918
END DO
919
END IF
920
END IF
921
END DO
922
!-------------------------------------------------------------------------------
923
END DO
924
!-------------------------------------------------------------------------------
925
926
CALL IterSolver( CMatrix,Solution,ForceVector,Solver )
927
928
!-------------------------------------------------------------------------------
929
END SUBROUTINE PoissonSolve
930
!-------------------------------------------------------------------------------
931
932
END MODULE FreeSurface
933
934
!> \}
935
936