Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/DefUtils.F90
5213 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: Juha Ruokolainen
27
! * Email: [email protected]
28
! * Web: http://www.csc.fi/elmer
29
! * Address: CSC - IT Center for Science Ltd.
30
! * Keilaranta 14
31
! * 02101 Espoo, Finland
32
! *
33
! * Original Date: 12 Jun 2003
34
! *
35
! ******************************************************************************/
36
37
!> \defgroup ElmerLib Elmer library
38
!> \{
39
!> \defgroup DefUtils Default API
40
!> \{
41
42
!--------------------------------------------------------------------------------
43
!> Module containing utility subroutines with default values for various
44
!> system subroutine arguments. For user defined solvers and subroutines
45
!> this module should provide all the needed functionality for typical finite
46
!> element procedures.
47
!--------------------------------------------------------------------------------
48
MODULE DefUtils
49
50
#include "../config.h"
51
52
USE MeshGenerate
53
USE MeshUtils, ONLY : AllocateElement, SaveParallelInfo
54
USE ElementUtils
55
USE SolverUtils
56
USE CutFEMUtils
57
58
IMPLICIT NONE
59
60
INTERFACE DefaultUpdateEquations
61
MODULE PROCEDURE DefaultUpdateEquationsR, DefaultUpdateEquationsC, &
62
DefaultUpdateEquationsDiagC
63
END INTERFACE
64
65
INTERFACE DefaultUpdatePrec
66
MODULE PROCEDURE DefaultUpdatePrecR, DefaultUpdatePrecC
67
END INTERFACE
68
69
INTERFACE DefaultUpdateMass
70
MODULE PROCEDURE DefaultUpdateMassR, DefaultUpdateMassC
71
END INTERFACE
72
73
INTERFACE DefaultUpdateBulk
74
MODULE PROCEDURE DefaultUpdateBulkR, DefaultUpdateBulkC
75
END INTERFACE
76
77
INTERFACE DefaultUpdateDamp
78
MODULE PROCEDURE DefaultUpdateDampR, DefaultUpdateDampC
79
END INTERFACE
80
81
INTERFACE DefaultUpdateForce
82
MODULE PROCEDURE DefaultUpdateForceR, DefaultUpdateForceC
83
END INTERFACE
84
85
INTERFACE DefaultUpdateTimeForce
86
MODULE PROCEDURE DefaultUpdateTimeForceR, DefaultUpdateTimeForceC
87
END INTERFACE
88
89
INTERFACE Default1stOrderTime
90
MODULE PROCEDURE Default1stOrderTimeR, Default1stOrderTimeC
91
END INTERFACE
92
93
INTERFACE Default2ndOrderTime
94
MODULE PROCEDURE Default2ndOrderTimeR, Default2ndOrderTimeC
95
END INTERFACE
96
97
INTERFACE GetLocalSolution
98
MODULE PROCEDURE GetScalarLocalSolution, GetVectorLocalSolution
99
END INTERFACE
100
101
INTERFACE GetLocalEigenmode
102
MODULE PROCEDURE GetScalarLocalEigenmode, GetVectorLocalEigenmode
103
END INTERFACE
104
105
INTERFACE GetLocalConsmode
106
MODULE PROCEDURE GetScalarLocalConsmode, GetVectorLocalConsmode
107
END INTERFACE
108
109
INTEGER, ALLOCATABLE, TARGET, PRIVATE :: IndexStore(:), VecIndexStore(:)
110
REAL(KIND=dp), ALLOCATABLE, TARGET, PRIVATE :: ValueStore(:)
111
!$OMP THREADPRIVATE(IndexStore, VecIndexStore, ValueStore)
112
113
TYPE(Element_t), POINTER :: CurrentElementThread => NULL()
114
!$OMP THREADPRIVATE(CurrentElementThread)
115
116
! TODO: Get actual values for these from mesh
117
INTEGER, PARAMETER, PRIVATE :: ISTORE_MAX_SIZE = 1024
118
INTEGER, PARAMETER, PRIVATE :: VSTORE_MAX_SIZE = 1024
119
PRIVATE :: GetIndexStore, GetPermIndexStore, GetValueStore
120
CONTAINS
121
122
123
FUNCTION GetVersion() RESULT(ch)
124
CHARACTER(LEN=:), ALLOCATABLE :: ch
125
ch = ELMER_FEM_VERSION
126
END FUNCTION GetVersion
127
128
FUNCTION GetSifName(Found) RESULT(ch)
129
CHARACTER(LEN=:), ALLOCATABLE :: ch
130
LOGICAL, OPTIONAL :: Found
131
ch = GetString(CurrentModel % Simulation,'Solver Input File',Found)
132
END FUNCTION GetSifName
133
134
FUNCTION GetRevision(Found) RESULT(ch)
135
CHARACTER(LEN=:), ALLOCATABLE :: ch
136
LOGICAL, OPTIONAL :: Found
137
#ifdef ELMER_FEM_REVISION
138
ch = ELMER_FEM_REVISION
139
IF(PRESENT(Found)) Found = .TRUE.
140
#else
141
ch = "unknown"
142
IF(PRESENT(Found)) Found = .FALSE.
143
#endif
144
END FUNCTION GetRevision
145
146
FUNCTION GetBranch(Found) RESULT(ch)
147
CHARACTER(LEN=:), ALLOCATABLE :: ch
148
LOGICAL, OPTIONAL :: Found
149
#ifdef ELMER_FEM_BRANCH
150
ch = ELMER_FEM_BRANCH
151
IF(PRESENT(Found)) Found = .TRUE.
152
#else
153
ch = "unknown"
154
IF(PRESENT(Found)) Found = .FALSE.
155
#endif
156
END FUNCTION GetBranch
157
158
FUNCTION GetCompilationDate(Found) RESULT(ch)
159
CHARACTER(LEN=:), ALLOCATABLE :: ch
160
LOGICAL, OPTIONAL :: Found
161
#ifdef ELMER_FEM_COMPILATIONDATE
162
ch = ELMER_FEM_COMPILATIONDATE
163
IF(PRESENT(Found)) Found = .TRUE.
164
#else
165
ch = "unknown"
166
IF(PRESENT(Found)) Found = .FALSE.
167
#endif
168
END FUNCTION GetCompilationDate
169
170
FUNCTION GetIndexStore() RESULT(ind)
171
IMPLICIT NONE
172
INTEGER, POINTER CONTIG :: ind(:)
173
INTEGER :: istat
174
175
IF ( .NOT. ALLOCATED(IndexStore) ) THEN
176
ALLOCATE( IndexStore(ISTORE_MAX_SIZE), STAT=istat )
177
IndexStore = 0
178
IF ( Istat /= 0 ) CALL Fatal( 'GetIndexStore', &
179
'Memory allocation error.' )
180
END IF
181
ind => IndexStore
182
END FUNCTION GetIndexStore
183
184
FUNCTION GetPermIndexStore() RESULT(ind)
185
IMPLICIT NONE
186
INTEGER, POINTER CONTIG :: ind(:)
187
INTEGER :: istat
188
189
IF ( .NOT. ALLOCATED(VecIndexStore) ) THEN
190
ALLOCATE( VecIndexStore(ISTORE_MAX_SIZE), STAT=istat )
191
VecIndexStore = 0
192
IF ( istat /= 0 ) CALL Fatal( 'GetPermIndexStore', &
193
'Memory allocation error.' )
194
END IF
195
ind => VecIndexStore
196
END FUNCTION GetPermIndexStore
197
198
FUNCTION GetValueStore(n) RESULT(val)
199
IMPLICIT NONE
200
REAL(KIND=dp), POINTER CONTIG :: val(:)
201
INTEGER :: n, istat
202
203
IF ( .NOT.ALLOCATED(ValueStore) ) THEN
204
ALLOCATE( ValueStore(VSTORE_MAX_SIZE), STAT=istat )
205
ValueStore = REAL(0, dp)
206
IF ( Istat /= 0 ) CALL Fatal( 'GetValueStore', &
207
'Memory allocation error.' )
208
END IF
209
IF (n > VSTORE_MAX_SIZE) THEN
210
CALL Fatal( 'GetValueStore', 'Not enough memory allocated for store.' )
211
END IF
212
val => ValueStore(1:n)
213
END FUNCTION GetValueStore
214
215
!> Returns handle to the active solver
216
FUNCTION GetSolver() RESULT( Solver )
217
TYPE(Solver_t), POINTER :: Solver
218
Solver => CurrentModel % Solver
219
END FUNCTION GetSolver
220
221
!> Returns handle to the active matrix
222
FUNCTION GetMatrix( USolver ) RESULT( Matrix )
223
TYPE(Matrix_t), POINTER :: Matrix
224
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
225
226
IF ( PRESENT( USolver ) ) THEN
227
Matrix => USolver % Matrix
228
ELSE
229
Matrix => CurrentModel % Solver % Matrix
230
END IF
231
END FUNCTION GetMatrix
232
233
!> Returns handle to the active mesh
234
FUNCTION GetMesh( USolver ) RESULT( Mesh )
235
TYPE(Mesh_t), POINTER :: Mesh
236
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
237
238
IF ( PRESENT( USolver ) ) THEN
239
Mesh => USolver % Mesh
240
ELSE
241
Mesh => CurrentModel % Solver % Mesh
242
END IF
243
END FUNCTION GetMesh
244
245
!> Returns handle to the active element
246
FUNCTION GetCurrentElement(Element) RESULT(Ret_Element)
247
IMPLICIT NONE
248
TYPE(Element_t), OPTIONAL, TARGET :: Element
249
TYPE(Element_t), POINTER :: Ret_Element
250
251
IF (PRESENT(Element)) THEN
252
Ret_Element=>Element
253
ELSE
254
#ifdef _OPENMP
255
IF (omp_in_parallel()) THEN
256
Ret_Element=>CurrentElementThread
257
ELSE
258
Ret_Element=>CurrentModel % CurrentElement
259
END IF
260
#else
261
Ret_Element => CurrentModel % CurrentElement
262
#endif
263
END IF
264
END FUNCTION GetCurrentElement
265
266
!> Sets handle to the active element of the current thread.
267
!> Old handle is given as a return value as what would be returned
268
!> by a call to GetCurrentElement
269
FUNCTION SetCurrentElement(Element) RESULT(OldElement)
270
IMPLICIT NONE
271
TYPE(Element_t), TARGET :: Element
272
TYPE(Element_t), POINTER :: OldElement
273
274
#ifdef _OPENMP
275
IF (omp_in_parallel()) THEN
276
OldElement => CurrentElementThread
277
CurrentElementThread => Element
278
ELSE
279
OldElement => CurrentModel % CurrentElement
280
CurrentModel % CurrentElement => Element
281
END IF
282
#else
283
OldElement => CurrentModel % CurrentElement
284
CurrentModel % CurrentElement => Element
285
#endif
286
END FUNCTION SetCurrentElement
287
288
!> Returns handle to the index of the current element
289
FUNCTION GetElementIndex(Element) RESULT(Indx)
290
TYPE(Element_t), OPTIONAL :: Element
291
INTEGER :: Indx
292
TYPE(Element_t), POINTER :: CurrElement
293
294
CurrElement => GetCurrentElement(Element)
295
Indx = CurrElement % ElementIndex
296
END FUNCTION GetElementIndex
297
298
SUBROUTINE GetElementNodeIndex(i, Element, n, FOUND)
299
IMPLICIT None
300
301
! variables in function header
302
INTEGER :: i, n
303
TYPE(Element_t), POINTER :: Element
304
Logical :: FOUND
305
306
DO i=1, SIZE(Element%NodeIndexes)
307
IF (n == Element%NodeIndexes(i)) THEN
308
FOUND=.TRUE.
309
EXIT
310
END IF
311
END DO
312
END SUBROUTINE GetElementNodeIndex
313
314
FUNCTION GetIPIndex( LocalIp, USolver, Element, IpVar ) RESULT ( GlobalIp )
315
INTEGER :: LocalIp, GlobalIp
316
317
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
318
TYPE(Element_t), OPTIONAL :: Element
319
TYPE(Variable_t), POINTER, OPTIONAL :: IpVar
320
321
TYPE(Solver_t), POINTER :: Solver
322
TYPE(Element_t), POINTER :: CurrElement
323
INTEGER :: n, m
324
INTEGER, POINTER :: IpPerm(:)
325
326
IF ( PRESENT( USolver ) ) THEN
327
Solver => USolver
328
ELSE
329
Solver => CurrentModel % Solver
330
END IF
331
332
CurrElement => GetCurrentElement(Element)
333
n = CurrElement % ElementIndex
334
GlobalIp = 0
335
336
IF( PRESENT( IpVar ) ) THEN
337
IF( IpVar % TYPE /= Variable_on_gauss_points ) THEN
338
CALL Fatal('GetIpIndex','Variable is not of type gauss points!')
339
END IF
340
341
IpPerm => IpVar % Perm
342
m = IpPerm(n+1) - IpPerm(n)
343
344
! This is a sign that the variable is not active at the element
345
IF( m == 0 ) RETURN
346
ELSE
347
IF( .NOT. ASSOCIATED( Solver % IpTable ) ) THEN
348
CALL Fatal('GetIpIndex','Cannot access index of gaussian point!')
349
END IF
350
351
IpPerm => Solver % IpTable % IpOffset
352
m = IpPerm(n+1) - IpPerm(n)
353
END IF
354
355
! There are not sufficient number of gauss points in the permutation table to have a
356
! local index this big.
357
IF( m < LocalIp ) THEN
358
CALL Warn('GetIpIndex','Inconsistent number of IP points!')
359
RETURN
360
END IF
361
362
GlobalIp = IpPerm(n) + LocalIp
363
364
END FUNCTION GetIPIndex
365
366
367
368
FUNCTION GetIPCount( USolver, IpVar ) RESULT ( IpCount )
369
INTEGER :: IpCount
370
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
371
TYPE(Variable_t), OPTIONAL, POINTER :: IpVar
372
373
TYPE(Solver_t), POINTER :: Solver
374
INTEGER, POINTER :: IpPerm
375
376
IF ( PRESENT( USolver ) ) THEN
377
Solver => USolver
378
ELSE
379
Solver => CurrentModel % Solver
380
END IF
381
382
IF( PRESENT( IpVar ) ) THEN
383
IF( IpVar % TYPE /= Variable_on_gauss_points ) THEN
384
CALL Fatal('GetIpCount','Variable is not of type gauss points!')
385
END IF
386
IpCount = SIZE( IpVar % Values ) / IpVar % Dofs
387
ELSE
388
IF( .NOT. ASSOCIATED( Solver % IpTable ) ) THEN
389
CALL Fatal('GetIpCount','Gauss point table not initialized')
390
END IF
391
IpCount = Solver % IpTable % IpCount
392
END IF
393
394
END FUNCTION GetIPCount
395
396
397
!> Returns the number of active elements for the current solver
398
FUNCTION GetNOFActive( USolver ) RESULT(n)
399
INTEGER :: n
400
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
401
TYPE(Solver_t), POINTER :: Solver
402
403
IF ( PRESENT( USolver ) ) THEN
404
Solver => USolver
405
ELSE
406
Solver => CurrentModel % Solver
407
END IF
408
409
IF( ASSOCIATED( Solver % ColourIndexList ) ) THEN
410
Solver % CurrentColour = Solver % CurrentColour + 1
411
n = Solver % ColourIndexList % ptr(Solver % CurrentColour+1) &
412
- Solver % ColourIndexList % ptr(Solver % CurrentColour)
413
CALL Info('GetNOFActive','Number of active elements: '&
414
//I2S(n)//' in colour '//I2S(Solver % CurrentColour),Level=20)
415
ELSE
416
n = Solver % NumberOfActiveElements
417
CALL Info('GetNOFActive','Number of active elements: '&
418
//I2S(n),Level=20)
419
END IF
420
421
END FUNCTION GetNOFActive
422
423
!> Return number of boundary elements of the current boundary colour
424
!> and increments the colour counter
425
FUNCTION GetNOFBoundaryActive( USolver ) RESULT(n)
426
INTEGER :: n
427
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
428
TYPE(Solver_t), POINTER :: Solver
429
430
IF ( PRESENT( USolver ) ) THEN
431
Solver => USolver
432
ELSE
433
Solver => CurrentModel % Solver
434
END IF
435
436
IF( ASSOCIATED( Solver % BoundaryColourIndexList ) ) THEN
437
Solver % CurrentBoundaryColour = Solver % CurrentBoundaryColour + 1
438
n = Solver % BoundaryColourIndexList % ptr(Solver % CurrentBoundaryColour+1) &
439
- Solver % BoundaryColourIndexList % ptr(Solver % CurrentBoundaryColour)
440
CALL Info('GetNOFBoundaryActive','Number of boundary elements: '&
441
//I2S(n)//' in colour '//I2S(Solver % CurrentBoundaryColour),Level=20)
442
ELSE
443
n = Solver % Mesh % NumberOfBoundaryElements
444
CALL Info('GetNOFBoundaryActive','Number of active elements: '&
445
//I2S(n),Level=20)
446
END IF
447
448
END FUNCTION GetNOFBoundaryActive
449
450
!> Returns the current time
451
FUNCTION GetTime() RESULT(st)
452
REAL(KIND=dp) :: st
453
TYPE(Variable_t), POINTER :: v
454
455
v => CurrentModel % Solver % Mesh % Variables
456
v => VariableGet( v, 'time' )
457
st = v % Values(1)
458
END FUNCTION GetTime
459
460
!> Returns the current periodic time
461
FUNCTION GetPeriodicTime() RESULT(st)
462
REAL(KIND=dp) :: st
463
TYPE(Variable_t), POINTER :: v
464
465
v => CurrentModel % Solver % Mesh % Variables
466
v => VariableGet( v, 'periodic time' )
467
st = v % Values(1)
468
END FUNCTION GetPeriodicTime
469
470
!> Returns the current timestep
471
FUNCTION GetTimeStep() RESULT(st)
472
INTEGER :: st
473
TYPE(Variable_t), POINTER :: v
474
475
v => CurrentModel % Solver % Mesh % Variables
476
v => VariableGet( v, 'timestep' )
477
st = NINT(v % Values(1))
478
END FUNCTION GetTimestep
479
480
!> Returns the current timestep interval
481
FUNCTION GetTimeStepInterval() RESULT(st)
482
INTEGER :: st
483
TYPE(Variable_t), POINTER :: v
484
485
v => CurrentModel % Solver % Mesh % Variables
486
v => VariableGet( v, 'timestep interval')
487
st = NINT(v % Values(1))
488
END FUNCTION GetTimestepInterval
489
490
!> Returns the current timestep size
491
FUNCTION GetTimestepSize() RESULT(st)
492
REAL(KIND=dp) :: st
493
TYPE(Variable_t), POINTER :: v
494
495
v => CurrentModel % Solver % Mesh % Variables
496
v => VariableGet( v, 'timestep size')
497
st = v % Values(1)
498
END FUNCTION GetTimestepSize
499
500
!> Returns the angular frequency
501
FUNCTION GetAngularFrequency(ValueList,Found, UElement) RESULT(w)
502
REAL(KIND=dp) :: w
503
TYPE(ValueList_t), POINTER, OPTIONAL :: ValueList
504
LOGICAL, OPTIONAL :: Found
505
TYPE(Element_t), OPTIONAL :: UElement
506
507
w = ListGetAngularFrequency( ValueList, Found, UElement )
508
END FUNCTION GetAngularFrequency
509
510
!> Returns the current coupled system iteration loop count
511
FUNCTION GetCoupledIter() RESULT(st)
512
INTEGER :: st
513
TYPE(Variable_t), POINTER :: v
514
515
v => CurrentModel % Solver % Mesh % Variables
516
v => VariableGet( v, 'coupled iter')
517
st = NINT(v % Values(1))
518
END FUNCTION GetCoupledIter
519
520
!> Returns the current nonlinear system iteration loop count
521
FUNCTION GetNonlinIter() RESULT(st)
522
INTEGER :: st
523
TYPE(Variable_t), POINTER :: v
524
525
v => CurrentModel % Solver % Mesh % Variables
526
v => VariableGet( v, 'nonlin iter')
527
st = NINT(v % Values(1))
528
END FUNCTION GetNonlinIter
529
530
!> Returns the number of boundary elements
531
FUNCTION GetNOFBoundaryElements( UMesh ) RESULT(n)
532
INTEGER :: n
533
TYPE(Mesh_t), OPTIONAL :: UMesh
534
535
IF ( PRESENT( UMesh ) ) THEN
536
n = UMesh % NumberOfBoundaryElements
537
ELSE
538
n = CurrentModel % Mesh % NumberOfBoundaryElements
539
END IF
540
END FUNCTION GetNOFBoundaryElements
541
542
!> Returns a scalar field in the nodes of the element
543
SUBROUTINE GetScalarLocalSolution( x,name,UElement,USolver,tStep, UVariable, Found)
544
REAL(KIND=dp) :: x(:)
545
CHARACTER(LEN=*), OPTIONAL :: name
546
TYPE(Solver_t) , OPTIONAL, TARGET :: USolver
547
TYPE(Element_t), OPTIONAL, TARGET :: UElement
548
TYPE(Variable_t), OPTIONAL, TARGET :: UVariable
549
INTEGER, OPTIONAL :: tStep
550
LOGICAL, OPTIONAL :: Found
551
552
REAL(KIND=dp), POINTER :: Values(:)
553
TYPE(Variable_t), POINTER :: Variable
554
TYPE(Solver_t) , POINTER :: Solver
555
TYPE(Element_t), POINTER :: Element, Parent
556
557
INTEGER :: i, j, k, n, lr
558
INTEGER, POINTER :: Indexes(:)
559
LOGICAL :: Found0
560
561
IF ( PRESENT(USolver) ) THEN
562
Solver => USolver
563
ELSE
564
Solver => CurrentModel % Solver
565
END IF
566
567
x = 0.0_dp
568
IF(PRESENT(Found)) Found = .FALSE.
569
570
IF(PRESENT(UVariable)) THEN
571
Variable => UVariable
572
ELSE IF( PRESENT(name) ) THEN
573
Variable => VariableGet( Solver % Mesh % Variables, name )
574
ELSE
575
Variable => Solver % Variable
576
END IF
577
IF ( .NOT. ASSOCIATED( Variable ) ) RETURN
578
579
Values => Variable % Values
580
IF ( PRESENT(tStep) ) THEN
581
IF ( tStep<0 ) THEN
582
IF ( ASSOCIATED(Variable % PrevValues) ) THEN
583
IF( -tStep<=SIZE(Variable % PrevValues,2)) &
584
Values => Variable % PrevValues(:,-tStep)
585
END IF
586
END IF
587
END IF
588
589
Element => GetCurrentElement(UElement)
590
Found0 = .FALSE.
591
592
! Some variables do not really follow the numbering
593
! nodes + faces + edges etc. of the standard solver.
594
! For example, if we want to request DG values from a variable
595
! that is not called by a DG solver we have to treat the DG variable
596
! separately. As is the case for Gauss variables.
597
! If variable is defined on gauss points return that instead
598
!-------------------------------------------------------------
599
IF( Variable % TYPE == Variable_on_gauss_points ) THEN
600
j = Element % ElementIndex
601
n = Variable % Perm(j+1) - Variable % Perm(j)
602
DO i=1,n
603
x(i) = Values(Variable % Perm(j) + i)
604
END DO
605
IF(PRESENT(Found)) Found = (n>1)
606
RETURN
607
ELSE IF( Variable % TYPE == Variable_on_nodes_on_elements ) THEN
608
n = Element % TYPE % NumberOfNodes
609
Indexes => Element % DGIndexes
610
IF(ASSOCIATED( Indexes ) ) THEN
611
DO i=1,n
612
j = Variable % Perm(Indexes(i))
613
IF(j>0) THEN
614
Found0 = .TRUE.
615
x(i) = Values(j)
616
END IF
617
END DO
618
ELSE IF ( ASSOCIATED( Element % BoundaryInfo ) ) THEN
619
DO lr=1,2
620
IF(lr==1) THEN
621
Parent => Element % BoundaryInfo % Left
622
ELSE
623
Parent => Element % BoundaryInfo % Right
624
END IF
625
IF(.NOT. ASSOCIATED( Parent ) ) CYCLE
626
IF( ANY( Variable % Perm( Parent % DGIndexes ) == 0) ) CYCLE
627
DO i=1,n
628
DO j=1,Parent % TYPE % NumberOfNodes
629
IF( Element % NodeIndexes(i) == Parent % NodeIndexes(j) ) THEN
630
k = Variable % Perm( Parent % DGIndexes(j) )
631
IF(k>0) THEN
632
Found0 = .TRUE.
633
x(i) = Values(k)
634
END IF
635
EXIT
636
END IF
637
END DO
638
END DO
639
EXIT
640
END DO
641
END IF
642
IF(PRESENT(Found)) Found = Found0
643
RETURN
644
ELSE IF( ASSOCIATED(Solver % CutInterp) ) THEN
645
! This is a special case associated to CutFEM. Only nodal fields can be mapped this way!
646
647
n = Element % TYPE % NumberOfNodes
648
Indexes => Element % NodeIndexes
649
650
BLOCK
651
INTEGER :: nn,j1,j2
652
REAL(KIND=dp) :: r
653
nn = SIZE(Variable % Perm)
654
655
DO i=1,n
656
j = Indexes(i)
657
IF ( j>0 .AND. j<=nn ) THEN
658
! This is an original node.
659
j = Variable % Perm(j)
660
IF ( j>0 ) THEN
661
Found0 = .TRUE.
662
x(i) = Values(j)
663
END IF
664
ELSE
665
! This is an additional node of the fictitious domain method.
666
! When we know where the isoline cuts the edge we can use linear interpolation
667
! on the edge to get the value at the intersetion on-the-fly.
668
r = Solver % CutInterp(j-nn)
669
j1 = Variable % Perm(Solver % Mesh % Edges(j-nn) % NodeIndexes(1))
670
j2 = Variable % Perm(Solver % Mesh % Edges(j-nn) % NodeIndexes(2))
671
IF(j1 > 0 .AND. j2 > 0) THEN
672
Found0 = .TRUE.
673
x(i) = r*Variable % Values(j1) + (1-r)*Variable % Values(j2)
674
!PRINT *,'interp:',j,j1,j2,r,x(i)
675
END IF
676
END IF
677
END DO
678
END BLOCK
679
RETURN
680
END IF
681
682
Indexes => GetIndexStore()
683
IF ( ASSOCIATED(Variable % Solver) ) THEN
684
n = GetElementDOFs( Indexes, Element, Variable % Solver )
685
ELSE
686
n = GetElementDOFs( Indexes, Element, Solver )
687
END IF
688
n = MIN( n, SIZE(x) )
689
690
691
IF ( ASSOCIATED( Variable % Perm ) ) THEN
692
IF( Variable % PeriodicFlipActive ) THEN
693
DO i=1,n
694
j = Indexes(i)
695
IF ( j>0 .AND. j<=SIZE(Variable % Perm) ) THEN
696
k = Variable % Perm(j)
697
IF ( k>0 ) THEN
698
Found0 = .TRUE.
699
x(i) = Values(k)
700
IF( CurrentModel % Mesh % PeriodicFlip(j) ) x(i) = -x(i)
701
END IF
702
END IF
703
END DO
704
ELSE
705
DO i=1,n
706
j = Indexes(i)
707
IF ( j>0 .AND. j<=SIZE(Variable % Perm) ) THEN
708
j = Variable % Perm(j)
709
IF ( j>0 ) THEN
710
Found0 = .TRUE.
711
x(i) = Values(j)
712
END IF
713
END IF
714
END DO
715
END IF
716
ELSE
717
DO i=1,n
718
j = Indexes(i)
719
IF ( j>0 .AND. j<=SIZE(Variable % Values) ) THEN
720
Found0 = .TRUE.
721
x(i) = Values(Indexes(i))
722
END IF
723
END DO
724
END IF
725
726
IF(PRESENT(Found)) Found = Found0
727
728
END SUBROUTINE GetScalarLocalSolution
729
730
731
732
!> Returns a vector field in the nodes of the element
733
SUBROUTINE GetVectorLocalSolution( x,name,UElement,USolver,tStep, UVariable, Found)
734
REAL(KIND=dp) :: x(:,:)
735
CHARACTER(LEN=*), OPTIONAL :: name
736
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
737
TYPE(Element_t), OPTIONAL, TARGET :: UElement
738
TYPE(Variable_t), OPTIONAL, TARGET :: UVariable
739
INTEGER, OPTIONAL :: tStep
740
LOGICAL, OPTIONAL :: Found
741
742
TYPE(Variable_t), POINTER :: Variable
743
TYPE(Solver_t) , POINTER :: Solver
744
TYPE(Element_t), POINTER :: Element, Parent
745
746
INTEGER :: i, j, k, l, lr, n
747
INTEGER, POINTER :: Indexes(:)
748
REAL(KIND=dp), POINTER :: Values(:)
749
LOGICAL :: Found0
750
751
Solver => CurrentModel % Solver
752
IF ( PRESENT(USolver) ) Solver => USolver
753
754
x = 0.0d0
755
IF(PRESENT(Found)) Found = .FALSE.
756
757
IF(.NOT. PRESENT(UVariable)) THEN
758
Variable => Solver % Variable
759
ELSE
760
Variable => UVariable
761
END IF
762
763
IF ( PRESENT(name) ) THEN
764
Variable => VariableGet( Solver % Mesh % Variables, name )
765
END IF
766
IF ( .NOT. ASSOCIATED( Variable ) ) RETURN
767
768
Values => Variable % Values
769
IF ( PRESENT(tStep) ) THEN
770
IF ( tStep<0 ) THEN
771
IF ( ASSOCIATED(Variable % PrevValues) ) THEN
772
IF ( -tStep<=SIZE(Variable % PrevValues,2)) &
773
Values => Variable % PrevValues(:,-tStep)
774
END IF
775
END IF
776
END IF
777
778
Element => GetCurrentElement(UElement)
779
Found0 = .FALSE.
780
781
782
! If variable is defined on gauss points return that instead
783
IF( Variable % TYPE == Variable_on_gauss_points ) THEN
784
ASSOCIATE(dofs => variable % dofs)
785
j = Element % ElementIndex
786
n = Variable % Perm(j+1) - Variable % Perm(j)
787
IF (SIZE(x,1) < dofs .OR. SIZE(x,2) < n) THEN
788
WRITE (message,*) 'Attempting to get IP solution to a too small array of size', &
789
SHAPE(x), '. Required size:', dofs, n
790
CALL Fatal('GetVectorLocalSolution', message)
791
END IF
792
DO i=1,n
793
ASSOCIATE(p => variable % perm(j) + i)
794
DO k=1,dofs
795
x(k, i) = Values((p-1)*dofs + k)
796
END DO
797
END ASSOCIATE
798
END DO
799
IF(PRESENT(Found)) Found = (n>1)
800
RETURN
801
END ASSOCIATE
802
ELSE IF( Variable % TYPE == Variable_on_nodes_on_elements ) THEN
803
n = Element % TYPE % NumberOfNodes
804
Indexes => Element % DGIndexes
805
IF(ASSOCIATED( Indexes ) ) THEN
806
ASSOCIATE(dofs => variable % dofs)
807
DO i=1,n
808
j = variable % perm(indexes(i))
809
IF( j==0 ) CYCLE
810
Found0 = .TRUE.
811
DO k=1,dofs
812
x(k,i) = Values((j-1)*dofs + k)
813
END DO
814
END DO
815
END ASSOCIATE
816
IF(PRESENT(Found)) Found = Found0
817
RETURN
818
ELSE IF ( ASSOCIATED( Element % BoundaryInfo ) ) THEN
819
DO lr=1,2
820
IF(lr==1) THEN
821
Parent => Element % BoundaryInfo % Left
822
ELSE
823
Parent => Element % BoundaryInfo % Right
824
END IF
825
IF(.NOT. ASSOCIATED( Parent ) ) CYCLE
826
IF( ANY( Variable % Perm( Parent % DGIndexes ) == 0) ) CYCLE
827
828
ASSOCIATE(dofs => variable % dofs)
829
DO i=1,n
830
DO j=1,Parent % TYPE % NumberOfNodes
831
IF( Element % NodeIndexes(i) == Parent % NodeIndexes(j) ) THEN
832
l = Variable % Perm( Parent % DGIndexes(j) )
833
IF(l>0) THEN
834
Found0 = .TRUE.
835
DO k=1,dofs
836
x(k,i) = Values((l-1)*dofs + k )
837
END DO
838
END IF
839
EXIT
840
END IF
841
END DO
842
END DO
843
END ASSOCIATE
844
EXIT
845
END DO
846
END IF
847
IF(PRESENT(Found)) Found = Found0
848
RETURN
849
ELSE IF( ASSOCIATED(Solver % CutInterp) ) THEN
850
CALL Fatal('GetVectorLocalSolution','Not associated for CutFEM yet!')
851
END IF
852
853
854
Indexes => GetIndexStore()
855
IF ( ASSOCIATED(Variable % Solver ) ) THEN
856
n = GetElementDOFs( Indexes, Element, Variable % Solver )
857
ELSE
858
n = GetElementDOFs( Indexes, Element, Solver )
859
END IF
860
n = MIN( n, SIZE(x,2) )
861
862
DO i=1,Variable % DOFs
863
IF ( ASSOCIATED( Variable % Perm ) ) THEN
864
IF( Variable % PeriodicFlipActive ) THEN
865
DO j=1,n
866
k = Indexes(j)
867
IF ( k>0 .AND. k<=SIZE(Variable % Perm) ) THEN
868
l = Variable % Perm(k)
869
IF( l>0 ) THEN
870
Found0 = .TRUE.
871
x(i,j) = Values(Variable % DOFs*(l-1)+i)
872
IF( CurrentModel % Mesh % PeriodicFlip(k) ) x(i,j) = -x(i,j)
873
END IF
874
END IF
875
END DO
876
ELSE
877
DO j=1,n
878
k = Indexes(j)
879
IF ( k>0 .AND. k<=SIZE(Variable % Perm) ) THEN
880
l = Variable % Perm(k)
881
IF (l>0) THEN
882
Found0 = .TRUE.
883
x(i,j) = Values(Variable % DOFs*(l-1)+i)
884
END IF
885
END IF
886
END DO
887
END IF
888
ELSE
889
DO j=1,n
890
IF ( Variable % DOFs*(Indexes(j)-1)+i <= &
891
SIZE( Variable % Values ) ) THEN
892
Found0 = .TRUE.
893
x(i,j) = Values(Variable % DOFs*(Indexes(j)-1)+i)
894
END IF
895
END DO
896
END IF
897
END DO
898
IF( PRESENT(Found)) Found = Found0
899
900
END SUBROUTINE GetVectorLocalSolution
901
902
903
! Eigenmodes may be used as a basis of sensitivity analysis, model reduction etc.
904
! then these subroutines may be used to obtain the local eigenmodes
905
!-------------------------------------------------------------------------------
906
907
!> Returns the number of eigenmodes
908
FUNCTION GetNofEigenModes( name,USolver) RESULT (NofEigenModes)
909
910
CHARACTER(LEN=*), OPTIONAL :: name
911
TYPE(Solver_t) , OPTIONAL, TARGET :: USolver
912
INTEGER :: NofEigenModes
913
914
REAL(KIND=dp), POINTER :: Values(:)
915
TYPE(Variable_t), POINTER :: Variable
916
TYPE(Solver_t) , POINTER :: Solver
917
918
NofEigenModes = 0
919
920
Solver => CurrentModel % Solver
921
IF ( PRESENT(USolver) ) Solver => USolver
922
923
Variable => Solver % Variable
924
IF ( PRESENT(name) ) THEN
925
Variable => VariableGet( Solver % Mesh % Variables, name )
926
END IF
927
928
IF ( .NOT. ASSOCIATED( Variable ) ) RETURN
929
IF ( .NOT. ASSOCIATED( Variable % EigenValues ) ) RETURN
930
931
NofEigenModes = SIZE( Variable % EigenValues, 1)
932
END FUNCTION GetNofEigenModes
933
934
935
!> Returns the desired eigenmode as a scalar field in an element
936
SUBROUTINE GetScalarLocalEigenmode( x,name,UElement,USolver,NoEigen,ComplexPart )
937
REAL(KIND=dp) :: x(:)
938
CHARACTER(LEN=*), OPTIONAL :: name
939
TYPE(Solver_t) , OPTIONAL, TARGET :: USolver
940
TYPE(Element_t), OPTIONAL, TARGET :: UElement
941
INTEGER, OPTIONAL :: NoEigen
942
LOGICAL, OPTIONAL :: ComplexPart
943
944
COMPLEX(KIND=dp), POINTER :: Values(:)
945
TYPE(Variable_t), POINTER :: Variable
946
TYPE(Solver_t) , POINTER :: Solver
947
TYPE(Element_t), POINTER :: Element
948
LOGICAL :: IsComplex
949
950
INTEGER :: i, j, n
951
INTEGER, POINTER :: Indexes(:)
952
953
Solver => CurrentModel % Solver
954
IF ( PRESENT(USolver) ) Solver => USolver
955
956
x = 0.0d0
957
958
Variable => Solver % Variable
959
IF ( PRESENT(name) ) THEN
960
Variable => VariableGet( Solver % Mesh % Variables, name )
961
END IF
962
IF ( .NOT. ASSOCIATED( Variable ) ) RETURN
963
IF ( .NOT. ASSOCIATED( Variable % EigenVectors ) ) RETURN
964
965
IsComplex = .FALSE.
966
IF( PRESENT( ComplexPart) ) IsComplex = ComplexPart
967
968
Element => GetCurrentElement(UElement)
969
970
Indexes => GetIndexStore()
971
IF ( ASSOCIATED(Variable % Solver ) ) THEN
972
n = GetElementDOFs( Indexes, Element, Variable % Solver )
973
ELSE
974
n = GetElementDOFs( Indexes, Element, Solver )
975
END IF
976
n = MIN( n, SIZE(x) )
977
978
IF (SIZE(Variable % EigenVectors,1) < NoEigen) THEN
979
CALL Fatal('GetScalarLocalEigenmode', 'Fewer eigenfunctions available than requested')
980
END IF
981
Values => Variable % EigenVectors( NoEigen, :)
982
983
IF ( ASSOCIATED( Variable % Perm ) ) THEN
984
DO i=1,n
985
j = Indexes(i)
986
IF ( j>0 .AND. j<= SIZE(Variable % Perm)) THEN
987
j = Variable % Perm(j)
988
IF ( j>0 ) THEN
989
IF ( IsComplex ) THEN
990
x(i) = AIMAG(Values(j))
991
ELSE
992
x(i) = REAL(Values(j))
993
END IF
994
END IF
995
END IF
996
END DO
997
ELSE
998
x(1:n) = Values(Indexes(1:n))
999
END IF
1000
END SUBROUTINE GetScalarLocalEigenmode
1001
1002
1003
1004
!> Returns the desired eigenmode as a vector field in an element
1005
SUBROUTINE GetVectorLocalEigenmode( x,name,UElement,USolver,NoEigen,ComplexPart )
1006
REAL(KIND=dp) :: x(:,:)
1007
CHARACTER(LEN=*), OPTIONAL :: name
1008
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
1009
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1010
INTEGER, OPTIONAL :: NoEigen
1011
LOGICAL, OPTIONAL :: ComplexPart
1012
1013
TYPE(Variable_t), POINTER :: Variable
1014
TYPE(Solver_t) , POINTER :: Solver
1015
TYPE(Element_t), POINTER :: Element
1016
LOGICAL :: IsComplex
1017
1018
INTEGER :: i, j, k, n
1019
INTEGER, POINTER :: Indexes(:)
1020
COMPLEX(KIND=dp), POINTER :: Values(:)
1021
1022
Solver => CurrentModel % Solver
1023
IF ( PRESENT(USolver) ) Solver => USolver
1024
1025
IsComplex = .FALSE.
1026
IF( PRESENT( ComplexPart) ) IsComplex = ComplexPart
1027
1028
x = 0.0d0
1029
1030
Variable => Solver % Variable
1031
IF ( PRESENT(name) ) THEN
1032
Variable => VariableGet( Solver % Mesh % Variables, name )
1033
END IF
1034
IF ( .NOT. ASSOCIATED( Variable ) ) RETURN
1035
IF ( .NOT. ASSOCIATED( Variable % EigenVectors ) ) RETURN
1036
1037
Element => GetCurrentElement(UElement)
1038
1039
Indexes => GetIndexStore()
1040
IF ( ASSOCIATED(Variable % Solver ) ) THEN
1041
n = GetElementDOFs( Indexes, Element, Variable % Solver )
1042
ELSE
1043
n = GetElementDOFs( Indexes, Element, Solver )
1044
END IF
1045
n = MIN( n, SIZE(x) )
1046
1047
IF (SIZE(Variable % EigenVectors,1) < NoEigen) THEN
1048
CALL Fatal('GetVectorLocalEigenmode', 'Fewer eigenfunctions available than requested')
1049
END IF
1050
Values => Variable % EigenVectors( NoEigen, : )
1051
1052
DO i=1,Variable % DOFs
1053
IF ( ASSOCIATED( Variable % Perm ) ) THEN
1054
DO j=1,n
1055
k = Indexes(j)
1056
IF ( k>0 .AND. k<= SIZE(Variable % Perm)) THEN
1057
k = Variable % Perm(k)
1058
IF ( k>0 ) THEN
1059
IF ( IsComplex ) THEN
1060
x(i,j) = AIMAG(Values(Variable % DOFs*(k-1)+i))
1061
ELSE
1062
x(i,j) = REAL(Values(Variable % DOFs*(k-1)+i))
1063
END IF
1064
END IF
1065
END IF
1066
END DO
1067
ELSE
1068
DO j=1,n
1069
IF( IsComplex ) THEN
1070
x(i,j) = AIMAG( Values(Variable % DOFs*(Indexes(j)-1)+i) )
1071
ELSE
1072
x(i,j) = REAL( Values(Variable % DOFs*(Indexes(j)-1)+i) )
1073
END IF
1074
END DO
1075
END IF
1076
END DO
1077
END SUBROUTINE GetVectorLocalEigenmode
1078
1079
1080
1081
!> Returns the desired constraint mode as a scalar field in an element
1082
SUBROUTINE GetScalarLocalConsmode( x,name,UElement,USolver,NoMode)
1083
REAL(KIND=dp) :: x(:)
1084
CHARACTER(LEN=*), OPTIONAL :: name
1085
TYPE(Solver_t) , OPTIONAL, TARGET :: USolver
1086
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1087
INTEGER, OPTIONAL :: NoMode
1088
1089
REAL(KIND=dp), POINTER :: Values(:)
1090
TYPE(Variable_t), POINTER :: Variable
1091
TYPE(Solver_t) , POINTER :: Solver
1092
TYPE(Element_t), POINTER :: Element
1093
1094
INTEGER :: i, j, k, l, n
1095
INTEGER, POINTER :: Indexes(:)
1096
1097
Solver => CurrentModel % Solver
1098
IF ( PRESENT(USolver) ) Solver => USolver
1099
1100
x = 0.0d0
1101
1102
IF ( PRESENT(name) ) THEN
1103
Variable => VariableGet( Solver % Mesh % Variables, name )
1104
ELSE
1105
Variable => Solver % Variable
1106
END IF
1107
IF ( .NOT. ASSOCIATED( Variable ) ) RETURN
1108
IF ( .NOT. ASSOCIATED( Variable % ConstraintModes ) ) RETURN
1109
1110
Element => GetCurrentElement(UElement)
1111
1112
Indexes => GetIndexStore()
1113
IF ( ASSOCIATED(Variable % Solver ) ) THEN
1114
n = GetElementDOFs( Indexes, Element, Variable % Solver )
1115
ELSE
1116
n = GetElementDOFs( Indexes, Element, Solver )
1117
END IF
1118
n = MIN( n, SIZE(x) )
1119
1120
IF (SIZE(Variable % ConstraintModes,1) < NoMode) THEN
1121
CALL Fatal('GetScalarLocalConsmode', 'Fewer constraint modes available than requested')
1122
END IF
1123
Values => Variable % ConstraintModes( NoMode, :)
1124
1125
1126
IF ( ASSOCIATED( Variable % Perm ) ) THEN
1127
IF( Variable % PeriodicFlipActive ) THEN
1128
DO i=1,n
1129
j = Indexes(i)
1130
IF ( j>0 .AND. j<=SIZE(Variable % Perm) ) THEN
1131
k = Variable % Perm(j)
1132
IF ( k>0 ) THEN
1133
x(i) = Values(k)
1134
IF( CurrentModel % Mesh % PeriodicFlip(j) ) x(i) = -x(i)
1135
END IF
1136
END IF
1137
END DO
1138
ELSE
1139
DO i=1,n
1140
j = Indexes(i)
1141
IF ( j>0 .AND. j<=SIZE(Variable % Perm) ) THEN
1142
j = Variable % Perm(j)
1143
IF ( j>0 ) THEN
1144
x(i) = Values(j)
1145
END IF
1146
END IF
1147
END DO
1148
END IF
1149
ELSE
1150
DO i=1,n
1151
j = Indexes(i)
1152
IF ( j>0 .AND. j<=SIZE(Variable % Values) ) THEN
1153
x(i) = Values(Indexes(i))
1154
END IF
1155
END DO
1156
END IF
1157
1158
END SUBROUTINE GetScalarLocalConsmode
1159
1160
1161
1162
!> Returns the desired constraint mode as a vector field in an element
1163
SUBROUTINE GetVectorLocalConsmode( x,name,UElement,USolver,NoMode)
1164
REAL(KIND=dp) :: x(:,:)
1165
CHARACTER(LEN=*), OPTIONAL :: name
1166
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
1167
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1168
INTEGER, OPTIONAL :: NoMode
1169
1170
TYPE(Variable_t), POINTER :: Variable
1171
TYPE(Solver_t) , POINTER :: Solver
1172
TYPE(Element_t), POINTER :: Element
1173
1174
INTEGER :: i, j, k, l, n
1175
INTEGER, POINTER :: Indexes(:)
1176
REAL(KIND=dp), POINTER :: Values(:)
1177
1178
Solver => CurrentModel % Solver
1179
IF ( PRESENT(USolver) ) Solver => USolver
1180
1181
x = 0.0d0
1182
1183
IF ( PRESENT(name) ) THEN
1184
Variable => VariableGet( Solver % Mesh % Variables, name )
1185
ELSE
1186
Variable => Solver % Variable
1187
END IF
1188
IF ( .NOT. ASSOCIATED( Variable ) ) RETURN
1189
IF ( .NOT. ASSOCIATED( Variable % ConstraintModes ) ) RETURN
1190
1191
Element => GetCurrentElement(UElement)
1192
1193
Indexes => GetIndexStore()
1194
IF ( ASSOCIATED(Variable % Solver ) ) THEN
1195
n = GetElementDOFs( Indexes, Element, Variable % Solver )
1196
ELSE
1197
n = GetElementDOFs( Indexes, Element, Solver )
1198
END IF
1199
n = MIN( n, SIZE(x) )
1200
1201
IF (SIZE(Variable % ConstraintModes,1) < NoMode) THEN
1202
CALL Fatal('GetVectorLocalConsmode', 'Fewer constraint modes available than requested')
1203
END IF
1204
Values => Variable % ConstraintModes( NoMode, :)
1205
1206
DO i=1,Variable % DOFs
1207
IF ( ASSOCIATED( Variable % Perm ) ) THEN
1208
IF( Variable % PeriodicFlipActive ) THEN
1209
DO j=1,n
1210
k = Indexes(j)
1211
IF ( k>0 .AND. k<=SIZE(Variable % Perm) ) THEN
1212
l = Variable % Perm(k)
1213
IF( l>0 ) THEN
1214
x(i,j) = Values(Variable % DOFs*(l-1)+i)
1215
IF( CurrentModel % Mesh % PeriodicFlip(k) ) x(i,j) = -x(i,j)
1216
END IF
1217
END IF
1218
END DO
1219
ELSE
1220
DO j=1,n
1221
k = Indexes(j)
1222
IF ( k>0 .AND. k<=SIZE(Variable % Perm) ) THEN
1223
l = Variable % Perm(k)
1224
IF (l>0) THEN
1225
x(i,j) = Values(Variable % DOFs*(l-1)+i)
1226
END IF
1227
END IF
1228
END DO
1229
END IF
1230
ELSE
1231
DO j=1,n
1232
IF ( Variable % DOFs*(Indexes(j)-1)+i <= &
1233
SIZE( Variable % Values ) ) THEN
1234
x(i,j) = Values(Variable % DOFs*(Indexes(j)-1)+i)
1235
END IF
1236
END DO
1237
END IF
1238
END DO
1239
1240
END SUBROUTINE GetVectorLocalConsmode
1241
1242
1243
1244
1245
FUNCTION DefaultVariableGet( Name, ThisOnly, USolver ) RESULT ( Var )
1246
1247
CHARACTER(LEN=*) :: Name
1248
LOGICAL, OPTIONAL :: ThisOnly
1249
TYPE(Solver_t), POINTER, OPTIONAL :: USolver
1250
TYPE(Variable_t), POINTER :: Var
1251
!------------------------------------------------------------------------------
1252
TYPE(Variable_t), POINTER :: Variables
1253
1254
IF( PRESENT( USolver ) ) THEN
1255
Variables => USolver % Mesh % Variables
1256
ELSE
1257
Variables => CurrentModel % Solver % Mesh % Variables
1258
END IF
1259
1260
Var => VariableGet( Variables, Name, ThisOnly )
1261
1262
END FUNCTION DefaultVariableGet
1263
1264
1265
!------------------------------------------------------------------------------
1266
!> Add variable to the default variable list.
1267
!------------------------------------------------------------------------------
1268
SUBROUTINE DefaultVariableAdd( Name, DOFs, Perm, Values,&
1269
Output,Secondary,VariableType,Global,InitValue,USolver,Var )
1270
1271
CHARACTER(LEN=*) :: Name
1272
INTEGER, OPTIONAL :: DOFs
1273
REAL(KIND=dp), OPTIONAL, POINTER :: Values(:)
1274
LOGICAL, OPTIONAL :: Output
1275
INTEGER, OPTIONAL, POINTER :: Perm(:)
1276
LOGICAL, OPTIONAL :: Secondary
1277
INTEGER, OPTIONAL :: VariableType
1278
LOGICAL, OPTIONAL :: Global
1279
REAL(KIND=dp), OPTIONAL :: InitValue
1280
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
1281
TYPE(Variable_t), OPTIONAL, POINTER :: Var
1282
!------------------------------------------------------------------------------
1283
TYPE(Variable_t), POINTER :: Variables
1284
TYPE(Mesh_t), POINTER :: Mesh
1285
TYPE(Solver_t), POINTER :: Solver
1286
1287
IF( PRESENT( USolver ) ) THEN
1288
Solver => USolver
1289
ELSE
1290
Solver => CurrentModel % Solver
1291
END IF
1292
Mesh => Solver % Mesh
1293
Variables => Mesh % Variables
1294
1295
CALL VariableAddVector( Variables,Mesh,Solver,Name,DOFs,Values,&
1296
Perm,Output,Secondary,VariableType,Global,InitValue )
1297
1298
IF( PRESENT( Var ) ) THEN
1299
Var => VariableGet( Variables, Name )
1300
END IF
1301
1302
END SUBROUTINE DefaultVariableAdd
1303
!------------------------------------------------------------------------------
1304
1305
1306
!> Returns a string by its name if found in the list structure
1307
FUNCTION GetString( List, Name, Found ) RESULT(str)
1308
TYPE(ValueList_t), POINTER :: List
1309
CHARACTER(LEN=*) :: Name
1310
LOGICAL, OPTIONAL :: Found
1311
CHARACTER(:), ALLOCATABLE :: str
1312
1313
str = TRIM(ListGetString(List, Name, Found))
1314
END FUNCTION GetString
1315
1316
1317
!> Returns an integer by its name if found in the list structure
1318
FUNCTION GetInteger( List, Name, Found ) RESULT(i)
1319
TYPE(ValueList_t), POINTER :: List
1320
CHARACTER(LEN=*) :: Name
1321
LOGICAL, OPTIONAL :: Found
1322
1323
INTEGER :: i
1324
1325
i = ListGetInteger( List, Name, Found )
1326
END FUNCTION GetInteger
1327
1328
1329
!> Returns a logical flag by its name if found in the list structure, otherwise false
1330
FUNCTION GetLogical( List, Name, Found, UnfoundFatal, DefValue ) RESULT(l)
1331
TYPE(ValueList_t), POINTER :: List
1332
CHARACTER(LEN=*) :: Name
1333
LOGICAL, OPTIONAL :: Found, UnfoundFatal, DefValue
1334
1335
LOGICAL :: l
1336
1337
l = ListGetLogical( List, Name, Found, UnfoundFatal, DefValue )
1338
END FUNCTION GetLogical
1339
1340
1341
!> Returns a constant real by its name if found in the list structure
1342
RECURSIVE FUNCTION GetConstReal( List, Name, Found,x,y,z ) RESULT(r)
1343
TYPE(ValueList_t), POINTER :: List
1344
CHARACTER(LEN=*) :: Name
1345
LOGICAL, OPTIONAL :: Found
1346
REAL(KIND=dp), OPTIONAL :: x,y,z
1347
1348
REAL(KIND=dp) :: r,xx,yy,zz
1349
1350
xx = 0.0_dp
1351
yy = 0.0_dp
1352
zz = 0.0_dp
1353
IF ( PRESENT( x ) ) xx = x
1354
IF ( PRESENT( y ) ) yy = y
1355
IF ( PRESENT( z ) ) zz = z
1356
1357
r = ListGetConstReal( List, Name, Found,xx,yy,zz )
1358
END FUNCTION GetConstReal
1359
1360
1361
!> Returns a real that may depend on global variables such as time, or timestep size,
1362
!! by its name if found in the list structure
1363
RECURSIVE FUNCTION GetCReal( List, Name, Found ) RESULT(s)
1364
TYPE(ValueList_t), POINTER :: List
1365
CHARACTER(LEN=*) :: Name
1366
LOGICAL, OPTIONAL :: Found
1367
INTEGER, TARGET :: Dnodes(1)
1368
INTEGER, POINTER :: NodeIndexes(:)
1369
1370
REAL(KIND=dp) :: s
1371
REAL(KIND=dp), POINTER CONTIG :: x(:)
1372
TYPE(Element_t), POINTER :: Element
1373
1374
INTEGER :: n, nthreads, thread, istat
1375
1376
IF ( PRESENT( Found ) ) Found = .FALSE.
1377
1378
NodeIndexes => Dnodes
1379
n = 1
1380
NodeIndexes(n) = 1
1381
1382
x => GetValueStore(n)
1383
x(1:n) = REAL(0, dp)
1384
IF( ASSOCIATED(List) ) THEN
1385
IF ( ASSOCIATED(List % Head) ) THEN
1386
x(1:n) = ListGetReal( List, Name, n, NodeIndexes, Found )
1387
END IF
1388
END IF
1389
s = x(1)
1390
END FUNCTION GetCReal
1391
1392
1393
!> Returns a real by its name if found in the list structure, and in the active element.
1394
RECURSIVE FUNCTION GetReal( List, Name, Found, UElement ) RESULT(x)
1395
IMPLICIT NONE
1396
TYPE(ValueList_t), POINTER :: List
1397
CHARACTER(LEN=*) :: Name
1398
LOGICAL, OPTIONAL :: Found
1399
INTEGER, TARGET :: Dnodes(1)
1400
INTEGER, POINTER :: NodeIndexes(:)
1401
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1402
1403
REAL(KIND=dp), POINTER CONTIG :: x(:)
1404
TYPE(Element_t), POINTER :: Element
1405
1406
INTEGER :: n, istat
1407
1408
IF ( PRESENT( Found ) ) Found = .FALSE.
1409
1410
Element => GetCurrentElement(UElement)
1411
1412
IF ( ASSOCIATED(Element) ) THEN
1413
n = GetElementNOFNodes(Element)
1414
NodeIndexes => Element % NodeIndexes
1415
ELSE
1416
n = 1
1417
NodeIndexes => Dnodes
1418
NodeIndexes(1) = 1
1419
END IF
1420
1421
x => GetValueStore(n)
1422
x(1:n) = REAL(0, dp)
1423
IF( ASSOCIATED(List) ) THEN
1424
IF ( ASSOCIATED(List % Head) ) THEN
1425
x(1:n) = ListGetReal( List, Name, n, NodeIndexes, Found )
1426
END IF
1427
END IF
1428
END FUNCTION GetReal
1429
1430
RECURSIVE SUBROUTINE GetRealValues( List, Name, Values, Found, UElement )
1431
IMPLICIT NONE
1432
TYPE(ValueList_t), POINTER :: List
1433
CHARACTER(LEN=*) :: Name
1434
REAL(KIND=dp) CONTIG :: Values(:)
1435
LOGICAL, OPTIONAL :: Found
1436
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1437
1438
! Variables
1439
INTEGER, TARGET :: Dnodes(1)
1440
INTEGER, POINTER CONTIG :: NodeIndexes(:)
1441
TYPE(Element_t), POINTER :: Element
1442
INTEGER :: n, istat
1443
1444
IF ( PRESENT( Found ) ) Found = .FALSE.
1445
1446
Element => GetCurrentElement(UElement)
1447
1448
IF ( ASSOCIATED(Element) ) THEN
1449
n = GetElementNOFNodes(Element)
1450
NodeIndexes => Element % NodeIndexes
1451
ELSE
1452
n = 1
1453
NodeIndexes => Dnodes
1454
NodeIndexes(1) = 1
1455
END IF
1456
1457
IF( ASSOCIATED(List) ) THEN
1458
IF ( ASSOCIATED(List % Head) ) THEN
1459
Values(1:n) = ListGetReal( List, Name, n, NodeIndexes, Found )
1460
END IF
1461
END IF
1462
END SUBROUTINE GetRealValues
1463
1464
1465
!> Returns a material property from either of the parents of the current boundary element
1466
RECURSIVE FUNCTION GetParentMatProp( Name, UElement, Found, UParent ) RESULT(x)
1467
CHARACTER(LEN=*) :: Name
1468
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1469
LOGICAL, OPTIONAL :: Found
1470
TYPE(Element_t), OPTIONAL, POINTER :: UParent
1471
1472
REAL(KIND=dp), POINTER CONTIG :: x(:)
1473
INTEGER, POINTER :: Indexes(:)
1474
LOGICAL :: GotIt, GotMat
1475
INTEGER :: n, leftright, mat_id
1476
TYPE(ValueList_t), POINTER :: Material
1477
TYPE(Element_t), POINTER :: Element, Parent
1478
1479
Element => GetCurrentElement(Uelement)
1480
1481
IF( .NOT. ASSOCIATED( Element ) ) THEN
1482
CALL Warn('GetParentMatProp','Element not associated!')
1483
END IF
1484
1485
IF( PRESENT(UParent) ) NULLIFY( UParent )
1486
1487
n = GetElementNOFNodes(Element)
1488
Indexes => Element % NodeIndexes
1489
1490
x => GetValueStore(n)
1491
x(1:n) = REAL(0, dp)
1492
1493
IF(.NOT. ASSOCIATED( Element % BoundaryInfo ) ) THEN
1494
CALL Warn('GetParentMatProp','Boundary element needs parent information!')
1495
RETURN
1496
END IF
1497
1498
1499
Gotit = .FALSE.
1500
DO leftright = 1, 2
1501
1502
IF( leftright == 1) THEN
1503
Parent => Element % BoundaryInfo % Left
1504
ELSE
1505
Parent => Element % BoundaryInfo % Right
1506
END IF
1507
1508
IF( ASSOCIATED(Parent) ) THEN
1509
1510
GotMat = .FALSE.
1511
IF( Parent % BodyId == 0) THEN
1512
CYCLE
1513
ELSE IF( Parent % BodyId <= CurrentModel % NumberOfBodies ) THEN
1514
mat_id = ListGetInteger( CurrentModel % Bodies(Parent % BodyId) % Values,'Material',GotMat)
1515
ELSE
1516
CALL Warn('GetParentMatProp','Invalid parent BodyId '//I2S(Parent % BodyId)//&
1517
' for element '//I2S(Parent % ElementIndex))
1518
CYCLE
1519
END IF
1520
1521
IF(.NOT. GotMat) THEN
1522
CALL Warn('GetParentMatProp','Parent body '//I2S(Parent % BodyId)//' does not have material associated!')
1523
END IF
1524
1525
IF( mat_id > 0 .AND. mat_id <= CurrentModel % NumberOfMaterials ) THEN
1526
Material => CurrentModel % Materials(mat_id) % Values
1527
ELSE
1528
CALL Warn('GetParentMatProp','Material index '//I2S(mat_id)//' not associated to material list')
1529
CYCLE
1530
END IF
1531
1532
IF( .NOT. ASSOCIATED( Material ) ) CYCLE
1533
1534
IF ( ListCheckPresent( Material,Name) ) THEN
1535
BLOCK
1536
TYPE(Element_t), POINTER :: se
1537
se => CurrentModel % CurrentElement
1538
CurrentModel % CurrentElement => Element
1539
x(1:n) = ListGetReal(Material, Name, n, Indexes)
1540
CurrentModel % CurrentElement => se
1541
END BLOCK
1542
IF( PRESENT( UParent ) ) UParent => Parent
1543
Gotit = .TRUE.
1544
EXIT
1545
END IF
1546
END IF
1547
END DO
1548
1549
IF( PRESENT( Found ) ) THEN
1550
Found = GotIt
1551
ELSE IF(.NOT. GotIt) THEN
1552
CALL Warn('GetParentMatProp','Property '//TRIM(Name)//' not in either parents!')
1553
END IF
1554
1555
END FUNCTION GetParentMatProp
1556
1557
1558
!> Returns a constant real array by its name if found in the list structure.
1559
RECURSIVE SUBROUTINE GetConstRealArray( List, x, Name, Found, UElement )
1560
TYPE(ValueList_t), POINTER :: List
1561
REAL(KIND=dp), POINTER :: x(:,:)
1562
CHARACTER(LEN=*) :: Name
1563
LOGICAL, OPTIONAL :: Found
1564
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1565
1566
IF ( PRESENT( Found ) ) Found = .FALSE.
1567
IF(ASSOCIATED(List)) THEN
1568
IF ( ASSOCIATED(List % Head) ) THEN
1569
x => ListGetConstRealArray( List, Name, Found )
1570
END IF
1571
END IF
1572
END SUBROUTINE GetConstRealArray
1573
1574
!> Returns a real array by its name if found in the list structure, and in the active element.
1575
RECURSIVE SUBROUTINE GetRealArray( List, x, Name, Found, UElement )
1576
REAL(KIND=dp), POINTER :: x(:,:,:)
1577
TYPE(ValueList_t), POINTER :: List
1578
CHARACTER(LEN=*) :: Name
1579
LOGICAL, OPTIONAL :: Found
1580
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1581
1582
TYPE(Element_t), POINTER :: Element
1583
1584
INTEGER :: n
1585
1586
IF ( PRESENT( Found ) ) Found = .FALSE.
1587
1588
Element => GetCurrentElement(UElement)
1589
1590
n = GetElementNOFNodes( Element )
1591
IF ( ASSOCIATED(List) ) THEN
1592
IF ( ASSOCIATED(List % Head) ) THEN
1593
CALL ListGetRealArray( List, Name, x, n, Element % NodeIndexes, Found )
1594
END IF
1595
END IF
1596
END SUBROUTINE GetRealArray
1597
1598
!> Returns a real vector by its name if found in the list structure, and in the active element.
1599
RECURSIVE SUBROUTINE GetRealVector( List, x, Name, Found, UElement )
1600
REAL(KIND=dp) :: x(:,:)
1601
TYPE(ValueList_t), POINTER :: List
1602
CHARACTER(LEN=*) :: Name
1603
LOGICAL, OPTIONAL :: Found
1604
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1605
1606
TYPE(Element_t), POINTER :: Element
1607
1608
INTEGER :: n
1609
1610
x = 0._dp
1611
IF ( PRESENT( Found ) ) Found = .FALSE.
1612
1613
Element => GetCurrentElement(UElement)
1614
1615
n = GetElementNOFNodes( Element )
1616
IF ( ASSOCIATED(List) ) THEN
1617
IF ( ASSOCIATED(List % Head) ) THEN
1618
CALL ListGetRealvector( List, Name, x, n, Element % NodeIndexes, Found )
1619
END IF
1620
END IF
1621
END SUBROUTINE GetRealVector
1622
1623
!> Returns a complex vector by its name if found in the list structure, and in the active element.
1624
RECURSIVE SUBROUTINE GetComplexVector( List, x, Name, Found, UElement )
1625
COMPLEX(KIND=dp) :: x(:,:)
1626
TYPE(ValueList_t), POINTER :: List
1627
CHARACTER(LEN=*) :: Name
1628
LOGICAL, OPTIONAL :: Found
1629
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1630
1631
TYPE(Element_t), POINTER :: Element
1632
LOGICAL :: lFound
1633
INTEGER :: n
1634
REAL(KIND=dp), ALLOCATABLE :: xr(:,:)
1635
1636
x = 0._dp
1637
IF ( PRESENT( Found ) ) Found = .FALSE.
1638
1639
Element => GetCurrentElement(UElement)
1640
1641
n = GetElementNOFNodes( Element )
1642
IF ( ASSOCIATED(List) ) THEN
1643
IF ( ASSOCIATED(List % Head) ) THEN
1644
ALLOCATE(xr(SIZE(x,1),SIZE(x,2)))
1645
CALL ListGetRealvector( List, Name, xr, n, &
1646
Element % NodeIndexes, lFound )
1647
IF(PRESENT(Found)) Found=lFound
1648
x = xr
1649
CALL ListGetRealvector( List, TRIM(Name)//' im', &
1650
xr, n, Element % NodeIndexes, lFound )
1651
IF(PRESENT(Found)) Found=Found.OR.lFound
1652
x = CMPLX(REAL(x), xr, KIND=dp)
1653
END IF
1654
END IF
1655
END SUBROUTINE GetComplexVector
1656
1657
1658
!> Set a named elementwise property (real-valued) to the active element or
1659
!> given element
1660
SUBROUTINE SetElementProperty( Name, Values, UElement )
1661
CHARACTER(LEN=*) :: Name
1662
REAL(KIND=dp) :: Values(:)
1663
TYPE(Element_t), POINTER, OPTIONAL :: UElement
1664
1665
TYPE(ElementData_t), POINTER :: p
1666
1667
TYPE(Element_t), POINTER :: Element
1668
1669
Element => GetCurrentElement(UElement)
1670
1671
p => Element % PropertyData
1672
DO WHILE( ASSOCIATED(p) )
1673
IF ( Name==p % Name ) EXIT
1674
p => p % Next
1675
END DO
1676
1677
IF ( ASSOCIATED(p) ) THEN
1678
IF ( SIZE(P % Values) == SIZE(Values) ) THEN
1679
P % Values = Values
1680
ELSE
1681
DEALLOCATE( P % Values )
1682
ALLOCATE( P % Values(SIZE(Values)) )
1683
P % Values = Values
1684
END IF
1685
ELSE
1686
ALLOCATE(p)
1687
ALLOCATE( P % Values(SIZE(Values)) )
1688
p % Values = Values
1689
p % Name = Name
1690
p % Next => Element % PropertyData
1691
Element % PropertyData => p
1692
END IF
1693
END SUBROUTINE SetElementProperty
1694
1695
!> Get a named elementwise property (real-valued) from the active element or
1696
!> from a given element
1697
FUNCTION GetElementProperty( Name, UElement ) RESULT(Values)
1698
CHARACTER(LEN=*) :: Name
1699
REAL(KIND=dp), POINTER :: Values(:)
1700
TYPE(Element_t), POINTER, OPTIONAL :: UElement
1701
1702
TYPE(ElementData_t), POINTER :: p
1703
1704
TYPE(Element_t), POINTER :: Element
1705
1706
Element => GetCurrentElement(UElement)
1707
1708
Values => NULL()
1709
p=> Element % PropertyData
1710
1711
DO WHILE( ASSOCIATED(p) )
1712
IF ( Name==p % Name ) THEN
1713
Values => p % Values
1714
RETURN
1715
END IF
1716
p => p % Next
1717
END DO
1718
END FUNCTION GetElementProperty
1719
1720
1721
!> Get a handle to the active element from the list of all active elements
1722
FUNCTION GetActiveElement(t,USolver) RESULT(Element)
1723
INTEGER :: t
1724
TYPE(Element_t), POINTER :: Element
1725
TYPE( Solver_t ), OPTIONAL, TARGET :: USolver
1726
1727
TYPE( Solver_t ), POINTER :: Solver
1728
INTEGER :: ind
1729
1730
Solver => CurrentModel % Solver
1731
IF ( PRESENT( USolver ) ) Solver => USolver
1732
1733
IF ( t > 0 .AND. t <= Solver % NumberOfActiveElements ) THEN
1734
! Check if colouring is really used by the solver
1735
IF( Solver % CurrentColour > 0 .AND. &
1736
ASSOCIATED( Solver % ColourIndexList ) ) THEN
1737
ind = Solver % ActiveElements( &
1738
Solver % ColourIndexList % ind(&
1739
Solver % ColourIndexList % ptr(Solver % CurrentColour)+(t-1) ) )
1740
ELSE
1741
ind = Solver % ActiveElements(t)
1742
END IF
1743
1744
Element => Solver % Mesh % Elements( ind )
1745
1746
#ifdef _OPENMP
1747
IF (omp_in_parallel()) THEN
1748
CurrentElementThread => Element
1749
ELSE
1750
! May be used by user functions, not thread safe
1751
CurrentModel % CurrentElement => Element
1752
END IF
1753
#else
1754
! May be used by user functions, not thread safe
1755
CurrentModel % CurrentElement => Element
1756
#endif
1757
ELSE
1758
WRITE( Message, * ) 'Invalid element number requested: ', t
1759
CALL Fatal( 'GetActiveElement', Message )
1760
END IF
1761
END FUNCTION GetActiveElement
1762
1763
1764
!> Get a handle to a boundary element from the list of all boundary elements
1765
FUNCTION GetBoundaryElement(t,USolver) RESULT(Element)
1766
INTEGER :: t
1767
TYPE(Element_t), POINTER :: Element
1768
TYPE( Solver_t ), OPTIONAL, TARGET :: USolver
1769
TYPE( Solver_t ), POINTER :: Solver
1770
INTEGER :: ind
1771
1772
Solver => CurrentModel % Solver
1773
IF ( PRESENT( USolver ) ) Solver => USolver
1774
1775
IF ( t > 0 .AND. t <= Solver % Mesh % NumberOfBoundaryElements ) THEN
1776
! Check if colouring is really used by the solver
1777
IF( Solver % CurrentBoundaryColour > 0 .AND. &
1778
ASSOCIATED( Solver % BoundaryColourIndexList ) ) THEN
1779
ind = Solver % BoundaryColourIndexList % ind( &
1780
Solver % BoundaryColourIndexList % ptr(Solver % CurrentBoundaryColour)+(t-1))
1781
ELSE
1782
ind = t
1783
END IF
1784
1785
! Element => Solver % Mesh % Elements( Solver % Mesh % NumberOfBulkElements+t )
1786
Element => Solver % Mesh % Elements( Solver % Mesh % NumberOfBulkElements + ind )
1787
#ifdef _OPENMP
1788
IF (omp_in_parallel()) THEN
1789
! May be used by user functions, thread safe
1790
CurrentElementThread => Element
1791
ELSE
1792
CurrentModel % CurrentElement => Element
1793
END IF
1794
#else
1795
CurrentModel % CurrentElement => Element
1796
#endif
1797
ELSE
1798
WRITE( Message, * ) 'Invalid element number requested: ', t
1799
CALL Fatal( 'GetBoundaryElement', Message )
1800
END IF
1801
END FUNCTION GetBoundaryElement
1802
1803
1804
!> Check if the boundary element is active in the current solve
1805
FUNCTION ActiveBoundaryElement(UElement,USolver,DGBoundary) RESULT(l)
1806
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1807
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
1808
LOGICAL, OPTIONAL :: DGBoundary
1809
1810
LOGICAL :: l, DGb
1811
INTEGER :: n, n2
1812
INTEGER, POINTER :: Indexes(:)
1813
1814
TYPE( Solver_t ), POINTER :: Solver
1815
TYPE(Element_t), POINTER :: Element, P1, P2
1816
1817
Solver => CurrentModel % Solver
1818
IF ( PRESENT( USolver ) ) Solver => USolver
1819
1820
Element => GetCurrentElement(UElement)
1821
1822
Indexes => GetIndexStore()
1823
n = GetElementDOFs( Indexes, Element, Solver )
1824
1825
DGb = Solver % DG .AND. PRESENT(DGboundary)
1826
IF(DGb) DGb = DGboundary
1827
1828
IF (DGb) THEN
1829
P1 => Element % BoundaryInfo % Left
1830
P2 => Element % BoundaryInfo % Right
1831
IF ( ASSOCIATED(P1).AND.ASSOCIATED(P2) ) THEN
1832
n = P1 % Type % NumberOfNodes
1833
l = ALL(Solver % Variable % Perm(Indexes(1:n)) > 0)
1834
IF (.NOT.l) THEN
1835
n2 = P2 % Type % NumberOfNodes
1836
l = ALL(Solver % Variable % Perm(Indexes(n+1:n+n2)) > 0)
1837
END IF
1838
ELSE
1839
l = ALL(Solver % Variable % Perm(Indexes(1:n)) > 0)
1840
END IF
1841
ELSE
1842
IF (isActivePElement(Element)) n=GetElementNOFNOdes(Element)
1843
l = ALL(Solver % Variable % Perm(Indexes(1:n)) > 0)
1844
END IF
1845
END FUNCTION ActiveBoundaryElement
1846
1847
1848
!> Return the element code in Elmer convention of the active element
1849
FUNCTION GetElementCode( Element ) RESULT(etype)
1850
INTEGER :: etype
1851
TYPE(Element_t), OPTIONAL :: Element
1852
TYPE(Element_t), POINTER :: CurrElement
1853
1854
CurrElement => GetCurrentElement(Element)
1855
etype = CurrElement % TYPE % ElementCode
1856
END FUNCTION GetElementCode
1857
1858
!> Return the element dimension in Elmer convention of the active element
1859
FUNCTION GetElementDim( Element ) RESULT(edim)
1860
INTEGER :: edim
1861
TYPE(Element_t), OPTIONAL :: Element
1862
TYPE(Element_t), POINTER :: CurrElement
1863
INTEGER :: etype
1864
1865
CurrElement => GetCurrentElement(Element)
1866
etype = CurrElement % TYPE % ElementCode
1867
IF( etype >= 500 ) THEN
1868
edim = 3
1869
ELSE IF( etype >= 300 ) THEN
1870
edim = 2
1871
ELSE IF( etype >= 200 ) THEN
1872
edim = 1
1873
ELSE
1874
edim = 0
1875
END IF
1876
END FUNCTION GetElementDim
1877
1878
1879
!> Return the element family in Elmer convention of the active element
1880
FUNCTION GetElementFamily( Element ) RESULT(family)
1881
INTEGER :: family
1882
TYPE(Element_t), OPTIONAL :: Element
1883
TYPE(Element_t), POINTER :: CurrElement
1884
1885
CurrElement => GetCurrentElement(Element)
1886
family = CurrElement % TYPE % ElementCode / 100
1887
END FUNCTION GetElementFamily
1888
1889
1890
!> Return the number of corners nodes i.e. the number of dofs for the lowest order element
1891
FUNCTION GetElementCorners( Element ) RESULT(corners)
1892
INTEGER :: corners
1893
TYPE(Element_t), OPTIONAL :: Element
1894
TYPE(Element_t), POINTER :: CurrElement
1895
1896
CurrElement => GetCurrentElement(Element)
1897
corners = CurrElement % TYPE % ElementCode / 100
1898
IF( corners >= 5 .AND. corners <= 7 ) THEN
1899
corners = corners - 1
1900
END IF
1901
END FUNCTION GetElementCorners
1902
1903
!> Return true if the element is a possible flux element
1904
!> Needed to skip nodal elements in 2D and 3D boundary condition setting.
1905
FUNCTION PossibleFluxElement( Element, Mesh ) RESULT(possible)
1906
LOGICAL :: possible
1907
TYPE(Element_t), OPTIONAL :: Element
1908
TYPE(Mesh_t), OPTIONAL :: Mesh
1909
INTEGER :: MeshDim, family
1910
1911
! Orphan elements are not currently present in the mesh so any
1912
! boundary condition that exists is a possible flux element also.
1913
! Thus this routine is more or less obsolete.
1914
possible = .TRUE.
1915
1916
RETURN
1917
1918
1919
IF( PRESENT( Mesh ) ) THEN
1920
MeshDim = Mesh % MeshDim
1921
ELSE
1922
MeshDim = CurrentModel % Solver % Mesh % MeshDim
1923
END IF
1924
1925
family = GetElementFamily( Element )
1926
1927
! This is not a generic rule but happens to be true for all combinations
1928
! 3D: families 3 and 4
1929
! 2D: family 2
1930
! 1D: family 1
1931
possible = ( MeshDim <= family )
1932
1933
END FUNCTION PossibleFluxElement
1934
1935
1936
!> Return the number of nodes in the active element
1937
FUNCTION GetElementNOFNodes( Element ) RESULT(n)
1938
INTEGER :: n
1939
TYPE(Element_t), OPTIONAL :: Element
1940
TYPE(Element_t), POINTER :: CurrElement
1941
1942
CurrElement => GetCurrentElement(Element)
1943
n = CurrElement % TYPE % NumberOfNodes
1944
END FUNCTION GetELementNOFNodes
1945
1946
1947
!> Return the number of element degrees of freedom
1948
FUNCTION GetElementNOFDOFs( UElement,USolver ) RESULT(n)
1949
1950
USE PElementMaps, ONLY : isActivePElement, getEdgeDOFs, getFaceDOFs, getBubbleDOFs
1951
1952
INTEGER :: n
1953
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
1954
TYPE(Element_t), OPTIONAL, TARGET :: UElement
1955
1956
TYPE(Element_t), POINTER :: Element, Face
1957
TYPE(Solver_t), POINTER :: Solver
1958
1959
INTEGER :: i, j, k, id, ElemFamily, ParentFamily, face_type, face_id
1960
INTEGER :: NDOFs
1961
LOGICAL :: Found, GB, NeedEdges, Bubbles
1962
1963
IF ( PRESENT( USolver ) ) THEN
1964
Solver => USolver
1965
ELSE
1966
Solver => CurrentModel % Solver
1967
END IF
1968
1969
n = 0
1970
1971
IF (.NOT. ASSOCIATED(Solver)) THEN
1972
CALL Warn('GetElementNOFDOFS', &
1973
'Cannot return the number of DOFs without knowing solver')
1974
RETURN
1975
END IF
1976
1977
Element => GetCurrentElement( UElement )
1978
ElemFamily = GetElementFamily(Element)
1979
1980
IF( Solver % DG ) THEN
1981
n = Element % DGDOFs
1982
IF ( n>0 ) RETURN
1983
END IF
1984
1985
id = Element % BodyId
1986
IF ( Id==0 .AND. ASSOCIATED(Element % BoundaryInfo) ) THEN
1987
IF ( ASSOCIATED(Element % BoundaryInfo % Left) ) &
1988
id = Element % BoundaryInfo % Left % BodyId
1989
1990
IF ( ASSOCIATED(Element % BoundaryInfo % Right) ) &
1991
id = Element % BoundaryInfo % Right % BodyId
1992
END IF
1993
IF ( Id==0 ) id=1
1994
1995
IF ( Solver % Def_Dofs(ElemFamily,id,1)>0 ) n = Element % NDOFs
1996
NDOFs = MAX(0, Solver % Def_Dofs(ElemFamily,id,1))
1997
IF (NDOFs > 0) n = NDOFs * Element % TYPE % NumberOfNodes
1998
1999
NeedEdges = .FALSE.
2000
DO i=2,SIZE(Solver % Def_Dofs,3)
2001
IF (Solver % Def_Dofs(ElemFamily, id, i)>=0) THEN
2002
NeedEdges = .TRUE.
2003
EXIT
2004
END IF
2005
END DO
2006
2007
IF (.NOT. NeedEdges) THEN
2008
!
2009
! Check whether face DOFs have been generated by "-quad_face b: ..." or
2010
! "-tri_face b: ..."
2011
!
2012
IF (ElemFamily == 3 .OR. ElemFamily == 4) THEN
2013
IF (Solver % Def_Dofs(6+ElemFamily, id, 5)>=0) NeedEdges = .TRUE.
2014
ELSE
2015
!
2016
! Check finally if 3-D faces are associated with face bubbles
2017
!
2018
IF ( ASSOCIATED( Element % FaceIndexes ) ) THEN
2019
DO j=1,Element % TYPE % NumberOfFaces
2020
Face => Solver % Mesh % Faces(Element % FaceIndexes(j))
2021
face_type = Face % TYPE % ElementCode/100
2022
IF (ASSOCIATED(Face % BoundaryInfo % Left)) THEN
2023
face_id = Face % BoundaryInfo % Left % BodyId
2024
k = MAX(0,Solver % Def_Dofs(face_type+6,face_id,5))
2025
END IF
2026
IF (ASSOCIATED(Face % BoundaryInfo % Right)) THEN
2027
face_id = Face % BoundaryInfo % Right % BodyId
2028
k = MAX(k,Solver % Def_Dofs(face_type+6,face_id,5))
2029
END IF
2030
IF (k > 0) THEN
2031
NeedEdges = .TRUE.
2032
EXIT
2033
END IF
2034
END DO
2035
END IF
2036
END IF
2037
END IF
2038
2039
IF ( .NOT. NeedEdges ) RETURN
2040
2041
2042
BLOCK
2043
LOGICAL :: EdgesDone, FacesDone
2044
INTEGER :: Ind, i,j, p, nb, EDOFs, FDOFs, BDOFs
2045
INTEGER :: face_id
2046
TYPE(Element_t), POINTER :: Parent, Edge
2047
2048
EdgesDone = .FALSE.; FacesDone = .FALSE.
2049
IF ( ASSOCIATED( Element % EdgeIndexes ) ) THEN
2050
DO j=1,Element % Type % NumberOFEdges
2051
Edge => Solver % Mesh % Edges( Element % EdgeIndexes(j) )
2052
IF (Edge % Type % ElementCode == Element % Type % ElementCode) THEN
2053
IF (.NOT. Solver % GlobalBubbles.OR..NOT.ASSOCIATED(Element % BoundaryInfo)) CYCLE
2054
END IF
2055
2056
EDOFs = 0
2057
IF (Solver % Def_Dofs(ElemFamily,id,2) >= 0) THEN
2058
EDOFs = Solver % Def_Dofs(ElemFamily,id,2)
2059
ELSE IF (Solver % Def_Dofs(ElemFamily,id,6) > 1) THEN
2060
! TO DO: This is not yet perfect; cf. what is done in InitialPermutation
2061
EDOFs = getEdgeDOFs(Element, Solver % Def_Dofs(ElemFamily,id,6))
2062
END IF
2063
n = n + EDOFs
2064
END DO
2065
EdgesDone = .TRUE.
2066
END IF
2067
2068
IF ( ASSOCIATED( Element % FaceIndexes ) ) THEN
2069
DO j=1,Element % TYPE % NumberOfFaces
2070
Face => Solver % Mesh % Faces( Element % FaceIndexes(j) )
2071
2072
IF (Face % Type % ElementCode==Element % Type % ElementCode) THEN
2073
IF ( .NOT.Solver % GlobalBubbles.OR..NOT.ASSOCIATED(Element % BoundaryInfo)) CYCLE
2074
END IF
2075
2076
k = MAX(0,Solver % Def_Dofs(ElemFamily,id,3))
2077
IF (k == 0) THEN
2078
!
2079
! NOTE: This depends on what dofs have been introduced
2080
! by using the construct "-quad_face b: ..." and
2081
! "-tri_face b: ..."
2082
!
2083
face_type = Face % TYPE % ElementCode/100
2084
IF (ASSOCIATED(Face % BoundaryInfo % Left)) THEN
2085
face_id = Face % BoundaryInfo % Left % BodyId
2086
k = MAX(0,Solver % Def_Dofs(face_type+6,face_id,5))
2087
END IF
2088
IF (ASSOCIATED(Face % BoundaryInfo % Right)) THEN
2089
face_id = Face % BoundaryInfo % Right % BodyId
2090
k = MAX(k,Solver % Def_Dofs(face_type+6,face_id,5))
2091
END IF
2092
2093
FDOFs = 0
2094
IF (k > 0) THEN
2095
FDOFs = k
2096
ELSE IF (Solver % Def_Dofs(ElemFamily,id,6) > 1) THEN
2097
! TO DO: This is not yet perfect; cf. what is done in InitialPermutation
2098
FDOFs = getFaceDOFs(Element,Solver % Def_Dofs(ElemFamily,id,6),j,Face)
2099
END IF
2100
END IF
2101
n = n + FDOFs
2102
END DO
2103
FacesDone = .TRUE.
2104
END IF
2105
2106
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
2107
2108
IF (isActivePElement(Element) ) THEN
2109
Parent => Element % PDefs % LocalParent
2110
ELSE
2111
Parent => Element % BoundaryInfo % Left
2112
IF (.NOT.ASSOCIATED(Parent) ) &
2113
Parent => Element % BoundaryInfo % Right
2114
END IF
2115
IF (.NOT.ASSOCIATED(Parent) ) RETURN
2116
ParentFamily = Parent % TYPE % ElementCode / 100
2117
2118
SELECT CASE(ElemFamily)
2119
CASE(2)
2120
IF ( .NOT. EdgesDone .AND. ASSOCIATED(Parent % EdgeIndexes) ) THEN
2121
EDOFs = 0
2122
IF ( isActivePElement(Element, Solver) ) THEN
2123
Ind=Element % PDefs % LocalNumber
2124
ELSE
2125
DO Ind=1,Parent % TYPE % NumberOfEdges
2126
Edge => Solver % Mesh % Edges(Parent % EdgeIndexes(ind))
2127
k = 0
2128
DO i=1,Edge % TYPE % NumberOfNodes
2129
DO j=1,Element % TYPE % NumberOfNodes
2130
IF ( Edge % NodeIndexes(i)==Element % NodeIndexes(j) ) k=k+1
2131
END DO
2132
END DO
2133
IF ( k==Element % TYPE % NumberOfNodes) EXIT
2134
END DO
2135
END IF
2136
2137
IF (Solver % Def_Dofs(ElemFamily,id,2) >= 0) THEN
2138
EDOFs = Solver % Def_Dofs(ElemFamily,id,2)
2139
ELSE IF (Solver % Def_Dofs(ElemFamily,id,6) > 1) THEN
2140
EDOFs = getEdgeDOFs(Parent, Solver % Def_Dofs(ParentFamily,id,6))
2141
END IF
2142
2143
n = n + EDOFs
2144
END IF
2145
2146
CASE(3,4)
2147
IF ( .NOT. FacesDone .AND. ASSOCIATED( Parent % FaceIndexes ) ) THEN
2148
2149
IF ( isActivePElement(Element, Solver) ) THEN
2150
Ind=Element % PDefs % LocalNumber
2151
ELSE
2152
DO Ind=1,Parent % TYPE % NumberOfFaces
2153
Face => Solver % Mesh % Faces(Parent % FaceIndexes(ind))
2154
k = 0
2155
DO i=1,Face % TYPE % NumberOfNodes
2156
DO j=1,Element % TYPE % NumberOfNodes
2157
IF ( Face % NodeIndexes(i)==Element % NodeIndexes(j)) k=k+1
2158
END DO
2159
END DO
2160
IF ( k==Face % TYPE % NumberOfNodes) EXIT
2161
END DO
2162
END IF
2163
2164
IF (Ind >= 1 .AND. Ind <= Parent % Type % NumberOfFaces) THEN
2165
2166
IF (ASSOCIATED(Element % FaceIndexes).AND. isActivePelement(Element, Solver) ) THEN
2167
Face => Solver % Mesh % Faces(Element % PDefs % localParent % Faceindexes(Ind))
2168
ELSE
2169
Face => Element
2170
END IF
2171
2172
IF (.NOT.EdgesDone .AND. ASSOCIATED(Face % EdgeIndexes)) THEN
2173
DO j=1,Face % TYPE % NumberOFEdges
2174
Edge => Solver % Mesh % Edges(Face % EdgeIndexes(j))
2175
2176
EDOFs = 0
2177
IF (Solver % Def_Dofs(ElemFamily,id,2) >= 0) THEN
2178
EDOFs = Solver % Def_Dofs(ElemFamily,id,2)
2179
ELSE IF (Solver % Def_Dofs(ElemFamily,id,6) > 1) THEN
2180
! TO DO: This is not yet perfect when p varies over mesh; cf. what is done in InitialPermutation
2181
EDOFs = getEdgeDOFs(Element, Solver % Def_Dofs(ElemFamily,id,6))
2182
END IF
2183
n = n + EDOFs
2184
END DO
2185
END IF
2186
2187
FDOFs = 0
2188
IF (Solver % Def_Dofs(ParentFamily,id,6) > 1) THEN
2189
FDOFs = getFaceDOFs(Parent,Solver % Def_Dofs(ParentFamily,id,6),Ind,Face)
2190
ELSE
2191
k = MAX(0,Solver % Def_Dofs(ElemFamily,id,3))
2192
IF (k == 0) THEN
2193
!
2194
! NOTE: This depends on what dofs have been introduced
2195
! by using the construct "-quad_face b: ..." and
2196
! "-tri_face b: ..."
2197
!
2198
face_type = Face % TYPE % ElementCode/100
2199
IF (ASSOCIATED(Face % BoundaryInfo % Left)) THEN
2200
face_id = Face % BoundaryInfo % Left % BodyId
2201
k = MAX(0,Solver % Def_Dofs(face_type+6,face_id,5))
2202
END IF
2203
IF (ASSOCIATED(Face % BoundaryInfo % Right)) THEN
2204
face_id = Face % BoundaryInfo % Right % BodyId
2205
k = MAX(k,Solver % Def_Dofs(face_type+6,face_id,5))
2206
END IF
2207
END IF
2208
2209
IF (k > 0) THEN
2210
FDOFs = k
2211
END IF
2212
END IF
2213
n = n + FDOFs
2214
END IF
2215
END IF
2216
END SELECT
2217
ELSE
2218
IF (Solver % GlobalBubbles .AND. ASSOCIATED(Element % BubbleIndexes)) THEN
2219
BDOFs = 0
2220
nb = Solver % Def_Dofs(ElemFamily,id,5)
2221
p = Solver % Def_Dofs(ElemFamily,id,6)
2222
IF (nb >= 0 .OR. p >=1) THEN
2223
IF (p > 1) BDOFs = GetBubbleDOFs(Element, p)
2224
BDOFs = MAX(nb, BDOFs)
2225
ELSE
2226
IF (ASSOCIATED(Solver % Values)) THEN
2227
Bubbles = ListGetLogical(Solver % Values, 'Bubbles', Found )
2228
! The following is not a right way to obtain the bubble count
2229
! in order to support solverwise definitions
2230
IF (Bubbles) BDOFs = SIZE(Element % BubbleIndexes)
2231
END IF
2232
END IF
2233
n = n + BDOFs
2234
END IF
2235
END IF
2236
END BLOCK
2237
END FUNCTION GetElementNOFDOFs
2238
2239
2240
!> In addition to returning the elementwise number of degrees of freedom
2241
!> the indexes of the degrees of freedom for a particular solver are also returned
2242
!-------------------------------------------------------------------------
2243
FUNCTION GetElementDOFs( Indexes, UElement, USolver, NotDG ) RESULT(NB)
2244
INTEGER :: Indexes(:)
2245
TYPE(Element_t), OPTIONAL, TARGET :: UElement
2246
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
2247
LOGICAL, OPTIONAL :: NotDG
2248
INTEGER :: NB
2249
2250
NB = mGetElementDOFs( Indexes, UElement, USolver, NotDG )
2251
END FUNCTION GetElementDOFs
2252
2253
2254
! -----------------------------------------------------------------------------
2255
!> Returns the number of bubble degrees of freedom in the active element.
2256
!> If the sif file contains more than one solver section
2257
!> with each of them having their own specification of the "Element"
2258
!> keyword, the BDOFs field of the Element structure may not be the number of
2259
!> bubbles that should be assigned to the solver. With the optional argument
2260
!> Update = .TRUE., the correct solver-wise bubble count is assigned to the
2261
!> the Element structure.
2262
! -----------------------------------------------------------------------------
2263
FUNCTION GetElementNOFBDOFs( Element, USolver, Update ) RESULT(n)
2264
! -----------------------------------------------------------------------------
2265
INTEGER :: n
2266
TYPE(Element_t), OPTIONAL :: Element
2267
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
2268
LOGICAL, OPTIONAL :: Update
2269
2270
TYPE(Element_t), POINTER :: CurrElement
2271
TYPE(Solver_t), POINTER :: Solver
2272
LOGICAL :: Found, GB, UpdateRequested,Bubbles
2273
INTEGER :: k, p, ElemFamily
2274
2275
IF ( PRESENT( USolver ) ) THEN
2276
Solver => USolver
2277
ELSE
2278
Solver => CurrentModel % Solver
2279
END IF
2280
2281
UpdateRequested = .FALSE.
2282
IF ( PRESENT(Update) ) UpdateRequested = Update
2283
2284
!GB = ListGetLogical( Solver % Values, 'Bubbles in Global System', Found )
2285
!IF (.NOT.Found) GB = .TRUE.
2286
GB = Solver % GlobalBubbles
2287
2288
n = 0
2289
IF ( .NOT. GB ) THEN
2290
CurrElement => GetCurrentElement(Element)
2291
ElemFamily = GetElementFamily(CurrElement)
2292
2293
k = Solver % Def_Dofs(ElemFamily, CurrElement % Bodyid, 5)
2294
p = Solver % Def_Dofs(ElemFamily, CurrElement % Bodyid, 6)
2295
2296
IF (k >= 0 .OR. p >= 1) THEN
2297
! Apparently an "Element" command has been read from a solver section.
2298
! Therefore we return the value of the solverwise definition.
2299
IF (p > 1) n = GetBubbleDOFs(CurrElement, p)
2300
n = MAX(k,n)
2301
ELSE
2302
! The element command hasn't been given, so the only way to activate the bubbles
2303
! should be the "Bubbles" command. The following is not a reliable way to obtain
2304
! the bubble count when solverwise definitions are used.
2305
IF (ASSOCIATED(Solver % Values)) THEN
2306
Bubbles = ListGetLogical(Solver % Values, 'Bubbles', Found)
2307
IF (Bubbles) THEN
2308
n = CurrElement % BDOFs
2309
END IF
2310
END IF
2311
END IF
2312
2313
IF (UpdateRequested) THEN
2314
CurrElement % BDOFs = n
2315
END IF
2316
ELSE
2317
! Rectify the bubble count assigned to the Element argument in case
2318
! some other solver has tampered it:
2319
IF (UpdateRequested) THEN
2320
CurrElement => GetCurrentElement(Element)
2321
ElemFamily = GetElementFamily(CurrElement)
2322
2323
k = Solver % Def_Dofs(ElemFamily, CurrElement % Bodyid, 5)
2324
p = Solver % Def_Dofs(ElemFamily, CurrElement % Bodyid, 6)
2325
2326
IF (k >= 0 .OR. p >= 1) THEN
2327
IF (p > 1) n = GetBubbleDOFs(CurrElement, p)
2328
n = MAX(k,n)
2329
CurrElement % BDOFs = n
2330
ELSE
2331
IF (ASSOCIATED(Solver % Values)) THEN
2332
Bubbles = ListGetLogical(Solver % Values, 'Bubbles', Found)
2333
IF (Bubbles .AND. ASSOCIATED(CurrElement % BubbleIndexes)) THEN
2334
CurrElement % BDOFs = SIZE(CurrElement % BubbleIndexes)
2335
ELSE
2336
CurrElement % BDOFs = 0
2337
END IF
2338
ELSE
2339
CurrElement % BDOFs = 0
2340
END IF
2341
END IF
2342
n = 0
2343
END IF
2344
END IF
2345
END FUNCTION GetElementNOFBDOFs
2346
2347
2348
!> Returns the nodal coordinate values in the active element
2349
SUBROUTINE GetElementNodes( ElementNodes, UElement, USolver, UMesh )
2350
TYPE(Nodes_t) :: ElementNodes
2351
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
2352
TYPE(Mesh_t), OPTIONAL, TARGET :: UMesh
2353
TYPE(Element_t), OPTIONAL, TARGET :: UElement
2354
2355
INTEGER :: i,n,nd,sz,sz1
2356
INTEGER, POINTER :: Indexes(:)
2357
TYPE(Mesh_t), POINTER :: Mesh
2358
TYPE(Element_t), POINTER :: Element
2359
2360
Element => GetCurrentElement(UElement)
2361
2362
IF( PRESENT( UMesh ) ) THEN
2363
Mesh => UMesh
2364
ELSE IF( PRESENT( USolver ) ) THEN
2365
Mesh => USolver % Mesh
2366
ELSE
2367
Mesh => CurrentModel % Solver % Mesh
2368
END IF
2369
2370
n = MAX(Mesh % MaxElementNodes,Mesh % MaxElementDOFs)
2371
2372
IF ( .NOT. ASSOCIATED( ElementNodes % x ) ) THEN
2373
ALLOCATE( ElementNodes % x(n), ElementNodes % y(n),ElementNodes % z(n) )
2374
ELSE IF ( SIZE(ElementNodes % x)<n ) THEN
2375
DEALLOCATE(ElementNodes % x, ElementNodes % y, ElementNodes % z)
2376
ALLOCATE( ElementNodes % x(n), ElementNodes % y(n),ElementNodes % z(n) )
2377
END IF
2378
2379
n = Element % TYPE % NumberOfNodes
2380
2381
ElementNodes % x(1:n) = Mesh % Nodes % x(Element % NodeIndexes(1:n))
2382
ElementNodes % y(1:n) = Mesh % Nodes % y(Element % NodeIndexes(1:n))
2383
ElementNodes % z(1:n) = Mesh % Nodes % z(Element % NodeIndexes(1:n))
2384
2385
sz = SIZE(ElementNodes % x)
2386
IF ( sz > n ) THEN
2387
ElementNodes % x(n+1:sz) = 0.0_dp
2388
ElementNodes % y(n+1:sz) = 0.0_dp
2389
ElementNodes % z(n+1:sz) = 0.0_dp
2390
2391
sz1 = SIZE(Mesh % Nodes % x)
2392
IF (sz1 > Mesh % NumberOfNodes) THEN
2393
Indexes => GetIndexStore()
2394
nd = GetElementDOFs(Indexes,Element,NotDG=.TRUE.)
2395
DO i=n+1,nd
2396
IF ( Indexes(i)>0 .AND. Indexes(i)<=sz1 ) THEN
2397
ElementNodes % x(i) = Mesh % Nodes % x(Indexes(i))
2398
ElementNodes % y(i) = Mesh % Nodes % y(Indexes(i))
2399
ElementNodes % z(i) = Mesh % Nodes % z(Indexes(i))
2400
END IF
2401
END DO
2402
END IF
2403
END IF
2404
END SUBROUTINE GetElementNodes
2405
2406
2407
! This is just a small wrapper in case we want to get the original and not the
2408
! mapped coordinates. This assumes that the original coordinates are stored in
2409
! NodesOrig. This is rarely need hence no reason to overload the standard routine
2410
! with this baggage.
2411
!---------------------------------------------------------------------------------
2412
SUBROUTINE GetElementNodesOrig( ElementNodes, UElement, USolver, UMesh )
2413
TYPE(Nodes_t) :: ElementNodes
2414
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
2415
TYPE(Mesh_t), OPTIONAL, TARGET :: UMesh
2416
TYPE(Element_t), OPTIONAL, TARGET :: UElement
2417
2418
TYPE(Mesh_t), POINTER :: Mesh
2419
TYPE(Nodes_t), POINTER :: TmpNodes
2420
2421
IF( PRESENT( UMesh ) ) THEN
2422
Mesh => UMesh
2423
ELSE IF( PRESENT( USolver ) ) THEN
2424
Mesh => USolver % Mesh
2425
ELSE
2426
Mesh => CurrentModel % Solver % Mesh
2427
END IF
2428
2429
TmpNodes => Mesh % Nodes
2430
IF(.NOT. ASSOCIATED( Mesh % NodesOrig ) ) THEN
2431
CALL Fatal('GetElementNodesOrig','Original node coordinates not yet stored!')
2432
END IF
2433
Mesh % Nodes => Mesh % NodesOrig
2434
2435
CALL GetElementNodes( ElementNodes, UElement, Umesh = Mesh )
2436
Mesh % Nodes => TmpNodes
2437
2438
END SUBROUTINE GetElementNodesOrig
2439
2440
2441
!> Returns the nodal coordinate values in the active element
2442
SUBROUTINE GetElementNodesVec( ElementNodes, UElement, USolver, UMesh )
2443
TYPE(Nodes_t), TARGET :: ElementNodes
2444
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
2445
TYPE(Mesh_t), OPTIONAL, TARGET :: UMesh
2446
TYPE(Element_t), OPTIONAL, TARGET :: UElement
2447
2448
INTEGER :: padn, dum
2449
2450
INTEGER :: i,n,nd,sz,sz1
2451
INTEGER, POINTER CONTIG :: Indexes(:)
2452
2453
TYPE(Solver_t), POINTER :: Solver
2454
TYPE(Mesh_t), POINTER :: Mesh
2455
TYPE(Element_t), POINTER :: Element
2456
2457
Element => GetCurrentElement(UElement)
2458
2459
IF( PRESENT( UMesh ) ) THEN
2460
Mesh => UMesh
2461
ELSE IF( PRESENT( USolver ) ) THEN
2462
Mesh => USolver % Mesh
2463
ELSE
2464
Mesh => CurrentModel % Solver % Mesh
2465
END IF
2466
2467
n = MAX(Mesh % MaxElementNodes,Mesh % MaxElementDOFs)
2468
padn = n
2469
2470
! Here we could pad beginning of columns of xyz to 64-byte
2471
! boundaries if needed as follows
2472
! padn=NBytePad(n,STORAGE_SIZE(REAL(1,dp))/8,64)
2473
2474
IF (.NOT. ALLOCATED( ElementNodes % xyz)) THEN
2475
IF (ASSOCIATED(ElementNodes % x)) DEALLOCATE(ElementNodes % x)
2476
IF (ASSOCIATED(ElementNodes % y)) DEALLOCATE(ElementNodes % y)
2477
IF (ASSOCIATED(ElementNodes % z)) DEALLOCATE(ElementNodes % z)
2478
2479
ALLOCATE(ElementNodes % xyz(padn,3))
2480
ElementNodes % xyz = REAL(0,dp)
2481
ElementNodes % x => ElementNodes % xyz(1:n,1)
2482
ElementNodes % y => ElementNodes % xyz(1:n,2)
2483
ElementNodes % z => ElementNodes % xyz(1:n,3)
2484
ELSE IF (SIZE(ElementNodes % xyz, 1)<padn) THEN
2485
DEALLOCATE(ElementNodes % xyz)
2486
ALLOCATE(ElementNodes % xyz(padn,3))
2487
ElementNodes % xyz = REAL(0,dp)
2488
ElementNodes % x => ElementNodes % xyz(1:n,1)
2489
ElementNodes % y => ElementNodes % xyz(1:n,2)
2490
ElementNodes % z => ElementNodes % xyz(1:n,3)
2491
ELSE
2492
ElementNodes % x => ElementNodes % xyz(1:n,1)
2493
ElementNodes % y => ElementNodes % xyz(1:n,2)
2494
ElementNodes % z => ElementNodes % xyz(1:n,3)
2495
END IF
2496
2497
n = Element % TYPE % NumberOfNodes
2498
!DIR$ IVDEP
2499
DO i=1,n
2500
ElementNodes % x(i) = Mesh % Nodes % x(Element % NodeIndexes(i))
2501
ElementNodes % y(i) = Mesh % Nodes % y(Element % NodeIndexes(i))
2502
ElementNodes % z(i) = Mesh % Nodes % z(Element % NodeIndexes(i))
2503
END DO
2504
2505
sz = SIZE(ElementNodes % xyz,1)
2506
IF ( sz > n ) THEN
2507
ElementNodes % xyz(n+1:sz,1) = 0.0d0
2508
ElementNodes % xyz(n+1:sz,2) = 0.0d0
2509
ElementNodes % xyz(n+1:sz,3) = 0.0d0
2510
END IF
2511
2512
sz1 = SIZE(Mesh % Nodes % x)
2513
IF (sz1 > Mesh % NumberOfNodes) THEN
2514
Indexes => GetIndexStore()
2515
nd = GetElementDOFs(Indexes,Element,NotDG=.TRUE.)
2516
!DIR$ IVDEP
2517
DO i=n+1,nd
2518
IF ( Indexes(i)>0 .AND. Indexes(i)<=sz1 ) THEN
2519
ElementNodes % x(i) = Mesh % Nodes % x(Indexes(i))
2520
ElementNodes % y(i) = Mesh % Nodes % y(Indexes(i))
2521
ElementNodes % z(i) = Mesh % Nodes % z(Indexes(i))
2522
END IF
2523
END DO
2524
END IF
2525
END SUBROUTINE GetElementNodesVec
2526
2527
2528
SUBROUTINE GetElementNodesOrigVec( ElementNodes, UElement, USolver, UMesh )
2529
TYPE(Nodes_t), TARGET :: ElementNodes
2530
TYPE(Element_t), OPTIONAL, TARGET :: UElement
2531
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
2532
TYPE(Mesh_t), OPTIONAL, TARGET :: UMesh
2533
2534
TYPE(Mesh_t), POINTER :: Mesh
2535
TYPE(Nodes_t), POINTER :: TmpNodes
2536
2537
IF( PRESENT( UMesh ) ) THEN
2538
Mesh => UMesh
2539
ELSE IF( PRESENT( USolver ) ) THEN
2540
Mesh => USolver % Mesh
2541
ELSE
2542
Mesh => CurrentModel % Solver % Mesh
2543
END IF
2544
2545
TmpNodes => Mesh % Nodes
2546
IF(.NOT. ASSOCIATED( Mesh % NodesOrig ) ) THEN
2547
CALL Fatal('GetElementNodesOrigVec','Original node coordinates not yet stored!')
2548
END IF
2549
Mesh % Nodes => Mesh % NodesOrig
2550
2551
CALL GetElementNodesVec( ElementNodes, UElement, UMesh = Mesh )
2552
2553
Mesh % Nodes => TmpNodes
2554
2555
END SUBROUTINE GetElementNodesOrigVec
2556
2557
2558
2559
!> Get element body id
2560
!------------------------------------------------------------------------------
2561
FUNCTION GetBody( Element ) RESULT(body_id)
2562
!------------------------------------------------------------------------------
2563
INTEGER::Body_id
2564
TYPE(Element_t), OPTIONAL :: Element
2565
!------------------------------------------------------------------------------
2566
TYPE(Element_t), POINTER :: el
2567
!------------------------------------------------------------------------------
2568
el => GetCurrentElement(Element)
2569
body_id= el % BodyId
2570
!------------------------------------------------------------------------------
2571
END FUNCTION GetBody
2572
!------------------------------------------------------------------------------
2573
2574
2575
!> Get element body parameters
2576
!------------------------------------------------------------------------------
2577
FUNCTION GetBodyParams(Element) RESULT(lst)
2578
!------------------------------------------------------------------------------
2579
TYPE(ValueList_t), POINTER :: Lst
2580
TYPE(Element_t), OPTIONAL :: Element
2581
!------------------------------------------------------------------------------
2582
TYPE(Element_t), POINTER :: el
2583
!------------------------------------------------------------------------------
2584
lst => CurrentModel % Bodies(GetBody(Element)) % Values
2585
!------------------------------------------------------------------------------
2586
END FUNCTION GetBodyParams
2587
!------------------------------------------------------------------------------
2588
2589
2590
!> Get the body force index of the active element
2591
!------------------------------------------------------------------------------
2592
FUNCTION GetBodyForceId( Element, Found ) RESULT(bf_id)
2593
!------------------------------------------------------------------------------
2594
LOGICAL, OPTIONAL :: Found
2595
TYPE(Element_t), OPTIONAL :: Element
2596
TYPE(Element_t), POINTER :: CurrElement
2597
2598
INTEGER :: bf_id, body_id
2599
2600
CurrElement => GetCurrentElement(Element)
2601
body_id = CurrElement % BodyId
2602
2603
IF ( PRESENT( Found ) ) THEN
2604
bf_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values, &
2605
'Body Force', Found, minv=1,maxv=CurrentModel % NumberOfBodyForces )
2606
ELSE
2607
bf_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values, &
2608
'Body Force', minv=1,maxv=CurrentModel % NumberOfBodyForces )
2609
END IF
2610
!------------------------------------------------------------------------------
2611
END FUNCTION GetBodyForceId
2612
!------------------------------------------------------------------------------
2613
2614
2615
2616
!------------------------------------------------------------------------------
2617
!> Returns the material index of the active element
2618
FUNCTION GetMaterialId( Element, Found ) RESULT(mat_id)
2619
!------------------------------------------------------------------------------
2620
LOGICAL, OPTIONAL :: Found
2621
TYPE(Element_t), OPTIONAL :: Element
2622
TYPE(Element_t), POINTER :: CurrElement
2623
2624
INTEGER :: mat_id, body_id
2625
2626
CurrElement => GetCurrentElement(Element)
2627
body_id = CurrElement % BodyId
2628
2629
IF( body_id <= 0 ) THEN
2630
mat_id = 0
2631
IF( PRESENT( Found ) ) Found = .FALSE.
2632
RETURN
2633
END IF
2634
2635
IF ( PRESENT( Found ) ) THEN
2636
mat_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values, &
2637
'Material', Found, minv=1,maxv=CurrentModel % NumberOfMaterials )
2638
ELSE
2639
mat_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values, &
2640
'Material', minv=1,maxv=CurrentModel % NumberOfMaterials )
2641
END IF
2642
!------------------------------------------------------------------------------
2643
END FUNCTION GetMaterialId
2644
!------------------------------------------------------------------------------
2645
2646
2647
!------------------------------------------------------------------------------
2648
!> Get component list given component id
2649
FUNCTION GetComponent(i) RESULT(list)
2650
!------------------------------------------------------------------------------
2651
INTEGER :: i
2652
TYPE(ValueList_t), POINTER :: list
2653
2654
List => Null()
2655
IF(i>=0 .AND. i<=SIZE(CurrentModel % Components)) list=> &
2656
CurrentModel % Components(i) % Values
2657
!------------------------------------------------------------------------------
2658
END FUNCTION GetComponent
2659
!------------------------------------------------------------------------------
2660
2661
2662
!------------------------------------------------------------------------------
2663
!> Returns the equation index of the active element
2664
FUNCTION GetEquationId( Element, Found ) RESULT(eq_id)
2665
!------------------------------------------------------------------------------
2666
LOGICAL, OPTIONAL :: Found
2667
TYPE(Element_t), OPTIONAL :: Element
2668
TYPE(Element_t), POINTER :: CurrElement
2669
2670
INTEGER :: eq_id, body_id
2671
2672
CurrElement => GetCurrentElement(Element)
2673
body_id = CurrElement % BodyId
2674
2675
IF ( PRESENT( Found ) ) THEN
2676
eq_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values, &
2677
'Equation', Found, minv=1,maxv=CurrentModel % NumberOfEquations )
2678
ELSE
2679
eq_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values, &
2680
'Equation', minv=1,maxv=CurrentModel % NumberOfEquations )
2681
END IF
2682
!------------------------------------------------------------------------------
2683
END FUNCTION GetEquationId
2684
!------------------------------------------------------------------------------
2685
2686
2687
2688
!------------------------------------------------------------------------------
2689
!> Returns handle to the Simulation value list
2690
FUNCTION GetSimulation() RESULT(Simulation)
2691
!------------------------------------------------------------------------------
2692
TYPE(ValueList_t), POINTER :: Simulation
2693
Simulation => CurrentModel % Simulation
2694
!------------------------------------------------------------------------------
2695
END FUNCTION GetSimulation
2696
!------------------------------------------------------------------------------
2697
2698
2699
2700
!------------------------------------------------------------------------------
2701
!> Returns handle to the Constants value list
2702
FUNCTION GetConstants() RESULT(Constants)
2703
!------------------------------------------------------------------------------
2704
TYPE(ValueList_t), POINTER :: Constants
2705
Constants => CurrentModel % Constants
2706
!------------------------------------------------------------------------------
2707
END FUNCTION GetConstants
2708
!------------------------------------------------------------------------------
2709
2710
2711
2712
!------------------------------------------------------------------------------
2713
!> Returns handle to the Solver value list of the active solver
2714
FUNCTION GetSolverParams(Solver) RESULT(SolverParam)
2715
!------------------------------------------------------------------------------
2716
TYPE(ValueList_t), POINTER :: SolverParam
2717
TYPE(Solver_t), OPTIONAL :: Solver
2718
2719
SolverParam => ListGetSolverParams(Solver)
2720
!------------------------------------------------------------------------------
2721
END FUNCTION GetSolverParams
2722
!------------------------------------------------------------------------------
2723
2724
2725
2726
!------------------------------------------------------------------------------
2727
!> Returns handle to Material value list of the active element
2728
FUNCTION GetMaterial( Element, Found ) RESULT(Material)
2729
!------------------------------------------------------------------------------
2730
TYPE(Element_t), OPTIONAL :: Element
2731
LOGICAL, OPTIONAL :: Found
2732
2733
TYPE(ValueList_t), POINTER :: Material
2734
2735
LOGICAL :: L
2736
INTEGER :: mat_id
2737
2738
IF ( PRESENT( Element ) ) THEN
2739
mat_id = GetMaterialId( Element, L )
2740
ELSE
2741
mat_id = GetMaterialId( Found=L )
2742
END IF
2743
2744
Material => Null()
2745
IF ( L ) Material => CurrentModel % Materials(mat_id) % Values
2746
IF ( PRESENT( Found ) ) Found = L
2747
!------------------------------------------------------------------------------
2748
END FUNCTION GetMaterial
2749
!------------------------------------------------------------------------------
2750
2751
2752
!------------------------------------------------------------------------------
2753
!> Returns handle to Parent element of a boundary element with a larger body id.
2754
!------------------------------------------------------------------------------
2755
FUNCTION GetBulkElementAtBoundary( Element, Found ) RESULT(BulkElement)
2756
!------------------------------------------------------------------------------
2757
TYPE(Element_t), OPTIONAL :: Element
2758
LOGICAL, OPTIONAL :: Found
2759
TYPE(element_t), POINTER :: BulkElement
2760
!------------------------------------------------------------------------------
2761
TYPE(element_t), POINTER :: BulkElementL, BulkElementR, BoundaryElement
2762
LOGICAL :: L
2763
INTEGER :: mat_id, BodyIdL, BodyIdR
2764
2765
BulkElement => NULL()
2766
2767
BoundaryElement => GetCurrentElement(Element)
2768
2769
IF ( .NOT. ASSOCIATED(BoundaryElement % boundaryinfo)) RETURN
2770
BulkElementR => BoundaryElement % boundaryinfo % right
2771
BulkElementL => BoundaryElement % boundaryinfo % left
2772
BodyIdR = 0; BodyIdL = 0
2773
2774
IF (ASSOCIATED(BulkElementR)) BodyIdR = BulkElementR % BodyId
2775
IF (ASSOCIATED(BulkElementL)) BodyIdL = BulkElementL % BodyId
2776
2777
IF (BodyIdR == 0 .AND. BodyIdL == 0) THEN
2778
RETURN
2779
ELSE IF (BodyIdR > BodyIdL) THEN
2780
BulkElement => BulkElementR
2781
ELSE IF (bodyIdL >= BodyIdR) THEN
2782
BulkElement => BulkElementL
2783
END IF
2784
2785
IF( PRESENT( Found ) ) Found = ASSOCIATED( BulkElement )
2786
2787
!------------------------------------------------------------------------------
2788
END FUNCTION GetBulkElementAtBoundary
2789
!------------------------------------------------------------------------------
2790
2791
2792
!------------------------------------------------------------------------------
2793
!> Returns handle to Material value list of the bulk material meeting
2794
!> element with larger body id. Typically Element is a boundary element.
2795
FUNCTION GetBulkMaterialAtBoundary( Element, Found ) RESULT(Material)
2796
!------------------------------------------------------------------------------
2797
TYPE(Element_t), OPTIONAL :: Element
2798
LOGICAL, OPTIONAL :: Found
2799
TYPE(ValueList_t), POINTER :: Material
2800
!------------------------------------------------------------------------------
2801
TYPE(element_t), POINTER :: BulkElement
2802
LOGICAL :: L
2803
INTEGER :: mat_id
2804
2805
Material => NULL()
2806
2807
BulkElement => GetBulkElementAtBoundary(Element, Found)
2808
2809
IF( ASSOCIATED( BulkElement ) ) THEN
2810
mat_id = GetMaterialId( BulkElement, L )
2811
IF ( L ) Material => CurrentModel % Materials(mat_id) % Values
2812
ELSE
2813
L = .FALSE.
2814
END IF
2815
2816
IF ( PRESENT( Found ) ) Found = L
2817
!------------------------------------------------------------------------------
2818
END FUNCTION GetBulkMaterialAtBoundary
2819
!------------------------------------------------------------------------------
2820
2821
!------------------------------------------------------------------------------
2822
!> Return handle to the Body Force value list of the active element
2823
FUNCTION GetBodyForce( Element, Found ) RESULT(BodyForce)
2824
!------------------------------------------------------------------------------
2825
TYPE(Element_t), OPTIONAL :: Element
2826
LOGICAL, OPTIONAL :: Found
2827
2828
TYPE(ValueList_t), POINTER :: BodyForce
2829
2830
LOGICAL :: l
2831
INTEGER :: bf_id
2832
2833
IF ( PRESENT( Element ) ) THEN
2834
bf_id = GetBodyForceId( Element, L )
2835
ELSE
2836
bf_id = GetBodyForceId( Found=L )
2837
END IF
2838
2839
BodyForce => Null()
2840
IF ( L ) BodyForce => CurrentModel % BodyForces(bf_id) % Values
2841
IF ( PRESENT( Found ) ) Found = L
2842
!------------------------------------------------------------------------------
2843
END FUNCTION GetBodyForce
2844
!------------------------------------------------------------------------------
2845
2846
2847
!> Is the active solver solved in the frequency space
2848
!------------------------------------------------------------------------------
2849
FUNCTION EigenOrHarmonicAnalysis(Usolver) RESULT(L)
2850
LOGICAL :: L
2851
TYPE(Solver_t), OPTIONAL,TARGET :: USolver
2852
!------------------------------------------------------------------------------
2853
TYPE(Solver_t), POINTER :: Solver
2854
2855
IF (PRESENT(USolver)) THEN
2856
Solver => USolver
2857
ELSE
2858
Solver => CurrentModel % Solver
2859
END IF
2860
L = Solver % NOFEigenValues > 0
2861
!------------------------------------------------------------------------------
2862
END FUNCTION EigenOrHarmonicAnalysis
2863
!------------------------------------------------------------------------------
2864
2865
2866
!> Returns the handle to the equation where the active element belongs to
2867
!------------------------------------------------------------------------------
2868
FUNCTION GetEquation( Element, Found ) RESULT(Equation)
2869
!------------------------------------------------------------------------------
2870
TYPE(Element_t), OPTIONAL :: Element
2871
LOGICAL, OPTIONAL :: Found
2872
2873
TYPE(ValueList_t), POINTER :: Equation
2874
2875
LOGICAL :: L
2876
INTEGER :: eq_id
2877
2878
2879
IF ( PRESENT( Element ) ) THEN
2880
eq_id = GetEquationId( Element, L )
2881
ELSE
2882
eq_id = GetEquationId( Found=L )
2883
END IF
2884
2885
NULLIFY( Equation )
2886
IF ( L ) Equation => CurrentModel % Equations(eq_id) % Values
2887
IF ( PRESENT( Found ) ) Found = L
2888
!------------------------------------------------------------------------------
2889
END FUNCTION GetEquation
2890
!------------------------------------------------------------------------------
2891
2892
2893
2894
!> Returns the Boundary Condition index of the active element
2895
!------------------------------------------------------------------------------
2896
FUNCTION GetBCId( UElement ) RESULT(bc_id)
2897
!------------------------------------------------------------------------------
2898
TYPE(Element_t), OPTIONAL, TARGET :: UElement
2899
2900
INTEGER :: bc_id
2901
2902
TYPE(Element_t), POINTER :: Element
2903
2904
Element => GetCurrentElement( UElement )
2905
2906
IF(.NOT. ASSOCIATED( Element % BoundaryInfo ) ) THEN
2907
bc_id = 0
2908
RETURN
2909
END IF
2910
2911
DO bc_id=1,CurrentModel % NumberOfBCs
2912
IF ( Element % BoundaryInfo % Constraint == CurrentModel % BCs(bc_id) % Tag ) EXIT
2913
END DO
2914
2915
IF ( bc_id > CurrentModel % NumberOfBCs ) bc_id=0
2916
!------------------------------------------------------------------------------
2917
END FUNCTION GetBCId
2918
!------------------------------------------------------------------------------
2919
2920
2921
!> Returns handle to the value list of the Boundary Condition where the active element belongs to
2922
!------------------------------------------------------------------------------
2923
FUNCTION GetBC( UElement ) RESULT(bc)
2924
!------------------------------------------------------------------------------
2925
TYPE(Element_t), OPTIONAL, TARGET :: UElement
2926
TYPE(ValueList_t), POINTER :: BC
2927
2928
INTEGER :: bc_id
2929
2930
TYPE(Element_t), POINTER :: Element
2931
2932
Element => GetCurrentElement( UElement )
2933
2934
BC => NULL()
2935
bc_id = GetBCId( Element )
2936
2937
IF ( bc_id > 0 ) BC => CurrentModel % BCs(bc_id) % Values
2938
2939
!------------------------------------------------------------------------------
2940
END FUNCTION GetBC
2941
!------------------------------------------------------------------------------
2942
2943
2944
!> Returns the index of the Initial Condition of the active element
2945
!------------------------------------------------------------------------------
2946
FUNCTION GetICId( Element, Found ) RESULT(ic_id)
2947
!------------------------------------------------------------------------------
2948
LOGICAL, OPTIONAL :: Found
2949
TYPE(Element_t), OPTIONAL :: Element
2950
2951
TYPE(Element_t), POINTER :: CElement
2952
INTEGER :: ic_id, body_id
2953
2954
CElement => GetCurrentElement( Element )
2955
body_id = CElement % BodyId
2956
2957
IF ( PRESENT( Found ) ) THEN
2958
ic_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values, &
2959
'Initial Condition', Found, minv=1,maxv=CurrentModel % NumberOfICs )
2960
ELSE
2961
ic_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values, &
2962
'Initial Condition', minv=1,maxv=CurrentModel % NumberOfICs )
2963
END IF
2964
!------------------------------------------------------------------------------
2965
END FUNCTION GetIcId
2966
!------------------------------------------------------------------------------
2967
2968
!> Returns handle to the value list of the Initial Condition where the active element belongs to
2969
!------------------------------------------------------------------------------
2970
FUNCTION GetIC( Element, Found ) RESULT(IC)
2971
!------------------------------------------------------------------------------
2972
TYPE(Element_t), OPTIONAL :: Element
2973
LOGICAL, OPTIONAL :: Found
2974
2975
TYPE(ValueList_t), POINTER :: IC
2976
2977
LOGICAL :: L
2978
INTEGER :: ic_id
2979
2980
IF ( PRESENT( Element ) ) THEN
2981
ic_id = GetICId( Element, L )
2982
ELSE
2983
ic_id = GetICId( Found=L )
2984
END IF
2985
2986
IC => Null()
2987
IF ( L ) IC => CurrentModel % ICs(ic_id) % Values
2988
IF ( PRESENT( Found ) ) Found = L
2989
!------------------------------------------------------------------------------
2990
END FUNCTION GetIC
2991
!------------------------------------------------------------------------------
2992
2993
!> Add the local matrix entries to for real valued equations that are of first order in time
2994
!------------------------------------------------------------------------------
2995
SUBROUTINE Default1stOrderTimeR( M, A, F, UElement, USolver )
2996
!------------------------------------------------------------------------------
2997
REAL(KIND=dp) :: M(:,:),A(:,:), F(:)
2998
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
2999
TYPE(Element_t), OPTIONAL, TARGET :: UElement
3000
3001
LOGICAL :: Found
3002
TYPE(ValueList_t), POINTER :: Params
3003
3004
TYPE(Solver_t), POINTER :: Solver
3005
TYPE(Variable_t), POINTER :: x
3006
TYPE(Element_t), POINTER :: Element
3007
3008
INTEGER :: n
3009
REAL(KIND=dp) :: dt
3010
INTEGER, POINTER :: Indexes(:)
3011
3012
IF ( PRESENT(USolver) ) THEN
3013
Solver => USolver
3014
ELSE
3015
Solver => CurrentModel % Solver
3016
END IF
3017
3018
Params => GetSolverParams(Solver)
3019
3020
! Antiperiodic elimination and FCT always use this
3021
IF (GetLogical(Params,'Use Global Mass Matrix',Found)) THEN
3022
CALL DefaultUpdateMass(M,UElement,USolver)
3023
RETURN
3024
END IF
3025
3026
Element => GetCurrentElement( UElement )
3027
3028
x => Solver % Variable
3029
3030
dt = Solver % dt
3031
Indexes => GetIndexStore()
3032
n = GetElementDOFs( Indexes,Element,Solver )
3033
3034
CALL Add1stOrderTime( M, A, F, dt, n, x % DOFs, &
3035
x % Perm(Indexes(1:n)), Solver, UElement=Element )
3036
3037
!------------------------------------------------------------------------------
3038
END SUBROUTINE Default1stOrderTimeR
3039
!------------------------------------------------------------------------------
3040
3041
!> Add the local matrix entries to for complex valued equations that are of first order in time
3042
!------------------------------------------------------------------------------
3043
SUBROUTINE Default1stOrderTimeC( MC, AC, FC, UElement, USolver )
3044
!------------------------------------------------------------------------------
3045
COMPLEX(KIND=dp) :: MC(:,:),AC(:,:), FC(:)
3046
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
3047
TYPE(Element_t), OPTIONAL, TARGET :: UElement
3048
3049
TYPE(Solver_t), POINTER :: Solver
3050
TYPE(Variable_t), POINTER :: x
3051
TYPE(Element_t), POINTER :: Element
3052
3053
REAL(KIND=dp), ALLOCATABLE :: M(:,:),A(:,:), F(:)
3054
3055
LOGICAL :: Found
3056
TYPE(ValueList_t), POINTER :: Params
3057
3058
INTEGER :: i,j,n,DOFs
3059
REAL(KIND=dp) :: dt
3060
INTEGER, POINTER :: Indexes(:)
3061
3062
IF ( PRESENT(USolver) ) THEN
3063
Solver => USolver
3064
ELSE
3065
Solver => CurrentModel % Solver
3066
END IF
3067
3068
Params=>GetSolverParams(Solver)
3069
3070
IF (GetLogical(Params,'Use Global Mass Matrix',Found)) THEN
3071
CALL DefaultUpdateMass(M,UElement,USolver)
3072
RETURN
3073
END IF
3074
3075
Element => GetCurrentElement( UElement )
3076
3077
x => Solver % Variable
3078
3079
dt = Solver % dt
3080
DOFs = x % DOFs
3081
Indexes => GetIndexStore()
3082
n = GetElementDOFs( Indexes,Element,Solver )
3083
3084
ALLOCATE( M(DOFs*n,DOFs*n), A(DOFs*n,DOFs*n), F(DOFs*n) )
3085
DO i=1,n*DOFs/2
3086
F( 2*(i-1)+1 ) = REAL( FC(i) )
3087
F( 2*(i-1)+2 ) = AIMAG( FC(i) )
3088
3089
DO j=1,n*DOFs/2
3090
M( 2*(i-1)+1, 2*(j-1)+1 ) = REAL( MC(i,j) )
3091
M( 2*(i-1)+1, 2*(j-1)+2 ) = -AIMAG( MC(i,j) )
3092
M( 2*(i-1)+2, 2*(j-1)+1 ) = AIMAG( MC(i,j) )
3093
M( 2*(i-1)+2, 2*(j-1)+2 ) = REAL( MC(i,j) )
3094
A( 2*(i-1)+1, 2*(j-1)+1 ) = REAL( AC(i,j) )
3095
A( 2*(i-1)+1, 2*(j-1)+2 ) = -AIMAG( AC(i,j) )
3096
A( 2*(i-1)+2, 2*(j-1)+1 ) = AIMAG( AC(i,j) )
3097
A( 2*(i-1)+2, 2*(j-1)+2 ) = REAL( AC(i,j) )
3098
END DO
3099
END DO
3100
3101
CALL Add1stOrderTime( M, A, F, dt, n, x % DOFs, &
3102
x % Perm(Indexes(1:n)), Solver, UElement=Element )
3103
3104
DO i=1,n*DOFs/2
3105
FC(i) = CMPLX( F(2*(i-1)+1), F(2*(i-1)+2),KIND=dp )
3106
DO j=1,n*DOFs/2
3107
MC(i,j) = CMPLX(M(2*(i-1)+1,2*(j-1)+1), -M(2*(i-1)+1,2*(j-1)+2), KIND=dp)
3108
AC(i,j) = CMPLX(A(2*(i-1)+1,2*(j-1)+1), -A(2*(i-1)+1,2*(j-1)+2), KIND=dp)
3109
END DO
3110
END DO
3111
3112
DEALLOCATE( M, A, F )
3113
!------------------------------------------------------------------------------
3114
END SUBROUTINE Default1stOrderTimeC
3115
!------------------------------------------------------------------------------
3116
3117
3118
!------------------------------------------------------------------------------
3119
SUBROUTINE Default1stOrderTimeGlobal(USolver)
3120
!------------------------------------------------------------------------------
3121
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
3122
!------------------------------------------------------------------------------
3123
CHARACTER(:), ALLOCATABLE :: Method
3124
TYPE(Solver_t), POINTER :: Solver
3125
INTEGER :: i,j,k,l,n,Order
3126
REAL(KIND=dp), POINTER :: SaveValues(:) => NULL()
3127
REAL(KIND=dp) :: FORCE(1), Dts(16)
3128
LOGICAL :: ConstantDt, Found, HasMass, HasFCT
3129
TYPE(Variable_t), POINTER :: DtVar
3130
SAVE STIFF, MASS, X
3131
REAL(KIND=dp), ALLOCATABLE :: STIFF(:,:),MASS(:,:), X(:,:)
3132
3133
!$OMP THREADPRIVATE(SaveValues)
3134
3135
IF ( PRESENT(USolver) ) THEN
3136
Solver => Usolver
3137
ELSE
3138
Solver => CurrentModel % solver
3139
END IF
3140
3141
Order = MAX( MIN( Solver % DoneTime, Solver % Order ), 1)
3142
HasMass = ASSOCIATED( Solver % Matrix % MassValues )
3143
3144
HasFCT = ListGetLogical( Solver % Values,'Linear System FCT', Found )
3145
3146
IF( HasFCT ) THEN
3147
IF( .NOT. HasMass ) THEN
3148
CALL Fatal('Default1stOrderTimeGlobal','FCT only makes sense if there is a mass matrix!')
3149
ELSE
3150
IF(.NOT. ASSOCIATED( Solver % Matrix % MassValuesLumped ) ) THEN
3151
CALL Fatal('Default1stOrderTimeGlobal','FCT requires a lumped mass matrix!')
3152
END IF
3153
HasMass = .FALSE.
3154
END IF
3155
END IF
3156
3157
! This is now the default global time integration routine but the old hack may still be called
3158
!---------------------------------------------------------------------------------------------
3159
IF( .NOT. ListGetLogical( Solver % Values,'Old Global Time Integration',Found ) ) THEN
3160
CALL Add1stOrderTime_CRS( Solver % Matrix, Solver % Matrix % rhs, &
3161
Solver % dt, Solver )
3162
RETURN
3163
END IF
3164
3165
3166
! The rest of the code in this subroutine is obsolete
3167
IF ( .NOT.ASSOCIATED(Solver % Variable % Values, SaveValues) ) THEN
3168
IF ( ALLOCATED(STIFF) ) DEALLOCATE( STIFF,MASS,X )
3169
n = 0
3170
DO i=1,Solver % Matrix % NumberOfRows
3171
n = MAX( n,Solver % Matrix % Rows(i+1)-Solver % Matrix % Rows(i) )
3172
END DO
3173
k = SIZE(Solver % Variable % PrevValues,2)
3174
ALLOCATE( STIFF(1,n),MASS(1,n),X(n,k) )
3175
SaveValues => Solver % Variable % Values
3176
END IF
3177
3178
STIFF = 0.0_dp
3179
MASS = 0.0_dp
3180
X = 0.0_dp
3181
3182
Method = GetString( Solver % Values, 'Timestepping Method', Found )
3183
IF ( Method == 'bdf' ) THEN
3184
Dts(1) = Solver % Dt
3185
ConstantDt = .TRUE.
3186
IF(Order > 1) THEN
3187
DtVar => VariableGet( Solver % Mesh % Variables, 'Timestep size' )
3188
DO i=2,Order
3189
Dts(i) = DtVar % PrevValues(1,i-1)
3190
IF(ABS(Dts(i)-Dts(1)) > 1.0d-6 * Dts(1)) ConstantDt = .FALSE.
3191
END DO
3192
END IF
3193
END IF
3194
3195
DO i=1,Solver % Matrix % NumberOFRows
3196
n = 0
3197
k = 0
3198
3199
DO j=Solver % Matrix % Rows(i),Solver % Matrix % Rows(i+1)-1
3200
n = n+1
3201
STIFF(1,n) = Solver % Matrix % Values(j)
3202
IF( HasMass ) THEN
3203
MASS(1,n) = Solver % Matrix % MassValues(j)
3204
ELSE IF( HasFCT ) THEN
3205
IF( j == Solver % Matrix % Diag(i) ) k = n
3206
END IF
3207
X(n,:) = Solver % Variable % PrevValues(Solver % Matrix % Cols(j),:)
3208
END DO
3209
3210
! Use lumped mass in lower order fct
3211
IF( HasFCT ) THEN
3212
IF( k == 0 ) THEN
3213
CALL Fatal('Default1stOrderTimeGlobal','Could not find diagonal entry for fct')
3214
ELSE
3215
MASS(1,k) = Solver % Matrix % MassValuesLumped(i)
3216
END IF
3217
END IF
3218
3219
FORCE(1) = Solver % Matrix % RHS(i)
3220
Solver % Matrix % Force(i,1) = FORCE(1)
3221
3222
SELECT CASE( Method )
3223
CASE( 'fs' )
3224
CALL FractionalStep( n, Solver % dt, MASS, STIFF, FORCE, &
3225
X(:,1), Solver % Beta, Solver )
3226
3227
CASE('bdf')
3228
IF(ConstantDt) THEN
3229
CALL BDFLocal( n, Solver % dt, MASS, STIFF, FORCE, X, Order )
3230
ELSE
3231
CALL VBDFLocal(n, Dts, MASS, STIFF, FORCE, X, Order )
3232
END IF
3233
3234
CASE DEFAULT
3235
CALL NewmarkBeta( n, Solver % dt, MASS, STIFF, FORCE, &
3236
X(:,1), Solver % Beta )
3237
END SELECT
3238
3239
IF( HasFCT ) MASS(1,k) = 0.0_dp
3240
3241
n = 0
3242
DO j=Solver % Matrix % Rows(i),Solver % Matrix % Rows(i+1)-1
3243
n=n+1
3244
Solver % Matrix % Values(j) = STIFF(1,n)
3245
END DO
3246
Solver % Matrix % RHS(i) = FORCE(1)
3247
END DO
3248
3249
!----------------------------------------------------------------------------
3250
END SUBROUTINE Default1stOrderTimeGlobal
3251
!----------------------------------------------------------------------------
3252
3253
!------------------------------------------------------------------------------
3254
SUBROUTINE Default2ndOrderTimeGlobal(USolver)
3255
!------------------------------------------------------------------------------
3256
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
3257
!------------------------------------------------------------------------------
3258
TYPE(Solver_t), POINTER :: Solver
3259
INTEGER :: i,j,k,l,n
3260
REAL(KIND=dp), POINTER :: SaveValues(:) => NULL()
3261
REAL(KIND=dp) :: FORCE(1)
3262
LOGICAL :: Found, HasDamping, HasMass
3263
REAL(KIND=dp), ALLOCATABLE, SAVE :: STIFF(:,:),MASS(:,:), DAMP(:,:), X(:,:)
3264
!OMP THREADPRIVATE(SaveValues)
3265
3266
IF ( PRESENT(USolver) ) THEN
3267
Solver => Usolver
3268
ELSE
3269
Solver => CurrentModel % solver
3270
END IF
3271
3272
! This is now the default global time integration routine but the old hack may still be called
3273
!---------------------------------------------------------------------------------------------
3274
IF( .NOT. ListGetLogical( Solver % Values,'Old Global Time Integration',Found ) ) THEN
3275
CALL Add2ndOrderTime_CRS( Solver % Matrix, Solver % Matrix % rhs, &
3276
Solver % dt, Solver % Variable % PrevValues, Solver )
3277
RETURN
3278
END IF
3279
3280
3281
IF ( .NOT.ASSOCIATED(Solver % Variable % Values, SaveValues) ) THEN
3282
IF ( ALLOCATED(STIFF) ) DEALLOCATE( STIFF,MASS,DAMP,X )
3283
n = 0
3284
DO i=1,Solver % Matrix % NumberOfRows
3285
n = MAX( n,Solver % Matrix % Rows(i+1)-Solver % Matrix % Rows(i) )
3286
END DO
3287
k = SIZE(Solver % Variable % PrevValues,2)
3288
ALLOCATE( STIFF(1,n),MASS(1,n),DAMP(1,n),X(n,k) )
3289
SaveValues => Solver % Variable % Values
3290
3291
STIFF = 0.0_dp
3292
MASS = 0.0_dp
3293
DAMP = 0.0_dp
3294
X = 0.0_dp
3295
END IF
3296
3297
HasDamping = ASSOCIATED(Solver % Matrix % DampValues )
3298
HasMass = ASSOCIATED(Solver % Matrix % MassValues )
3299
3300
DO i=1,Solver % Matrix % NumberOFRows
3301
n = 0
3302
DO j=Solver % Matrix % Rows(i),Solver % Matrix % Rows(i+1)-1
3303
n=n+1
3304
IF( HasMass ) MASS(1,n) = Solver % Matrix % MassValues(j)
3305
IF( HasDamping ) DAMP(1,n) = Solver % Matrix % DampValues(j)
3306
STIFF(1,n) = Solver % Matrix % Values(j)
3307
X(n,:) = Solver % Variable % PrevValues(Solver % Matrix % Cols(j),:)
3308
END DO
3309
FORCE(1) = Solver % Matrix % RHS(i)
3310
Solver % Matrix % Force(i,1) = FORCE(1)
3311
3312
CALL Time2ndOrder( n, Solver % dt, MASS, DAMP, STIFF, &
3313
FORCE, X(1:n,3), X(1:n,4), X(1:n,5), X(1:n,7), Solver % Alpha, Solver % Beta )
3314
3315
n = 0
3316
DO j=Solver % Matrix % Rows(i),Solver % Matrix % Rows(i+1)-1
3317
n=n+1
3318
Solver % Matrix % Values(j) = STIFF(1,n)
3319
END DO
3320
Solver % Matrix % RHS(i) = FORCE(1)
3321
END DO
3322
!----------------------------------------------------------------------------
3323
END SUBROUTINE Default2ndOrderTimeGlobal
3324
!----------------------------------------------------------------------------
3325
3326
3327
!------------------------------------------------------------------------------
3328
SUBROUTINE Default2ndOrderTimeR( M, B, A, F, UElement, USolver )
3329
!------------------------------------------------------------------------------
3330
REAL(KIND=dp) :: M(:,:), B(:,:), A(:,:), F(:)
3331
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
3332
TYPE(Element_t), OPTIONAL, TARGET :: UElement
3333
3334
TYPE(Solver_t), POINTER :: Solver
3335
TYPE(Variable_t), POINTER :: x
3336
TYPE(Element_t), POINTER :: Element
3337
3338
LOGICAL :: Found
3339
TYPE(ValueList_t), POINTER :: Params
3340
3341
INTEGER :: n
3342
REAL(KIND=dp) :: dt
3343
INTEGER, POINTER :: Indexes(:)
3344
3345
Solver => CurrentModel % Solver
3346
IF ( PRESENT(USolver) ) Solver => USolver
3347
3348
Params=>GetSolverParams(Solver)
3349
3350
IF (GetLogical(Params,'Use Global Mass Matrix',Found)) THEN
3351
CALL DefaultUpdateMass(M,UElement,USolver)
3352
CALL DefaultUpdateDamp(B,UElement,USolver)
3353
RETURN
3354
END IF
3355
3356
Element => GetCurrentElement( UElement )
3357
3358
x => Solver % Variable
3359
3360
dt = Solver % dt
3361
Indexes => GetIndexStore()
3362
n = GetElementDOFs( Indexes, Element, Solver )
3363
3364
CALL Add2ndOrderTime( M, B, A, F, dt, n, x % DOFs, &
3365
x % Perm(Indexes(1:n)), Solver )
3366
!------------------------------------------------------------------------------
3367
END SUBROUTINE Default2ndOrderTimeR
3368
!------------------------------------------------------------------------------
3369
3370
3371
3372
!------------------------------------------------------------------------------
3373
SUBROUTINE Default2ndOrderTimeC( MC, BC, AC, FC, UElement, USolver )
3374
!------------------------------------------------------------------------------
3375
COMPLEX(KIND=dp) :: MC(:,:), BC(:,:), AC(:,:), FC(:)
3376
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
3377
TYPE(Element_t), OPTIONAL, TARGET :: UElement
3378
3379
TYPE(Solver_t), POINTER :: Solver
3380
TYPE(Variable_t), POINTER :: x
3381
TYPE(Element_t), POINTER :: Element
3382
REAL(KIND=dp), ALLOCATABLE :: M(:,:), B(:,:), A(:,:), F(:)
3383
3384
LOGICAL :: Found
3385
TYPE(ValueList_t), POINTER :: Params
3386
3387
INTEGER :: i,j,n,DOFs
3388
REAL(KIND=dp) :: dt
3389
INTEGER, POINTER :: Indexes(:)
3390
3391
Solver => CurrentModel % Solver
3392
IF ( PRESENT(USolver) ) Solver => USolver
3393
3394
Params=>GetSolverParams(Solver)
3395
3396
IF (GetLogical(Params,'Use Global Mass Matrix',Found)) THEN
3397
CALL DefaultUpdateMass(M,UElement,USolver)
3398
CALL DefaultUpdateDamp(B,UElement,USolver)
3399
RETURN
3400
END IF
3401
3402
Element => GetCurrentElement( UElement )
3403
3404
x => Solver % Variable
3405
3406
dt = Solver % dt
3407
DOFs = x % DOFs
3408
Indexes => GetIndexStore()
3409
n = GetElementDOFs( Indexes, Element, Solver )
3410
3411
ALLOCATE( M(DOFs*n,DOFs*n), A(DOFs*n,DOFs*n), B(DOFs*n,DOFs*n), F(DOFs*n) )
3412
DO i=1,n*DOFs/2
3413
F( 2*(i-1)+1 ) = REAL( FC(i) )
3414
F( 2*(i-1)+2 ) = AIMAG( FC(i) )
3415
3416
DO j=1,n*DOFs/2
3417
M(2*(i-1)+1, 2*(j-1)+1) = REAL( MC(i,j) )
3418
M(2*(i-1)+1, 2*(j-1)+2) = -AIMAG( MC(i,j) )
3419
M(2*(i-1)+2, 2*(j-1)+1) = AIMAG( MC(i,j) )
3420
M(2*(i-1)+2, 2*(j-1)+2) = REAL( MC(i,j) )
3421
B(2*(i-1)+1, 2*(j-1)+1) = REAL( BC(i,j) )
3422
B(2*(i-1)+1, 2*(j-1)+2) = -AIMAG( BC(i,j) )
3423
B(2*(i-1)+2, 2*(j-1)+1) = AIMAG( BC(i,j) )
3424
B(2*(i-1)+2, 2*(j-1)+2) = REAL( BC(i,j) )
3425
A(2*(i-1)+1, 2*(j-1)+1) = REAL( AC(i,j) )
3426
A(2*(i-1)+1, 2*(j-1)+2) = -AIMAG( AC(i,j) )
3427
A(2*(i-1)+2, 2*(j-1)+1) = AIMAG( AC(i,j) )
3428
A(2*(i-1)+2, 2*(j-1)+2) = REAL( AC(i,j) )
3429
END DO
3430
END DO
3431
3432
CALL Add2ndOrderTime( M, B, A, F, dt, n, x % DOFs, &
3433
x % Perm(Indexes(1:n)), Solver )
3434
3435
DO i=1,n*DOFs/2
3436
FC(i) = CMPLX( F(2*(i-1)+1), F(2*(i-1)+2), KIND=dp )
3437
DO j=1,n*DOFs/2
3438
MC(i,j) = CMPLX( M(2*(i-1)+1, 2*(j-1)+1), -M(2*(i-1)+1, 2*(j-1)+2), KIND=dp )
3439
BC(i,j) = CMPLX( B(2*(i-1)+1, 2*(j-1)+1), -B(2*(i-1)+1, 2*(j-1)+2), KIND=dp )
3440
AC(i,j) = CMPLX( A(2*(i-1)+1, 2*(j-1)+1), -A(2*(i-1)+1, 2*(j-1)+2), KIND=dp )
3441
END DO
3442
END DO
3443
3444
DEALLOCATE( M, B, A, F )
3445
!------------------------------------------------------------------------------
3446
END SUBROUTINE Default2ndOrderTimeC
3447
!------------------------------------------------------------------------------
3448
3449
3450
!--------------------------------------------------------------------------------
3451
!> One can enforce weak coupling by calling a dependent solver a.k.a. slave solver
3452
!> at different stages of the master solver: e.g. before and after the solver.
3453
!> The strategy can be particularly efficient for nonlinear problems when the
3454
!> slave solver is cheap and a stepsize control is applied.
3455
!> Also one can easily make postprocessing steps just at the correct slot.
3456
!-----------------------------------------------------------------------------
3457
RECURSIVE SUBROUTINE DefaultSlaveSolvers( Solver, SlaveSolverStr)
3458
!------------------------------------------------------------------------------
3459
TYPE(Solver_t), POINTER :: Solver
3460
CHARACTER(LEN=*) :: SlaveSolverStr
3461
3462
TYPE(Solver_t), POINTER :: SlaveSolver
3463
TYPE(ValueList_t), POINTER :: Params
3464
TYPE(Variable_t), POINTER :: iterV
3465
INTEGER, POINTER :: SlaveSolverIndexes(:)
3466
INTEGER :: j,k,iter
3467
REAL(KIND=dp) :: dt
3468
LOGICAL :: Transient, Found, alloc_parenv
3469
3470
TYPE(ParEnv_t), POINTER :: SParEnv
3471
3472
INTERFACE
3473
SUBROUTINE SolverActivate_x(Model,Solver,dt,Transient)
3474
USE Types
3475
TYPE(Model_t)::Model
3476
TYPE(Solver_t),POINTER::Solver
3477
REAL(KIND=dp) :: dt
3478
LOGICAL :: Transient
3479
END SUBROUTINE SolverActivate_x
3480
END INTERFACE
3481
3482
SlaveSolverIndexes => ListGetIntegerArray( Solver % Values,&
3483
SlaveSolverStr,Found )
3484
IF(.NOT. Found ) RETURN
3485
3486
CALL Info('DefaultSlaveSolvers','Executing slave solvers: '// &
3487
TRIM(SlaveSolverStr),Level=6)
3488
3489
dt = GetTimeStepsize()
3490
Transient = GetString(CurrentModel % Simulation,'Simulation type',Found)=='transient'
3491
3492
! store the nonlinear iteration at the outer loop
3493
iterV => VariableGet( Solver % Mesh % Variables, 'nonlin iter' )
3494
iter = NINT(iterV % Values(1))
3495
3496
3497
DO j=1,SIZE(SlaveSolverIndexes)
3498
k = SlaveSolverIndexes(j)
3499
SlaveSolver => CurrentModel % Solvers(k)
3500
3501
CALL Info('DefaultSlaveSolvers','Calling slave solver: '//I2S(k),Level=8)
3502
3503
IF( ListGetLogical( Solver % Values,'Monolithic Slave',Found ) ) THEN
3504
IF(.NOT. ListCheckPresent( SlaveSolver % Values,'Linear System Solver Disabled') ) THEN
3505
CALL Info('DefaultSlaveSolvers','Disabling linear system solver for slave: '//I2S(k),Level=6)
3506
CALL ListAddLogical(SlaveSolver % Values,'Linear System Solver Disabled',.TRUE.)
3507
END IF
3508
END IF
3509
3510
IF(ParEnv % PEs>1) THEN
3511
SParEnv => ParEnv
3512
3513
IF(ASSOCIATED(SlaveSolver % Matrix)) THEN
3514
IF(ASSOCIATED(SlaveSolver % Matrix % ParMatrix) ) THEN
3515
ParEnv => SlaveSolver % Matrix % ParMatrix % ParEnv
3516
ELSE
3517
ParEnv % ActiveComm = SlaveSolver % Matrix % Comm
3518
END IF
3519
ELSE
3520
CALL ListAddLogical( SlaveSolver % Values, 'Slave not parallel', .TRUE.)
3521
END IF
3522
END IF
3523
3524
CurrentModel % Solver => SlaveSolver
3525
CALL SolverActivate_x( CurrentModel,SlaveSolver,dt,Transient)
3526
3527
IF(ParEnv % PEs>1) THEN
3528
ParEnv => SParEnv
3529
END IF
3530
END DO
3531
iterV % Values = iter
3532
CurrentModel % Solver => Solver
3533
3534
END SUBROUTINE DefaultSlaveSolvers
3535
!------------------------------------------------------------------------------
3536
3537
3538
3539
!> Performs initialization for matrix equation related to the active solver
3540
!------------------------------------------------------------------------------
3541
RECURSIVE SUBROUTINE DefaultInitialize( USolver, UseConstantBulk )
3542
!------------------------------------------------------------------------------
3543
TYPE(Solver_t), OPTIONAL, TARGET, INTENT(IN) :: USolver
3544
LOGICAL, OPTIONAL :: UseConstantBulk
3545
!------------------------------------------------------------------------------
3546
TYPE(Solver_t), POINTER :: Solver
3547
INTEGER :: i,n
3548
LOGICAL :: Found
3549
3550
IF ( PRESENT( USolver ) ) THEN
3551
Solver => USolver
3552
ELSE
3553
Solver => CurrentModel % Solver
3554
END IF
3555
3556
IF(.NOT. ASSOCIATED( Solver % Matrix ) ) THEN
3557
CALL Fatal('DefaultInitialize','No matrix exists, cannot initialize!')
3558
END IF
3559
3560
IF( PRESENT( UseConstantBulk ) ) THEN
3561
IF ( UseConstantBulk ) THEN
3562
IF (.NOT. ASSOCIATED( Solver % Matrix % BulkRhs ) ) THEN
3563
Solver % Matrix % rhs = 0.0d0
3564
END IF
3565
3566
CALL Info('DefaultInitialize','Using constant bulk matrix',Level=8)
3567
IF (.NOT. ASSOCIATED( Solver % Matrix % BulkValues ) ) THEN
3568
CALL Warn('DefaultInitialize','Constant bulk system requested but not associated!')
3569
RETURN
3570
END IF
3571
3572
CALL RestoreBulkMatrix(Solver % Matrix)
3573
RETURN
3574
END IF
3575
END IF
3576
3577
IF( ListGetLogical( Solver % Values,'Apply Explicit Control', Found )) THEN
3578
CALL ApplyExplicitControl( Solver )
3579
END IF
3580
3581
3582
CALL DefaultSlaveSolvers(Solver,'Slave Solvers') ! this is the initial name of the slot
3583
CALL DefaultSlaveSolvers(Solver,'Nonlinear Pre Solvers')
3584
3585
3586
! If we changed the system last time to harmonic one then revert back the real system
3587
IF( ListGetLogical( Solver % Values,'Harmonic Mode',Found ) ) THEN
3588
CALL ChangeToHarmonicSystem( Solver, .TRUE. )
3589
END IF
3590
3591
CALL InitializeToZero( Solver % Matrix, Solver % Matrix % RHS )
3592
3593
IF(ASSOCIATED(Solver % Matrix % RhsAdjoint) ) THEN
3594
Solver % Matrix % RhsAdjoint = 0.0_dp
3595
END IF
3596
3597
IF( ALLOCATED(Solver % Matrix % ConstrainedDOF) ) THEN
3598
Solver % Matrix % ConstrainedDOF = .FALSE.
3599
END IF
3600
3601
IF( ALLOCATED(Solver % Matrix % Dvalues) ) THEN
3602
Solver % Matrix % Dvalues = 0._dp
3603
END IF
3604
3605
IF( ListGetLogical( Solver % Values,'Bulk Assembly Timing',Found ) ) THEN
3606
CALL ResetTimer('BulkAssembly'//GetVarName(Solver % Variable) )
3607
END IF
3608
3609
! This is a slot for calling solver that contribute to the assembly
3610
CALL DefaultSlaveSolvers(Solver,'Assembly Solvers')
3611
3612
!------------------------------------------------------------------------------
3613
END SUBROUTINE DefaultInitialize
3614
!------------------------------------------------------------------------------
3615
3616
3617
3618
!> Performs pre-steps related to the active solver
3619
!------------------------------------------------------------------------------
3620
RECURSIVE SUBROUTINE DefaultStart( USolver )
3621
!------------------------------------------------------------------------------
3622
TYPE(Solver_t), OPTIONAL, TARGET, INTENT(IN) :: USolver
3623
TYPE(Solver_t), POINTER :: Solver
3624
LOGICAL :: Found
3625
TYPE(ValueList_t), POINTER :: Params
3626
INTEGER :: i,j,n
3627
TYPE(Matrix_t), POINTER :: pMatrix
3628
3629
IF ( PRESENT( USolver ) ) THEN
3630
Solver => USolver
3631
ELSE
3632
Solver => CurrentModel % Solver
3633
END IF
3634
3635
Params => Solver % Values
3636
3637
CALL Info('DefaultStart','Starting solver: '//&
3638
GetString(Params,'Equation'),Level=10)
3639
3640
! Code for splitting the mesh to be able to integrate accurately over discontinuous
3641
! fields defined by zero levelset.
3642
IF( ListGetLogical( Params,'CutFEM',Found ) ) THEN
3643
pMatrix => Solver % Matrix
3644
CALL CreateCutFEMPerm(Solver,.TRUE.)
3645
Solver % Matrix => CreateCutFEMMatrix(Solver,Solver % Variable % Perm, pMatrix )
3646
CALL FreeMatrix(pMatrix)
3647
IF(.NOT. ListGetLogical( Params,'CutFEM Solver',Found ) ) THEN
3648
CALL CreateCutFEMAddMesh(Solver)
3649
END IF
3650
END IF
3651
3652
! When Newton linearization is used we may reset it after previously visiting the solver
3653
IF( Solver % NewtonActive ) THEN
3654
IF( ListGetLogical( Params,'Nonlinear System Reset Newton', Found) ) Solver % NewtonActive = .FALSE.
3655
END IF
3656
3657
IF( ListGetLogical( Params,'Nonlinear System Nullify Guess', Found ) ) THEN
3658
Solver % Variable % Values = 0.0_dp
3659
END IF
3660
3661
! If we changed the system last time to harmonic one then revert back the real system
3662
IF( ListGetLogical( Params,'Harmonic Mode',Found ) ) THEN
3663
CALL ChangeToHarmonicSystem( Solver, .TRUE. )
3664
END IF
3665
3666
! One can run preprocessing solver in this slot.
3667
!-----------------------------------------------------------------------------
3668
CALL DefaultSlaveSolvers(Solver,'Pre Solvers')
3669
3670
IF( ListGetLogical(Params,'Local Matrix Storage',Found ) ) THEN
3671
IF(.NOT. ASSOCIATED(Solver % InvActiveElements) ) THEN
3672
ALLOCATE( Solver % InvActiveElements( Solver % Mesh % NumberOfBulkElements &
3673
+ Solver % Mesh % NumberOFBoundaryElements ) )
3674
Solver % InvActiveElements = 0
3675
DO i=1,Solver % NumberOfActiveElements
3676
Solver % InvActiveElements( Solver % ActiveElements(i) ) = i
3677
END DO
3678
END IF
3679
3680
n = Solver % NumberOfActiveElements
3681
IF(ASSOCIATED(Solver % LocalSystem)) THEN
3682
IF(SIZE(Solver % LocalSystem) < n ) DEALLOCATE(Solver % LocalSystem)
3683
END IF
3684
IF(.NOT. ASSOCIATED(Solver % LocalSystem ) ) THEN
3685
CALL Info('DefaultStart','Allocating local storage of size: '//I2S(n),Level=7)
3686
ALLOCATE( Solver % LocalSystem(n) )
3687
Solver % LocalSystem(1:n) % eind = 0
3688
! If the stiffness matrix is constant the 1st element gives stiffness matrix for all!
3689
! This could be inherited differently too for splitted meshes, for example.
3690
IF( ListGetLogical( Params,'Local Matrix Identical', Found ) ) THEN
3691
CALL Info('DefaultStart','Assuming all elements to be identical!')
3692
Solver % LocalSystem(1:n) % eind = 1
3693
ELSE IF( ListGetLogical( Params,'Local Matrix Identical Bodies', Found ) ) THEN
3694
CALL Info('DefaultStart','Assuming all elements to be identical within bodies!')
3695
BLOCK
3696
INTEGER, ALLOCATABLE :: Body1st(:)
3697
ALLOCATE(Body1st(CurrentModel % NumberOfBodies))
3698
Body1st = 0
3699
DO i=1,Solver % NumberOfActiveElements
3700
j = Solver % Mesh % Elements(Solver % ActiveElements(i)) % BodyId
3701
IF(Body1st(j) == 0) Body1st(j) = i
3702
Solver % LocalSystem(i) % eind = Body1st(j)
3703
END DO
3704
END BLOCK
3705
END IF
3706
END IF
3707
3708
Solver % LocalSystemMode = 1
3709
END IF
3710
3711
IF(ListGetLogical( Params,'Solve Adjoint Equation',Found ) ) THEN
3712
IF(.NOT. ASSOCIATED( Solver % Matrix % RhsAdjoint ) ) THEN
3713
ALLOCATE( Solver % Matrix % RhsAdjoint(SIZE(Solver % Matrix % Rhs)))
3714
END IF
3715
CALL ListAddLogical( Params,'Constraint Modes Analysis Frozen',.TRUE.)
3716
END IF
3717
3718
3719
BLOCK
3720
INTEGER, POINTER :: SlaveSolverIndexes(:)
3721
CHARACTER(:), ALLOCATABLE :: str
3722
TYPE(Solver_t), POINTER :: SlaveSolver
3723
TYPE(NormalTangential_t), POINTER :: NT
3724
INTEGER :: dim
3725
3726
SlaveSolverIndexes => ListGetIntegerArray( Params,'prec solvers',Found )
3727
3728
IF(ASSOCIATED(SlaveSolverIndexes)) THEN
3729
DO i=1,SIZE(SlaveSolverIndexes)
3730
j = SlaveSolverIndexes(i)
3731
SlaveSolver => CurrentModel % Solvers(j)
3732
3733
str = 'Normal-Tangential ' // GetVarName(SlaveSolver % Variable)
3734
IF( ListGetLogicalAnyBC( CurrentModel, str ) ) THEN
3735
CALL Info('DefaultStart','Generating N-T system for preconditioning solver!')
3736
3737
dim = SlaveSolver % Mesh % MeshDim
3738
NT => SlaveSolver % NormalTangential
3739
NT % NormalTangentialNOFNodes = 0
3740
NT % NormalTangentialName = TRIM(str)
3741
3742
CALL CheckNormalTangentialBoundary( CurrentModel, NT % NormalTangentialName, &
3743
NT % NormalTangentialNOFNodes, NT % BoundaryReorder, &
3744
NT % BoundaryNormals, NT % BoundaryTangent1, NT % BoundaryTangent2, dim )
3745
3746
CALL AverageBoundaryNormals( CurrentModel, NT % NormalTangentialName, &
3747
NT % NormalTangentialNOFNodes, NT % BoundaryReorder, &
3748
NT % BoundaryNormals, NT % BoundaryTangent1, NT % BoundaryTangent2, &
3749
dim )
3750
END IF
3751
END DO
3752
3753
END IF
3754
END BLOCK
3755
3756
!------------------------------------------------------------------------------
3757
END SUBROUTINE DefaultStart
3758
!------------------------------------------------------------------------------
3759
3760
3761
3762
!> Performs finalizing steps related to the active solver
3763
!------------------------------------------------------------------------------
3764
RECURSIVE SUBROUTINE DefaultFinish( USolver )
3765
!------------------------------------------------------------------------------
3766
TYPE(Solver_t), OPTIONAL, TARGET, INTENT(IN) :: USolver
3767
TYPE(Solver_t), POINTER :: Solver
3768
TYPE(ValueList_t), POINTER :: Params
3769
TYPE(Mesh_t), POINTER :: Mesh
3770
CHARACTER(:), ALLOCATABLE :: str
3771
LOGICAL :: Found, SolveAdjoint
3772
3773
IF ( PRESENT( USolver ) ) THEN
3774
Solver => USolver
3775
ELSE
3776
Solver => CurrentModel % Solver
3777
END IF
3778
3779
Params => Solver % Values
3780
3781
IF ( ListGetLogical( Params,'Linear System Save',Found )) THEN
3782
str = GetString( Params,'Linear System Save Slot', Found )
3783
IF(Found .AND. str == 'finish') THEN
3784
CALL SaveLinearSystem( Solver )
3785
END IF
3786
END IF
3787
3788
! One can run postprocessing solver in this slot.
3789
!-----------------------------------------------------------------------------
3790
CALL DefaultSlaveSolvers(Solver,'Post Solvers')
3791
3792
IF( ListGetLogical( Params,'Apply Explicit Control', Found )) THEN
3793
CALL ApplyExplicitControl( Solver )
3794
END IF
3795
3796
3797
SolveAdjoint = ListGetLogical(Params,'Solve Adjoint Equation', Found )
3798
3799
IF( SolveAdjoint ) THEN
3800
BLOCK
3801
INTEGER :: n
3802
REAL(KIND=dp) :: Norm
3803
REAL(KIND=dp), ALLOCATABLE :: xtmp(:), btmp(:)
3804
REAL(KIND=dp), POINTER :: AdjSol(:)
3805
TYPE(Variable_t), POINTER :: aVar
3806
TYPE(Mesh_t), POINTER :: Mesh
3807
3808
n = SIZE(Solver % Matrix % rhs)
3809
CALL ListAddLogical(Params,'Skip Compute Nonlinear Change',.TRUE.)
3810
3811
3812
Mesh => Solver % Mesh
3813
aVar => VariableGet( Mesh % Variables,TRIM(Solver % Variable % Name)//' adjoint')
3814
IF(.NOT. ASSOCIATED(aVar)) THEN
3815
ALLOCATE(AdjSol(n))
3816
AdjSol = 0.0_dp
3817
CALL VariableAddVector( Mesh % Variables,Mesh,Solver,&
3818
TRIM(Solver % Variable % Name)//' adjoint',Solver % Variable % Dofs,&
3819
AdjSol, Solver % Variable % Perm, Output = .TRUE., Secondary = .TRUE.)
3820
aVar => VariableGet( Mesh % Variables,TRIM(Solver % Variable % Name)//' adjoint')
3821
3822
CALL VariableAddVector( Mesh % Variables,Mesh,Solver,&
3823
TRIM(Solver % Variable % Name)//' adjoint rhs',Solver % Variable % Dofs,&
3824
Solver % Matrix % rhsAdjoint, Solver % Variable % Perm, &
3825
Output = .TRUE., Secondary = .TRUE.)
3826
END IF
3827
AdjSol => avar % Values
3828
3829
3830
CALL SolveSystem( Solver % Matrix, ParMatrix, Solver % Matrix % rhsAdjoint, &
3831
AdjSol, Norm, Solver % Variable % DOFs,Solver )
3832
3833
3834
CALL ListAddLogical(Params,'Skip Compute Nonlinear Change',.FALSE.)
3835
END BLOCK
3836
END IF
3837
3838
3839
3840
IF( Solver % NumberOfConstraintModes > 0 ) THEN
3841
! If we have a frozen stat then the nonlinear system loop is used to find that frozen state
3842
! and we perform the linearized constraint modes analysis at the end.
3843
IF( ListGetLogical(Params,'Constraint Modes Analysis Frozen',Found ) ) THEN
3844
BLOCK
3845
INTEGER :: n
3846
REAL(KIND=dp) :: Norm
3847
REAL(KIND=dp), ALLOCATABLE :: xtmp(:), btmp(:)
3848
REAL(KIND=dp), POINTER :: AdjSol(:)
3849
3850
n = SIZE(Solver % Matrix % rhs)
3851
CALL ListAddLogical(Params,'Skip Compute Nonlinear Change',.TRUE.)
3852
3853
IF( SolveAdjoint ) THEN
3854
3855
CALL SolveSystem( Solver % Matrix, ParMatrix, Solver % Matrix % rhsAdjoint, &
3856
Solver % Variable % ConstraintModes(1,:), Norm, Solver % Variable % DOFs,Solver )
3857
3858
AdjSol => Solver % Variable % ConstraintModes(1,:)
3859
CALL VariableAddVector( Solver % Mesh % Variables,Solver % Mesh,Solver,&
3860
TRIM(Solver % Variable % Name)//' adjoint',Solver % Variable % Dofs,&
3861
AdjSol, Solver % Variable % Perm, &
3862
Output = .TRUE., Secondary = .TRUE.)
3863
3864
CALL VariableAddVector( Solver % Mesh % Variables,Solver % Mesh,Solver,&
3865
TRIM(Solver % Variable % Name)//' adjoint rhs',Solver % Variable % Dofs,&
3866
Solver % Matrix % rhsAdjoint, Solver % Variable % Perm, &
3867
Output = .TRUE., Secondary = .TRUE.)
3868
3869
ELSE
3870
ALLOCATE(xtmp(n),btmp(n))
3871
btmp = Solver % Matrix % rhs
3872
xtmp = Solver % Variable % Values
3873
3874
Solver % Matrix % rhs = 0.0_dp
3875
3876
CALL ListAddLogical(Params,'Constraint Modes Analysis Frozen',.FALSE.)
3877
3878
CALL SolveSystem( Solver % Matrix, ParMatrix, Solver % Matrix % rhs, &
3879
Solver % Variable % Values, Norm, Solver % Variable % DOFs,Solver )
3880
3881
CALL ListAddLogical(Params,'Constraint Modes Analysis Frozen',.TRUE.)
3882
3883
Solver % Matrix % rhs = btmp
3884
Solver % Variable % Values = xtmp
3885
DEALLOCATE(xtmp,btmp)
3886
END IF
3887
3888
CALL ListAddLogical(Params,'Skip Compute Nonlinear Change',.FALSE.)
3889
END BLOCK
3890
END IF
3891
3892
IF( ListGetLogical( Params,'Nonlinear System Constraint Modes', Found ) ) THEN
3893
CALL FinalizeLumpedMatrix( Solver )
3894
END IF
3895
END IF
3896
3897
3898
3899
IF( ListGetLogical( Params,'CutFEM',Found ) ) THEN
3900
Mesh => Solver % Mesh
3901
3902
! We do not need the old meshes. When we reach a new timestep
3903
! they have already been saved.
3904
IF(ASSOCIATED(Solver % Mesh % Next ) ) THEN
3905
IF(ASSOCIATED(Solver % Mesh % Next % Next ) ) THEN
3906
CALL FreeMesh(Solver % Mesh % Next % Next )
3907
END IF
3908
CALL FreeMesh(Solver % Mesh % Next)
3909
END IF
3910
3911
! Updates Level-set and creates 1D mesh that becomes "Mesh % Next"
3912
! The Mesh % Next is saved normally in the VTU files etc.
3913
CALL LevelSetUpdate(Solver,Solver % Mesh)
3914
3915
! We do not need to create the actual CutFEM Mesh, but we might want to have it
3916
! for visualization purposes.
3917
IF( ListGetLogical( Solver % Values,'CutFEM Mesh Save', Found ) ) THEN
3918
! This 2D mesh becomes Mesh % Next % Next
3919
Solver % Mesh % Next % Next => CreateCutFEMMesh(Solver,Mesh,Solver % Variable % Perm,&
3920
.TRUE.,.TRUE.,.FALSE.,Solver % Values,'project variable')
3921
END IF
3922
3923
CALL CutFEMVariableFinalize(Solver)
3924
END IF
3925
3926
IF( ListGetLogical( Params,'MMG Remesh', Found ) ) THEN
3927
CALL Remesh(CurrentModel,Solver)
3928
END IF
3929
3930
CALL Info('DefaultFinish','Finished solver: '//GetString(Params,'Equation'),Level=8)
3931
3932
!------------------------------------------------------------------------------
3933
END SUBROUTINE DefaultFinish
3934
!------------------------------------------------------------------------------
3935
3936
FUNCTION DefaultCutFEM(Solver) RESULT( Swap )
3937
TYPE(Solver_t), TARGET, OPTIONAL :: Solver
3938
3939
TYPE(Solver_t), POINTER :: pSolver
3940
LOGICAL :: Swap, Found
3941
INTEGER :: i,n,Counter=0
3942
3943
SAVE Counter
3944
3945
Swap = .FALSE.
3946
3947
IF(PRESENT(Solver)) THEN
3948
pSolver => Solver
3949
ELSE
3950
pSolver => CurrentModel % Solver
3951
END IF
3952
3953
3954
! Nothing to do.
3955
IF(.NOT. ListGetLogical( pSolver % Values,'CutFEM',Found ) ) RETURN
3956
3957
! If we have special solver where we use the on-the-fly splitting do not swap the mesh.
3958
IF(ListGetLogical( pSolver % Values,'CutFEM Solver',Found ) ) THEN
3959
CALL Info('DefaultCutFEM','Skipping mesh swapping for modified CutFEM solver!',Level=10)
3960
RETURN
3961
END IF
3962
3963
Counter = Counter+1
3964
3965
IF(MODULO(Counter,2) == 1 ) THEN
3966
! We start with the original mesh, then swap to AddMesh.
3967
Swap = .TRUE.
3968
CALL CutFEMSetAddMesh(pSolver)
3969
ELSE
3970
! Nothing to swap this time.
3971
CALL CutFEMSetOrigMesh(pSolver)
3972
END IF
3973
3974
END FUNCTION DefaultCutFEM
3975
3976
3977
3978
3979
!> Solver the matrix equation related to the active solver
3980
!------------------------------------------------------------------------------
3981
RECURSIVE FUNCTION DefaultSolve( USolver, BackRotNT ) RESULT(Norm)
3982
!------------------------------------------------------------------------------
3983
TYPE(Solver_t), OPTIONAL, TARGET, INTENT(in) :: USolver
3984
REAL(KIND=dp) :: Norm
3985
LOGICAL, OPTIONAL, INTENT(in) :: BackRotNT
3986
3987
TYPE(Matrix_t), POINTER :: A
3988
TYPE(Variable_t), POINTER :: x
3989
REAL(KIND=dp), POINTER CONTIG :: b(:)
3990
REAL(KIND=dp), POINTER CONTIG :: SOL(:)
3991
3992
LOGICAL :: Found, BackRot
3993
3994
TYPE(ValueList_t), POINTER :: Params
3995
TYPE(Solver_t), POINTER :: Solver
3996
TYPE(Matrix_t), POINTER :: Ctmp
3997
CHARACTER(:), ALLOCATABLE :: linsolver, precond, dumpfile, saveslot
3998
INTEGER :: NameSpaceI, Count, MaxCount, i
3999
LOGICAL :: LinearSystemTrialing, SourceControl, NonlinearControl, &
4000
MonolithicSlave
4001
REAL(KIND=dp) :: s(3)
4002
4003
CALL Info('DefaultSolve','Solving linear system with default routines',Level=10)
4004
4005
Solver => CurrentModel % Solver
4006
Norm = REAL(0, dp)
4007
IF ( PRESENT( USolver ) ) Solver => USolver
4008
4009
Params => GetSolverParams(Solver)
4010
4011
NameSpaceI = NINT( ListGetCReal( Params,'Linear System Namespace Number', Found ) )
4012
LinearSystemTrialing = ListGetLogical( Params,'Linear System Trialing', Found )
4013
IF( LinearSystemTrialing ) NameSpaceI = MAX( 1, NameSpaceI )
4014
4015
IF( NameSpaceI > 0 ) THEN
4016
CALL Info('DefaultSolve','Linear system namespace number: '//I2S(NameSpaceI),Level=7)
4017
CALL ListPushNamespace('linsys'//I2S(NameSpaceI)//':')
4018
END IF
4019
4020
IF( ListGetLogical( Params,'Linear System Remove Zeros',Found ) ) THEN
4021
CALL CRS_RemoveZeros( Solver % Matrix )
4022
END IF
4023
4024
IF ( ListGetLogical( Params,'Linear System Save',Found )) THEN
4025
saveslot = GetString( Params,'Linear System Save Slot', Found )
4026
IF(.NOT. Found .OR. saveslot == 'solve') THEN
4027
CALL SaveLinearSystem( Solver )
4028
END IF
4029
END IF
4030
4031
IF (PRESENT(BackRotNT)) THEN
4032
BackRot=GetLogical(Params,'Back Rotate N-T Solution',Found)
4033
IF(.NOT.Found) BackRot=.TRUE.
4034
4035
IF (BackRot.NEQV.BackRotNT) &
4036
CALL ListAddLogical(Params,'Back Rotate N-T Solution',BackRotNT)
4037
END IF
4038
4039
MonolithicSlave = ListGetLogical(Params,'Monolithic Slave',Found )
4040
IF( MonolithicSlave ) THEN
4041
CALL MergeSlaveSolvers( Solver, PreSolve = .TRUE.)
4042
END IF
4043
4044
IF( ListGetLogical( Params,'Harmonic Mode',Found ) ) THEN
4045
CALL ChangeToHarmonicSystem( Solver )
4046
END IF
4047
4048
! Generate projector that allows enforcing of total flux when using Robin BC's
4049
CALL GenerateRobinProjectors( CurrentModel, Solver )
4050
4051
! Combine the individual projectors into one massive projector
4052
CALL GenerateConstraintMatrix( CurrentModel, Solver )
4053
4054
IF( GetLogical(Params,'Linear System Solver Disabled',Found) ) THEN
4055
CALL Info('DefaultSolve','Solver disabled, exiting early!',Level=10)
4056
RETURN
4057
END IF
4058
4059
SourceControl = ListGetLogical( Params,'Apply Source Control',Found )
4060
IF(SourceControl) CALL ControlLinearSystem( Solver,PreSolve=.TRUE. )
4061
4062
NonlinearControl = ListGetLogical( Params,'Apply Nonlinear Control',Found )
4063
IF(NonlinearControl) CALL ControlNonlinearSystem( Solver, PreSolve=.TRUE.)
4064
4065
4066
CALL Info('DefaultSolve','Calling SolveSystem for linear solution',Level=20)
4067
4068
A => Solver % Matrix
4069
x => Solver % Variable
4070
b => A % RHS
4071
SOL => x % Values
4072
4073
! Debugging stuff activated only when "Max Output Level" >= 20
4074
IF( InfoActive( 20 ) ) THEN
4075
CALL VectorValuesRange(A % Values,SIZE(A % Values),'A')
4076
CALL VectorValuesRange(A % rhs,SIZE(A % rhs),'b')
4077
END IF
4078
4079
10 CONTINUE
4080
4081
CALL SolveSystem(A,ParMatrix,b,SOL,x % Norm,x % DOFs,Solver)
4082
4083
IF( InfoActive( 20 ) ) THEN
4084
CALL VectorValuesRange(x % Values,SIZE(x % values),'x')
4085
END IF
4086
4087
IF( LinearSystemTrialing ) THEN
4088
IF( x % LinConverged > 0 ) THEN
4089
IF( ListGetLogical( Params,'Linear System Trialing Conserve',Found ) ) THEN
4090
MaxCount = ListGetInteger( Params,'Linear System Trialing Conserve Rounds',Found )
4091
IF( Found ) THEN
4092
i = NINT( ListGetConstReal( Params,'Linear System Namespace Number',Found ) )
4093
IF( i == NameSpaceI ) THEN
4094
Count = 1 + ListGetInteger( Params,'Linear System Namespace Conserve Count',Found )
4095
ELSE
4096
Count = 0
4097
END IF
4098
IF( Count > MaxCount ) THEN
4099
NameSpaceI = 0
4100
Count = 0
4101
END IF
4102
CALL ListAddInteger( Params,'Linear System Namespace Conserve Count',Count )
4103
END IF
4104
CALL ListAddConstReal( Params,'Linear System Namespace Number', 1.0_dp *NameSpaceI )
4105
END IF
4106
ELSE
4107
NameSpaceI = NameSpaceI + 1
4108
IF( .NOT. ListCheckPrefix( Params,'linsys'//I2S(NameSpaceI) ) ) THEN
4109
CALL Fatal('DefaultSolve','Exhausted all linear system strategies!')
4110
END IF
4111
CALL ListPopNamespace()
4112
CALL Info('DefaultSolve','Linear system namespace number: '//I2S(NameSpaceI),Level=7)
4113
CALL ListPushNamespace('linsys'//I2S(NameSpaceI)//':')
4114
GOTO 10
4115
END IF
4116
END IF
4117
4118
IF(SourceControl) CALL ControlLinearSystem( Solver,PreSolve=.FALSE. )
4119
IF(NonlinearControl) CALL ControlNonlinearSystem(Solver,PreSolve=.FALSE.)
4120
4121
IF ( ListGetLogical( Params,'Linear System Save',Found )) THEN
4122
saveslot = GetString( Params,'Linear System Save Slot', Found )
4123
IF( Found .AND. saveslot == 'after') THEN
4124
CALL SaveLinearSystem( Solver )
4125
END IF
4126
END IF
4127
4128
4129
! If flux corrected transport is used then apply the corrector to the system
4130
IF( GetLogical( Params,'Linear System FCT',Found ) ) THEN
4131
CALL FCT_Correction( Solver )
4132
END IF
4133
4134
IF( MonolithicSlave ) THEN
4135
CALL MergeSlaveSolvers( Solver, PreSolve = .FALSE.)
4136
END IF
4137
4138
! Backchange the linear system
4139
IF( ListGetLogical( Params,'Harmonic Mode',Found ) ) THEN
4140
CALL ChangeToHarmonicSystem( Solver, .TRUE. )
4141
END IF
4142
4143
IF (PRESENT(BackRotNT)) THEN
4144
IF (BackRot.NEQV.BackRotNT) &
4145
CALL ListAddLogical(Params,'Back Rotate N-T Solution',BackRot)
4146
END IF
4147
4148
Norm = x % Norm
4149
4150
IF( NameSpaceI > 0 ) CALL ListPopNamespace()
4151
4152
! One can run postprocessing solver in this slot in every nonlinear iteration.
4153
!-----------------------------------------------------------------------------
4154
CALL DefaultSlaveSolvers(Solver,'Nonlinear Post Solvers')
4155
4156
4157
! This could be somewhere else too. Now it is here for debugging.
4158
CALL SaveParallelInfo( Solver )
4159
4160
IF( ListGetLogical( Params,'Linear System Solve and Stop',Found ) ) THEN
4161
CALL Info('DefaultSolve','Just solved matrix and stopped!',Level=4)
4162
STOP EXIT_OK
4163
END IF
4164
4165
!------------------------------------------------------------------------------
4166
END FUNCTION DefaultSolve
4167
!------------------------------------------------------------------------------
4168
4169
4170
!------------------------------------------------------------------------------
4171
!> Is the system converged. Wrapper to hide the dirty test.
4172
!------------------------------------------------------------------------------
4173
FUNCTION DefaultConverged( USolver ) RESULT( Converged )
4174
!------------------------------------------------------------------------------
4175
TYPE(Solver_t), OPTIONAL, TARGET, INTENT(in) :: USolver
4176
TYPE(Solver_t), POINTER :: Solver
4177
LOGICAL :: Converged
4178
LOGICAL :: Found
4179
INTEGER :: i,imin,imax
4180
4181
Solver => CurrentModel % Solver
4182
IF ( PRESENT( USolver ) ) Solver => USolver
4183
4184
IF( ListGetLogical( CurrentModel % Simulation,'Parallel Timestepping',Found ) ) THEN
4185
i = Solver % Variable % NonlinConverged
4186
CALL Info('DefaultConverged','Convergence status: '//I2S(i),Level=12)
4187
imin = ParallelReduction(i,1)
4188
imax = ParallelReduction(i,2)
4189
IF(imin /= imax ) THEN
4190
CALL Info('DefaultConverged','Parallel timestepping converging at different rates!',Level=6)
4191
Solver % Variable % NonlinConverged = imin
4192
END IF
4193
END IF
4194
4195
Converged = ( Solver % Variable % NonlinConverged > 0 )
4196
4197
END FUNCTION DefaultConverged
4198
!------------------------------------------------------------------------------
4199
4200
4201
!------------------------------------------------------------------------------
4202
FUNCTION DefaultLinesearch( Converged, USolver, FirstIter, nsize, values, values0 ) RESULT( ReduceStep )
4203
!------------------------------------------------------------------------------
4204
LOGICAL, OPTIONAL :: Converged
4205
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
4206
LOGICAL, OPTIONAL :: FirstIter
4207
INTEGER, OPTIONAL :: nsize
4208
REAL(KIND=dp), OPTIONAL, TARGET :: values(:), values0(:)
4209
LOGICAL :: ReduceStep
4210
4211
LOGICAL :: stat, First, Last, DoLinesearch
4212
TYPE(Solver_t), POINTER :: Solver
4213
TYPE(Variable_t), POINTER :: iterV
4214
INTEGER :: iter, previter, MaxIter
4215
REAL(KIND=dp) :: LinesearchCond
4216
4217
SAVE :: previter
4218
4219
IF ( PRESENT( USolver ) ) THEN
4220
Solver => USolver
4221
ELSE
4222
Solver => CurrentModel % Solver
4223
END IF
4224
4225
DoLinesearch = .FALSE.
4226
IF( ListCheckPrefix( Solver % Values,'Nonlinear System Linesearch') ) THEN
4227
LineSearchCond = ListGetCReal( Solver % Values,&
4228
'Nonlinear System Linesearch Condition', Stat )
4229
IF( Stat ) THEN
4230
DoLinesearch = ( LineSearchCond > 0.0_dp )
4231
CALL ListAddLogical( Solver % Values,'Nonlinear System Linesearch', DoLinesearch )
4232
ELSE
4233
DoLinesearch = ListGetLogical( Solver % Values,'Nonlinear System Linesearch',Stat)
4234
END IF
4235
END IF
4236
4237
! This routine might be called for convenience also without checking
4238
! first whether it is needed.
4239
IF(.NOT. DoLinesearch ) THEN
4240
ReduceStep = .FALSE.
4241
IF( PRESENT( Converged ) ) Converged = .FALSE.
4242
RETURN
4243
END IF
4244
4245
IF( PRESENT( FirstIter ) ) THEN
4246
First = FirstIter
4247
Last = .FALSE.
4248
ELSE
4249
! This is the first trial if we are the first nonlinear iteration
4250
! for the first time.
4251
iterV => VariableGet( Solver % Mesh % Variables, 'nonlin iter' )
4252
iter = NINT(iterV % Values(1))
4253
MaxIter = ListGetInteger( Solver % Values,'Nonlinear System Max Iterations',Stat)
4254
First = (iter == 1 ) .AND. (iter /= previter)
4255
Last = (iter == MaxIter )
4256
previter = iter
4257
END IF
4258
4259
ReduceStep = CheckStepSize(Solver,First,nsize,values,values0)
4260
4261
IF( Last .AND. .NOT. ReduceStep ) THEN
4262
CALL Info('DefaultLinesearch',&
4263
'Maximum number of nonlinear iterations reached, giving up after linesearch',Level=6)
4264
END IF
4265
4266
IF( PRESENT( Converged ) ) THEN
4267
Converged = ( Solver % Variable % NonlinConverged == 1 ) .OR. Last
4268
END IF
4269
4270
END FUNCTION DefaultLinesearch
4271
4272
4273
4274
!------------------------------------------------------------------------------
4275
SUBROUTINE DefaultUpdateEquationsR( G, F, UElement, USolver, VecAssembly )
4276
!------------------------------------------------------------------------------
4277
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
4278
TYPE(Element_t), OPTIONAL, TARGET :: UElement
4279
REAL(KIND=dp) :: G(:,:), f(:)
4280
LOGICAL, OPTIONAL :: VecAssembly
4281
4282
TYPE(Solver_t), POINTER :: Solver
4283
TYPE(Matrix_t), POINTER :: A
4284
TYPE(Variable_t), POINTER :: x
4285
TYPE(Element_t), POINTER :: Element, P1, P2
4286
REAL(KIND=dp), POINTER CONTIG :: b(:), svalues(:)
4287
4288
LOGICAL :: Found, VecAsm, MCAsm
4289
4290
INTEGER :: i, j, n, nd
4291
INTEGER(KIND=AddrInt) :: Proc
4292
INTEGER, POINTER CONTIG :: Indexes(:), PermIndexes(:)
4293
4294
IF ( PRESENT( USolver ) ) THEN
4295
Solver => USolver
4296
ELSE
4297
Solver => CurrentModel % Solver
4298
END IF
4299
A => Solver % Matrix
4300
x => Solver % Variable
4301
b => A % RHS
4302
4303
Element => GetCurrentElement( UElement )
4304
4305
VecAsm = .FALSE.
4306
IF ( PRESENT( VecAssembly )) THEN
4307
VecAsm = VecAssembly
4308
END IF
4309
4310
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
4311
Proc = Solver % BoundaryElementProcedure
4312
ELSE
4313
Proc = Solver % BulkElementProcedure
4314
END IF
4315
IF ( Proc /= 0 ) THEN
4316
n = GetElementNOFNodes( Element )
4317
nd = GetElementNOFDOFs( Element, Solver )
4318
CALL ExecLocalProc( Proc, CurrentModel, Solver, &
4319
G, F, Element, n, nd )
4320
END IF
4321
4322
4323
IF ( ParEnv % PEs > 1 ) THEN
4324
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
4325
P1 => Element % BoundaryInfo % Left
4326
P2 => Element % BoundaryInfo % Right
4327
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
4328
IF ( P1 % PartIndex /= ParEnv % myPE .AND. &
4329
P2 % PartIndex /= ParEnv % myPE )RETURN
4330
4331
IF ( P1 % PartIndex /= ParEnv % myPE .OR. &
4332
P2 % PartIndex /= ParEnv % myPE ) THEN
4333
G=G/2; F=F/2;
4334
END IF
4335
ELSE IF ( ASSOCIATED(P1) ) THEN
4336
IF ( P1 % PartIndex /= ParEnv % myPE ) RETURN
4337
ELSE IF ( ASSOCIATED(P2) ) THEN
4338
IF ( P2 % PartIndex /= ParEnv % myPE ) RETURN
4339
END IF
4340
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
4341
IF(GetLogical(Solver % Values,'Linear System FCT',Found)) THEN
4342
Indexes => GetIndexStore()
4343
n = GetElementDOFs( Indexes, Element, Solver )
4344
IF(.NOT.ASSOCIATED(A % HaloValues)) THEN
4345
ALLOCATE(A % HaloValues(SIZE(A % Values))); A % HaloValues=0._dp
4346
END IF
4347
CALL UpdateGlobalEquations( A,G,b,0._dp*f,n,x % DOFs, &
4348
x % Perm(Indexes(1:n)),UElement=Element,GlobalValues=A % HaloValues )
4349
END IF
4350
RETURN
4351
END IF
4352
END IF
4353
4354
! Vectorized version of the glueing process requested
4355
IF (VecAsm) THEN
4356
#ifdef _OPENMP
4357
IF (OMP_GET_NUM_THREADS() == 1) THEN
4358
MCAsm = .TRUE.
4359
ELSE
4360
! Check if multicoloured assembly is in use
4361
MCAsm = (Solver % CurrentColour > 0) .AND. &
4362
ASSOCIATED(Solver % ColourIndexList)
4363
END IF
4364
#else
4365
MCAsm = .TRUE.
4366
#endif
4367
ELSE
4368
MCAsm = .FALSE.
4369
END IF
4370
4371
Indexes => GetIndexStore()
4372
n = GetElementDOFs( Indexes, Element, Solver )
4373
4374
PermIndexes => GetPermIndexStore()
4375
! Get permuted indices
4376
!DIR$ IVDEP
4377
DO j=1,n
4378
PermIndexes(j) = x % Perm(Indexes(j))
4379
END DO
4380
4381
IF( Solver % LocalSystemMode > 0 ) THEN
4382
CALL UseLocalMatrixStorage( Solver, n * x % dofs, G, F, ElemInd = Element % ElementIndex )
4383
END IF
4384
4385
! If we have any antiperiodic entries we need to check them all!
4386
IF( Solver % PeriodicFlipActive ) THEN
4387
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, G )
4388
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
4389
END IF
4390
4391
IF( VecAsm ) THEN
4392
CALL UpdateGlobalEquationsVec( A, G, b, f, n, &
4393
x % DOFs, PermIndexes, &
4394
UElement=Element, MCAssembly=MCAsm )
4395
ELSE
4396
! IF( A % FORMAT == MATRIX_CRS ) THEN
4397
! ! For CRS format these are effectively the same
4398
! CALL UpdateGlobalEquationsVec( A,G,b,f,n,x % DOFs, &
4399
! PermIndexes, UElement=Element )
4400
! ELSE
4401
CALL UpdateGlobalEquations( A,G,b,f,n,x % DOFs, &
4402
PermIndexes, UElement=Element )
4403
! END IF
4404
4405
IF(Solver % DirectMethod == DIRECT_PERMON) THEN
4406
CALL UpdatePermonMatrix( A, G, n, x % DOFs, PermIndexes )
4407
END IF
4408
END IF
4409
4410
! backflip, in case G is needed again
4411
! For change of sign backflip and flip are same operations.
4412
IF( Solver % PeriodicFlipActive ) THEN
4413
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, G )
4414
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
4415
END IF
4416
4417
!------------------------------------------------------------------------------
4418
END SUBROUTINE DefaultUpdateEquationsR
4419
!------------------------------------------------------------------------------
4420
4421
4422
SUBROUTINE DefaultUpdateEquationsIm( G, F, UElement, USolver, VecAssembly )
4423
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
4424
TYPE(Element_t), OPTIONAL, TARGET :: UElement
4425
REAL(KIND=dp) :: G(:,:), f(:)
4426
LOGICAL, OPTIONAL :: VecAssembly
4427
4428
TYPE(Matrix_t), POINTER :: A
4429
REAL(KIND=dp), POINTER :: pvalues(:), prhs(:)
4430
4431
IF ( PRESENT( USolver ) ) THEN
4432
A => USolver % Matrix
4433
ELSE
4434
A => CurrentModel % Solver % Matrix
4435
END IF
4436
4437
IF(.NOT. ASSOCIATED( A % Values_im ) ) THEN
4438
ALLOCATE( A % Values_im(SIZE( A % Values ) ) )
4439
A % Values_im = 0.0_dp
4440
END IF
4441
pvalues => A % Values
4442
A % Values => A % Values_im
4443
4444
IF(.NOT. ASSOCIATED( A % rhs_im ) ) THEN
4445
ALLOCATE( A % rhs_im(SIZE( A % rhs ) ) )
4446
A % rhs_im = 0.0_dp
4447
END IF
4448
prhs => A % Rhs
4449
A % rhs => A % rhs_im
4450
4451
CALL DefaultUpdateEquationsR( G, F, UElement, USolver, VecAssembly )
4452
4453
A % Values => pValues
4454
A % rhs => prhs
4455
4456
END SUBROUTINE DefaultUpdateEquationsIm
4457
4458
4459
!------------------------------------------------------------------------------
4460
SUBROUTINE UpdatePermonMatrix(A,G,n,dofs,nind)
4461
!------------------------------------------------------------------------------
4462
#ifdef HAVE_FETI4I
4463
use feti4i
4464
#endif
4465
4466
TYPE(Matrix_t) :: A
4467
INTEGER :: n, dofs, nInd(:)
4468
REAL(KIND=dp) :: G(:,:)
4469
!------------------------------------------------------------------------------
4470
REAL(KIND=C_DOUBLE), ALLOCATABLE :: vals(:)
4471
INTEGER, POINTER :: ptr
4472
INTEGER :: i,j,k,l,k1,k2
4473
INTEGER :: matrixType, eType
4474
INTEGER(C_INT), ALLOCATABLE :: ind(:)
4475
4476
TYPE(Element_t), POINTER :: CElement
4477
4478
#ifdef HAVE_FETI4I
4479
!!$ INTERFACE
4480
!!$ FUNCTION Permon_InitMatrix(n) RESULT(handle) BIND(C,Name="permon_init")
4481
!!$ USE, INTRINSIC :: ISO_C_BINDING
4482
!!$ TYPE(C_PTR) :: Handle
4483
!!$ INTEGER(C_INT), VALUE :: n
4484
!!$ END FUNCTION Permon_InitMatrix
4485
!!$
4486
!!$ SUBROUTINE Permon_UpdateMatrix(handle,n,inds,vals) BIND(C,Name="permon_update")
4487
!!$ USE, INTRINSIC :: ISO_C_BINDING
4488
!!$ TYPE(C_PTR), VALUE :: Handle
4489
!!$ INTEGER(C_INT), VALUE :: n
4490
!!$ INTEGER(C_INT) :: inds(*)
4491
!!$ REAL(C_DOUBLE) :: vals(*)
4492
!!$ END SUBROUTINE Permon_UpdateMatrix
4493
!!$ END INTERFACE
4494
4495
IF(.NOT. C_ASSOCIATED(A % PermonMatrix)) THEN
4496
A % NoDirichlet = .TRUE.
4497
!! A % PermonMatrix = Permon_InitMatrix(A % NumberOFRows)
4498
!! TODO: get correct matrix type
4499
matrixType = 0 !! symmetric positive definite (for other types see feti4i.h)
4500
CALL FETI4ICreateStiffnessMatrix(A % PermonMatrix, matrixType, 1) !TODO add number of rows A % NumberOFRows
4501
END IF
4502
4503
4504
ALLOCATE(vals(n*n*dofs*dofs), ind(n*dofs))
4505
DO i=1,n
4506
DO j=1,dofs
4507
k1 = (i-1)*dofs + j
4508
DO k=1,n
4509
DO l=1,dofs
4510
k2 = (k-1)*dofs + l
4511
vals(dofs*n*(k1-1)+k2) = G(k1,k2)
4512
END DO
4513
END DO
4514
ind(k1) = dofs*(nInd(i)-1)+j
4515
END DO
4516
END DO
4517
4518
!CALL Permon_UpdateMatrix( A % PermonMatrix, n*dofs, ind, vals )
4519
4520
CElement => GetCurrentElement()
4521
eType = ElementDim( CElement )
4522
! type of the element is the same as its dimension
4523
4524
CALL FETI4IAddElement(A % PermonMatrix, eType, n, nInd, n*dofs, ind, vals)
4525
4526
#endif
4527
4528
!------------------------------------------------------------------------------
4529
END SUBROUTINE UpdatePermonMatrix
4530
!------------------------------------------------------------------------------
4531
4532
4533
!------------------------------------------------------------------------------
4534
SUBROUTINE DefaultUpdateEquationsC( GC, FC, UElement, USolver, VecAssembly )
4535
!------------------------------------------------------------------------------
4536
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
4537
TYPE(Element_t), OPTIONAL, TARGET :: UElement
4538
COMPLEX(KIND=dp) :: GC(:,:), FC(:)
4539
LOGICAL, OPTIONAL :: VecAssembly ! The complex version lacks support for this
4540
4541
TYPE(Solver_t), POINTER :: Solver
4542
TYPE(Matrix_t), POINTER :: A
4543
TYPE(Variable_t), POINTER :: x
4544
TYPE(Element_t), POINTER :: Element, P1, P2
4545
REAL(KIND=dp), POINTER CONTIG :: b(:)
4546
4547
REAL(KIND=dp), POINTER :: G(:,:), F(:)
4548
4549
LOGICAL :: Found
4550
4551
INTEGER :: i,j,n,DOFs
4552
INTEGER, POINTER :: Indexes(:)
4553
4554
IF ( PRESENT( USolver ) ) THEN
4555
Solver => USolver
4556
ELSE
4557
Solver => CurrentModel % Solver
4558
END IF
4559
A => Solver % Matrix
4560
x => Solver % Variable
4561
b => A % RHS
4562
4563
Element => GetCurrentElement( UElement )
4564
4565
DOFs = x % DOFs
4566
Indexes => GetIndexStore()
4567
n = GetElementDOFs( Indexes, Element, Solver )
4568
4569
IF ( ParEnv % PEs > 1 ) THEN
4570
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
4571
P1 => Element % BoundaryInfo % Left
4572
P2 => Element % BoundaryInfo % Right
4573
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
4574
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
4575
P2 % PartIndex/=ParEnv % myPE )RETURN
4576
4577
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
4578
P2 % PartIndex/=ParEnv % myPE ) THEN
4579
GC=GC/2; FC=FC/2;
4580
END IF
4581
ELSE IF ( ASSOCIATED(P1) ) THEN
4582
IF ( P1 % PartIndex/=ParEnv % myPE ) RETURN
4583
ELSE IF ( ASSOCIATED(P2) ) THEN
4584
IF ( P2 % PartIndex/=ParEnv % myPE ) RETURN
4585
END IF
4586
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
4587
RETURN
4588
END IF
4589
END IF
4590
4591
ALLOCATE( G(DOFs*n,DOFs*n), F(DOFs*n) )
4592
DO i=1,n*DOFs/2
4593
F( 2*(i-1)+1 ) = REAL( FC(i) )
4594
F( 2*(i-1)+2 ) = AIMAG( FC(i) )
4595
4596
DO j=1,n*DOFs/2
4597
G( 2*(i-1)+1, 2*(j-1)+1 ) = REAL( GC(i,j) )
4598
G( 2*(i-1)+1, 2*(j-1)+2 ) = -AIMAG( GC(i,j) )
4599
G( 2*(i-1)+2, 2*(j-1)+1 ) = AIMAG( GC(i,j) )
4600
G( 2*(i-1)+2, 2*(j-1)+2 ) = REAL( GC(i,j) )
4601
END DO
4602
END DO
4603
4604
IF( Solver % LocalSystemMode > 0 ) THEN
4605
CALL UseLocalMatrixStorage( Solver, n * x % dofs, G, F, ElemInd = Element % ElementIndex )
4606
END IF
4607
4608
! If we have any antiperiodic entries we need to check them all!
4609
IF( Solver % PeriodicFlipActive ) THEN
4610
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, G )
4611
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
4612
END IF
4613
4614
CALL UpdateGlobalEquations( A,G,b,f,n,x % DOFs,x % Perm(Indexes(1:n)) )
4615
4616
DEALLOCATE( G, F)
4617
!------------------------------------------------------------------------------
4618
END SUBROUTINE DefaultUpdateEquationsC
4619
!------------------------------------------------------------------------------
4620
4621
4622
! This is a version when the initial matrix is given in diagonal form,
4623
! such that the last array index refers to the component.
4624
!------------------------------------------------------------------------------
4625
SUBROUTINE DefaultUpdateEquationsDiagC( GC, FC, UElement, USolver, VecAssembly )
4626
!------------------------------------------------------------------------------
4627
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
4628
TYPE(Element_t), OPTIONAL, TARGET :: UElement
4629
COMPLEX(KIND=dp) :: GC(:,:,:), FC(:,:)
4630
LOGICAL, OPTIONAL :: VecAssembly ! The complex version lacks support for this
4631
4632
TYPE(Solver_t), POINTER :: Solver
4633
TYPE(Matrix_t), POINTER :: A
4634
TYPE(Variable_t), POINTER :: x
4635
TYPE(Element_t), POINTER :: Element, P1, P2
4636
REAL(KIND=dp), POINTER CONTIG :: b(:)
4637
4638
REAL(KIND=dp), POINTER :: G(:,:), F(:)
4639
4640
LOGICAL :: Found, Half
4641
4642
INTEGER :: i,j,k,n,DOFs
4643
INTEGER, POINTER :: Indexes(:)
4644
4645
IF ( PRESENT( USolver ) ) THEN
4646
Solver => USolver
4647
ELSE
4648
Solver => CurrentModel % Solver
4649
END IF
4650
A => Solver % Matrix
4651
x => Solver % Variable
4652
b => A % RHS
4653
4654
Element => GetCurrentElement( UElement )
4655
4656
DOFs = x % DOFs
4657
Indexes => GetIndexStore()
4658
n = GetElementDOFs( Indexes, Element, Solver )
4659
4660
Half = .FALSE.
4661
IF ( ParEnv % PEs > 1 ) THEN
4662
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
4663
P1 => Element % BoundaryInfo % Left
4664
P2 => Element % BoundaryInfo % Right
4665
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
4666
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
4667
P2 % PartIndex/=ParEnv % myPE )RETURN
4668
4669
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
4670
P2 % PartIndex/=ParEnv % myPE ) THEN
4671
Half = .TRUE.
4672
END IF
4673
ELSE IF ( ASSOCIATED(P1) ) THEN
4674
IF ( P1 % PartIndex/=ParEnv % myPE ) RETURN
4675
ELSE IF ( ASSOCIATED(P2) ) THEN
4676
IF ( P2 % PartIndex/=ParEnv % myPE ) RETURN
4677
END IF
4678
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
4679
RETURN
4680
END IF
4681
END IF
4682
4683
ALLOCATE( G(DOFs*n,DOFs*n), F(DOFs*n) )
4684
G = 0.0_dp; F = 0.0_dp
4685
4686
DO i=1,n
4687
DO k=1,dofs/2
4688
F( dofs*(i-1)+2*k-1) = REAL( FC(i,k) )
4689
F( dofs*(i-1)+2*k ) = AIMAG( FC(i,k) )
4690
END DO
4691
END DO
4692
4693
DO i=1,n
4694
DO j=1,n
4695
DO k=1,DOFs/2
4696
G( dofs*(i-1)+2*k-1, dofs*(j-1)+2*k-1 ) = REAL( GC(i,j,k) )
4697
G( dofs*(i-1)+2*k-1, dofs*(j-1)+2*k ) = -AIMAG( GC(i,j,k) )
4698
G( dofs*(i-1)+2*k, dofs*(j-1)+2*k-1 ) = AIMAG( GC(i,j,k) )
4699
G( dofs*(i-1)+2*k, dofs*(j-1)+2*k ) = REAL( GC(i,j,k) )
4700
END DO
4701
END DO
4702
END DO
4703
4704
! Scale only the temporal fields
4705
IF( Half ) THEN
4706
G = G/2; F = F/2
4707
END IF
4708
4709
! If we have any antiperiodic entries we need to check them all!
4710
IF( Solver % PeriodicFlipActive ) THEN
4711
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, G )
4712
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
4713
END IF
4714
4715
CALL UpdateGlobalEquations( A,G,b,f,n,x % DOFs,x % Perm(Indexes(1:n)) )
4716
4717
DEALLOCATE( G, F)
4718
!------------------------------------------------------------------------------
4719
END SUBROUTINE DefaultUpdateEquationsDiagC
4720
!------------------------------------------------------------------------------
4721
4722
4723
4724
!> Adds the elementwise contribution the right-hand-side of the real valued matrix equation
4725
!------------------------------------------------------------------------------
4726
SUBROUTINE DefaultUpdateForceR( F, UElement, USolver, BulkUpdate )
4727
!------------------------------------------------------------------------------
4728
REAL(KIND=dp) :: F(:)
4729
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
4730
TYPE(Element_t), OPTIONAL, TARGET :: UElement
4731
LOGICAL, OPTIONAL :: BulkUpdate
4732
4733
TYPE(Solver_t), POINTER :: Solver
4734
TYPE(Variable_t), POINTER :: x
4735
TYPE(Element_t), POINTER :: Element, P1, P2
4736
4737
LOGICAL :: Found
4738
4739
INTEGER :: n
4740
INTEGER, POINTER :: Indexes(:)
4741
4742
Solver => CurrentModel % Solver
4743
IF ( PRESENT(USolver) ) Solver => USolver
4744
4745
Element => GetCurrentElement( UElement )
4746
4747
x => Solver % Variable
4748
Indexes => GetIndexStore()
4749
n = GetElementDOFs( Indexes, Element, Solver )
4750
4751
IF ( ParEnv % PEs > 1 ) THEN
4752
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
4753
P1 => Element % BoundaryInfo % Left
4754
P2 => Element % BoundaryInfo % Right
4755
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
4756
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
4757
P2 % PartIndex/=ParEnv % myPE )RETURN
4758
4759
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
4760
P2 % PartIndex/=ParEnv % myPE ) F=F/2;
4761
ELSE IF ( ASSOCIATED(P1) ) THEN
4762
IF ( P1 % PartIndex /= ParEnv % myPE ) RETURN
4763
ELSE IF ( ASSOCIATED(P2) ) THEN
4764
IF ( P2 % PartIndex /= ParEnv % myPE ) RETURN
4765
END IF
4766
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
4767
RETURN
4768
END IF
4769
END IF
4770
4771
! If we have any antiperiodic entries we need to check them all!
4772
IF( Solver % PeriodicFlipActive ) THEN
4773
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
4774
END IF
4775
4776
CALL UpdateGlobalForce( Solver % Matrix % RHS, &
4777
F, n, x % DOFs, x % Perm(Indexes(1:n)), UElement=Element)
4778
4779
IF( Solver % PeriodicFlipActive ) THEN
4780
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
4781
END IF
4782
4783
4784
!------------------------------------------------------------------------------
4785
END SUBROUTINE DefaultUpdateForceR
4786
!------------------------------------------------------------------------------
4787
4788
4789
4790
!> Adds the elementwise contribution the right-hand-side of the complex valued matrix equation
4791
!------------------------------------------------------------------------------
4792
SUBROUTINE DefaultUpdateForceC( FC, UElement, USolver )
4793
!------------------------------------------------------------------------------
4794
COMPLEX(KIND=dp) :: FC(:)
4795
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
4796
TYPE(Element_t), OPTIONAL, TARGET :: UElement
4797
4798
TYPE(Solver_t), POINTER :: Solver
4799
TYPE(Variable_t), POINTER :: x
4800
TYPE(Element_t), POINTER :: Element, P1, P2
4801
4802
REAL(KIND=dp), ALLOCATABLE :: F(:)
4803
4804
INTEGER :: i,n,DOFs
4805
INTEGER, POINTER :: Indexes(:)
4806
4807
Solver => CurrentModel % Solver
4808
IF ( PRESENT(USolver) ) Solver => USolver
4809
4810
Element => GetCurrentElement( UElement )
4811
4812
x => Solver % Variable
4813
DOFs = x % DOFs
4814
Indexes => GetIndexStore()
4815
n = GetElementDOFs( Indexes, Element, Solver )
4816
4817
IF ( ParEnv % PEs > 1 ) THEN
4818
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
4819
P1 => Element % BoundaryInfo % Left
4820
P2 => Element % BoundaryInfo % Right
4821
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
4822
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
4823
P2 % PartIndex/=ParEnv % myPE )RETURN
4824
4825
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
4826
P2 % PartIndex/=ParEnv % myPE ) FC=FC/2;
4827
ELSE IF ( ASSOCIATED(P1) ) THEN
4828
IF ( P1 % PartIndex/=ParEnv % myPE ) RETURN
4829
ELSE IF ( ASSOCIATED(P2) ) THEN
4830
IF ( P2 % PartIndex/=ParEnv % myPE ) RETURN
4831
END IF
4832
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
4833
RETURN
4834
END IF
4835
END IF
4836
4837
4838
ALLOCATE( F(DOFs*n) )
4839
DO i=1,n*DOFs/2
4840
F( 2*(i-1) + 1 ) = REAL(FC(i))
4841
F( 2*(i-1) + 2 ) = AIMAG(FC(i))
4842
END DO
4843
4844
IF( Solver % PeriodicFlipActive ) THEN
4845
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
4846
END IF
4847
4848
CALL UpdateGlobalForce( Solver % Matrix % RHS, &
4849
F, n, x % DOFs, x % Perm(Indexes(1:n)) )
4850
4851
DEALLOCATE( F )
4852
!------------------------------------------------------------------------------
4853
END SUBROUTINE DefaultUpdateForceC
4854
!------------------------------------------------------------------------------
4855
4856
4857
!------------------------------------------------------------------------------
4858
SUBROUTINE DefaultUpdateTimeForceR( F, UElement, USolver )
4859
!------------------------------------------------------------------------------
4860
REAL(KIND=dp) :: F(:)
4861
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
4862
TYPE(Element_t), OPTIONAL, TARGET :: UElement
4863
4864
TYPE(Solver_t), POINTER :: Solver
4865
TYPE(Variable_t), POINTER :: x
4866
TYPE(Element_t), POINTER :: Element, P1, P2
4867
4868
INTEGER :: n
4869
INTEGER, POINTER :: Indexes(:)
4870
4871
Solver => CurrentModel % Solver
4872
IF ( PRESENT(USolver) ) Solver => USolver
4873
4874
Element => GetCurrentElement( UElement )
4875
4876
x => Solver % Variable
4877
Indexes => GetIndexStore()
4878
n = GetElementDOFs( Indexes, Element, Solver )
4879
4880
IF ( ParEnv % PEs > 1 ) THEN
4881
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
4882
P1 => Element % BoundaryInfo % Left
4883
P2 => Element % BoundaryInfo % Right
4884
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
4885
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
4886
P2 % PartIndex/=ParEnv % myPE )RETURN
4887
4888
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
4889
P2 % PartIndex/=ParEnv % myPE ) F=F/2;
4890
ELSE IF ( ASSOCIATED(P1) ) THEN
4891
IF ( P1 % PartIndex /= ParEnv % myPE ) RETURN
4892
ELSE IF ( ASSOCIATED(P2) ) THEN
4893
IF ( P2 % PartIndex /= ParEnv % myPE ) RETURN
4894
END IF
4895
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
4896
RETURN
4897
END IF
4898
END IF
4899
4900
IF( Solver % PeriodicFlipActive ) THEN
4901
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
4902
END IF
4903
4904
CALL UpdateTimeForce( Solver % Matrix,Solver % Matrix % RHS, &
4905
F, n, x % DOFs, x % Perm(Indexes(1:n)) )
4906
4907
IF( Solver % PeriodicFlipActive ) THEN
4908
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
4909
END IF
4910
4911
!------------------------------------------------------------------------------
4912
END SUBROUTINE DefaultUpdateTimeForceR
4913
!------------------------------------------------------------------------------
4914
4915
4916
4917
!------------------------------------------------------------------------------
4918
SUBROUTINE DefaultUpdateTimeForceC( FC, UElement, USolver )
4919
!------------------------------------------------------------------------------
4920
COMPLEX(KIND=dp) :: FC(:)
4921
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
4922
TYPE(Element_t), OPTIONAL, TARGET :: UElement
4923
4924
TYPE(Solver_t), POINTER :: Solver
4925
TYPE(Variable_t), POINTER :: x
4926
TYPE(Element_t), POINTER :: Element, P1, P2
4927
4928
REAL(KIND=dp), ALLOCATABLE :: F(:)
4929
4930
INTEGER :: i,n,DOFs
4931
INTEGER, POINTER :: Indexes(:)
4932
4933
Solver => CurrentModel % Solver
4934
IF ( PRESENT(USolver) ) Solver => USolver
4935
4936
Element => GetCurrentElement( UElement )
4937
4938
x => Solver % Variable
4939
DOFs = x % DOFs
4940
Indexes => GetIndexStore()
4941
n = GetElementDOFs( Indexes, Element, Solver )
4942
4943
IF ( ParEnv % PEs > 1 ) THEN
4944
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
4945
P1 => Element % BoundaryInfo % Left
4946
P2 => Element % BoundaryInfo % Right
4947
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
4948
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
4949
P2 % PartIndex/=ParEnv % myPE )RETURN
4950
4951
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
4952
P2 % PartIndex/=ParEnv % myPE ) FC=FC/2;
4953
ELSE IF ( ASSOCIATED(P1) ) THEN
4954
IF ( P1 % PartIndex/=ParEnv % myPE ) RETURN
4955
ELSE IF ( ASSOCIATED(P2) ) THEN
4956
IF ( P2 % PartIndex/=ParEnv % myPE ) RETURN
4957
END IF
4958
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
4959
RETURN
4960
END IF
4961
END IF
4962
4963
ALLOCATE( F(DOFs*n) )
4964
DO i=1,n*DOFs/2
4965
F( 2*(i-1) + 1 ) = REAL(FC(i))
4966
F( 2*(i-1) + 2 ) = -AIMAG(FC(i))
4967
END DO
4968
4969
IF( Solver % PeriodicFlipActive ) THEN
4970
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
4971
END IF
4972
4973
CALL UpdateTimeForce( Solver % Matrix,Solver % Matrix % RHS, &
4974
F, n, x % DOFs, x % Perm(Indexes(1:n)) )
4975
4976
DEALLOCATE( F )
4977
!------------------------------------------------------------------------------
4978
END SUBROUTINE DefaultUpdateTimeForceC
4979
!------------------------------------------------------------------------------
4980
4981
4982
4983
4984
4985
!------------------------------------------------------------------------------
4986
SUBROUTINE DefaultUpdatePrecR( M, UElement, USolver )
4987
!------------------------------------------------------------------------------
4988
TYPE(Solver_t), OPTIONAL,TARGET :: USolver
4989
TYPE(Element_t), OPTIONAL, TARGET :: UElement
4990
REAL(KIND=dp) :: M(:,:)
4991
4992
TYPE(Solver_t), POINTER :: Solver
4993
TYPE(Matrix_t), POINTER :: A
4994
TYPE(Variable_t), POINTER :: x
4995
TYPE(Element_t), POINTER :: Element, P1, P2
4996
4997
INTEGER :: i,j,n
4998
INTEGER, POINTER :: Indexes(:)
4999
5000
IF ( PRESENT( USolver ) ) THEN
5001
Solver => USolver
5002
ELSE
5003
Solver => CurrentModel % Solver
5004
END IF
5005
A => Solver % Matrix
5006
x => Solver % Variable
5007
5008
Element => GetCurrentElement( UElement )
5009
5010
Indexes => GetIndexStore()
5011
n = GetElementDOFs( Indexes, Element, Solver )
5012
5013
IF ( ParEnv % PEs > 1 ) THEN
5014
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
5015
P1 => Element % BoundaryInfo % Left
5016
P2 => Element % BoundaryInfo % Right
5017
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
5018
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
5019
P2 % PartIndex/=ParEnv % myPE )RETURN
5020
5021
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
5022
P2 % PartIndex/=ParEnv % myPE ) M=M/2
5023
ELSE IF ( ASSOCIATED(P1) ) THEN
5024
IF ( P1 % PartIndex /= ParEnv % myPE ) RETURN
5025
ELSE IF ( ASSOCIATED(P2) ) THEN
5026
IF ( P2 % PartIndex /= ParEnv % myPE ) RETURN
5027
END IF
5028
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
5029
RETURN
5030
END IF
5031
END IF
5032
5033
!$OMP CRITICAL
5034
IF ( .NOT. ASSOCIATED( A % PrecValues ) ) THEN
5035
CALL Info('DefaultUpdatePrecR','Allocating for separate preconditioning matrix!',Level=20)
5036
ALLOCATE( A % PrecValues(SIZE(A % Values)) )
5037
A % PrecValues = 0.0d0
5038
END IF
5039
!$OMP END CRITICAL
5040
5041
! flip mass matrix for periodic elimination
5042
IF( Solver % PeriodicFlipActive ) THEN
5043
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, M )
5044
END IF
5045
5046
SELECT CASE( A % Format )
5047
CASE( MATRIX_CRS )
5048
CALL CRS_GlueLocalMatrix( A, n, x % DOFs, x % Perm(Indexes(1:n)), &
5049
M, A % PrecValues )
5050
CASE DEFAULT
5051
CALL FATAL( 'DefaultUpdatePrecR', 'Unexpected matrix format')
5052
END SELECT
5053
5054
IF( Solver % PeriodicFlipActive ) THEN
5055
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, M )
5056
END IF
5057
5058
!------------------------------------------------------------------------------
5059
END SUBROUTINE DefaultUpdatePrecR
5060
!------------------------------------------------------------------------------
5061
5062
!------------------------------------------------------------------------------
5063
SUBROUTINE DefaultUpdatePrecC( MC, UElement, USolver )
5064
!------------------------------------------------------------------------------
5065
TYPE(Solver_t), OPTIONAL,TARGET :: USolver
5066
TYPE(Element_t), OPTIONAL, TARGET :: UElement
5067
COMPLEX(KIND=dp) :: MC(:,:)
5068
5069
TYPE(Solver_t), POINTER :: Solver
5070
TYPE(Matrix_t), POINTER :: A
5071
TYPE(Variable_t), POINTER :: x
5072
TYPE(Element_t), POINTER :: Element, P1, P2
5073
5074
REAL(KIND=dp), ALLOCATABLE :: M(:,:)
5075
5076
INTEGER :: i,j,n,DOFs
5077
INTEGER, POINTER :: Indexes(:)
5078
5079
IF ( PRESENT( USolver ) ) THEN
5080
Solver => USolver
5081
ELSE
5082
Solver => CurrentModel % Solver
5083
END IF
5084
A => Solver % Matrix
5085
x => Solver % Variable
5086
5087
Element => GetCurrentElement( UElement )
5088
5089
DOFs = x % DOFs
5090
Indexes => GetIndexStore()
5091
n = GetElementDOFs( Indexes, Element, Solver )
5092
5093
IF ( ParEnv % PEs > 1 ) THEN
5094
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
5095
P1 => Element % BoundaryInfo % Left
5096
P2 => Element % BoundaryInfo % Right
5097
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
5098
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
5099
P2 % PartIndex/=ParEnv % myPE )RETURN
5100
5101
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
5102
P2 % PartIndex/=ParEnv % myPE ) MC=MC/2
5103
ELSE IF ( ASSOCIATED(P1) ) THEN
5104
IF ( P1 % PartIndex/=ParEnv % myPE ) RETURN
5105
ELSE IF ( ASSOCIATED(P2) ) THEN
5106
IF ( P2 % PartIndex/=ParEnv % myPE ) RETURN
5107
END IF
5108
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
5109
RETURN
5110
END IF
5111
END IF
5112
5113
!$OMP CRITICAL
5114
IF ( .NOT. ASSOCIATED( A % PrecValues ) ) THEN
5115
CALL Info('DefaultUpdatePrecC','Allocating for separate preconditioning matrix!',Level=20)
5116
ALLOCATE( A % PrecValues(SIZE(A % Values)) )
5117
A % PrecValues = 0.0d0
5118
END IF
5119
!$OMP END CRITICAL
5120
5121
ALLOCATE( M(DOFs*n,DOFs*n) )
5122
DO i=1,n*DOFs/2
5123
DO j=1,n*DOFs/2
5124
M(2*(i-1)+1, 2*(j-1)+1) = REAL( MC(i,j) )
5125
M(2*(i-1)+1, 2*(j-1)+2) = -AIMAG( MC(i,j) )
5126
M(2*(i-1)+2, 2*(j-1)+1) = AIMAG( MC(i,j) )
5127
M(2*(i-1)+2, 2*(j-1)+2) = REAL( MC(i,j) )
5128
END DO
5129
END DO
5130
5131
! flip preconditioning matrix for periodic elimination
5132
IF( Solver % PeriodicFlipActive ) THEN
5133
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, M )
5134
END IF
5135
5136
SELECT CASE( A % Format )
5137
CASE( MATRIX_CRS )
5138
CALL CRS_GlueLocalMatrix( A, n, x % DOFs, x % Perm(Indexes(1:n)), &
5139
M, A % PrecValues )
5140
CASE DEFAULT
5141
CALL FATAL( 'DefaultUpdatePrecC', 'Unexpected matrix format')
5142
END SELECT
5143
5144
DEALLOCATE( M )
5145
!------------------------------------------------------------------------------
5146
END SUBROUTINE DefaultUpdatePrecC
5147
!------------------------------------------------------------------------------
5148
5149
!------------------------------------------------------------------------------
5150
SUBROUTINE DefaultUpdateMassR( M, UElement, USolver )
5151
!------------------------------------------------------------------------------
5152
TYPE(Solver_t), OPTIONAL,TARGET :: USolver
5153
TYPE(Element_t), OPTIONAL, TARGET :: UElement
5154
REAL(KIND=dp) :: M(:,:)
5155
5156
TYPE(Solver_t), POINTER :: Solver
5157
TYPE(Matrix_t), POINTER :: A
5158
TYPE(Variable_t), POINTER :: x
5159
TYPE(Element_t), POINTER :: Element, P1, P2
5160
5161
LOGICAL :: Found
5162
5163
INTEGER :: i,j,n
5164
INTEGER, POINTER :: Indexes(:)
5165
5166
IF ( PRESENT( USolver ) ) THEN
5167
Solver => USolver
5168
A => Solver % Matrix
5169
x => Solver % Variable
5170
ELSE
5171
Solver => CurrentModel % Solver
5172
A => Solver % Matrix
5173
x => Solver % Variable
5174
END IF
5175
5176
Element => GetCurrentElement( UElement )
5177
5178
Indexes => GetIndexStore()
5179
n = GetElementDOFs( Indexes, Element, Solver )
5180
5181
IF ( ParEnv % PEs > 1 ) THEN
5182
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
5183
P1 => Element % BoundaryInfo % Left
5184
P2 => Element % BoundaryInfo % Right
5185
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
5186
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
5187
P2 % PartIndex/=ParEnv % myPE )RETURN
5188
5189
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
5190
P2 % PartIndex/=ParEnv % myPE ) M=M/2
5191
ELSE IF ( ASSOCIATED(P1) ) THEN
5192
IF ( P1 % PartIndex /= ParEnv % myPE ) RETURN
5193
ELSE IF ( ASSOCIATED(P2) ) THEN
5194
IF ( P2 % PartIndex /= ParEnv % myPE ) RETURN
5195
END IF
5196
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
5197
IF (ListGetLogical(Solver % Values, 'Linear System FCT', Found)) THEN
5198
Indexes => GetIndexStore()
5199
n = GetElementDOFs( Indexes, Element, Solver )
5200
IF(.NOT.ASSOCIATED(A % HaloMassValues)) THEN
5201
ALLOCATE(A % HaloMassValues(SIZE(A % Values))); A % HaloMassValues=0._dp
5202
END IF
5203
CALL UpdateMassMatrix( A, M, n, x % DOFs, x % Perm(Indexes(1:n)), &
5204
A % HaloMassValues )
5205
END IF
5206
RETURN
5207
END IF
5208
END IF
5209
5210
!$OMP CRITICAL
5211
IF ( .NOT. ASSOCIATED( A % MassValues ) ) THEN
5212
ALLOCATE( A % MassValues(SIZE(A % Values)) )
5213
A % MassValues = 0.0_dp
5214
END IF
5215
!$OMP END CRITICAL
5216
5217
5218
! flip mass matrix for periodic elimination
5219
IF( Solver % PeriodicFlipActive ) THEN
5220
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, M )
5221
END IF
5222
5223
CALL UpdateMassMatrix( A, M, n, x % DOFs, x % Perm(Indexes(1:n)), &
5224
A % MassValues )
5225
5226
! backflip to be on the safe side
5227
IF( Solver % PeriodicFlipActive ) THEN
5228
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % Dofs, M )
5229
END IF
5230
5231
5232
!------------------------------------------------------------------------------
5233
END SUBROUTINE DefaultUpdateMassR
5234
!------------------------------------------------------------------------------
5235
5236
!------------------------------------------------------------------------------
5237
SUBROUTINE DefaultUpdateMassC( MC, UElement, USolver )
5238
!------------------------------------------------------------------------------
5239
TYPE(Solver_t), OPTIONAL,TARGET :: USolver
5240
TYPE(Element_t), OPTIONAL, TARGET :: UElement
5241
COMPLEX(KIND=dp) :: MC(:,:)
5242
5243
TYPE(Solver_t), POINTER :: Solver
5244
TYPE(Matrix_t), POINTER :: A
5245
TYPE(Variable_t), POINTER :: x
5246
TYPE(Element_t), POINTER :: Element, P1, P2
5247
5248
REAL(KIND=dp), ALLOCATABLE :: M(:,:)
5249
5250
INTEGER :: i,j,n,DOFs
5251
INTEGER, POINTER :: Indexes(:)
5252
5253
IF ( PRESENT( USolver ) ) THEN
5254
Solver => USolver
5255
A => Solver % Matrix
5256
x => Solver % Variable
5257
ELSE
5258
Solver => CurrentModel % Solver
5259
A => Solver % Matrix
5260
x => Solver % Variable
5261
END IF
5262
5263
Element => GetCurrentElement( UElement )
5264
5265
DOFs = x % DOFs
5266
Indexes => GetIndexStore()
5267
n = GetElementDOFs( Indexes, Element, Solver )
5268
5269
IF ( ParEnv % PEs > 1 ) THEN
5270
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
5271
P1 => Element % BoundaryInfo % Left
5272
P2 => Element % BoundaryInfo % Right
5273
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
5274
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
5275
P2 % PartIndex/=ParEnv % myPE )RETURN
5276
5277
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
5278
P2 % PartIndex/=ParEnv % myPE ) MC=MC/2
5279
ELSE IF ( ASSOCIATED(P1) ) THEN
5280
IF ( P1 % PartIndex/=ParEnv % myPE ) RETURN
5281
ELSE IF ( ASSOCIATED(P2) ) THEN
5282
IF ( P2 % PartIndex/=ParEnv % myPE ) RETURN
5283
END IF
5284
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
5285
RETURN
5286
END IF
5287
END IF
5288
5289
!$OMP CRITICAL
5290
IF ( .NOT. ASSOCIATED( A % MassValues ) ) THEN
5291
ALLOCATE( A % MassValues(SIZE(A % Values)) )
5292
A % MassValues = 0.0d0
5293
END IF
5294
!$OMP END CRITICAL
5295
5296
ALLOCATE( M(DOFs*n,DOFs*n) )
5297
DO i=1,n*DOFs/2
5298
DO j=1,n*DOFs/2
5299
M(2*(i-1)+1, 2*(j-1)+1) = REAL( MC(i,j) )
5300
M(2*(i-1)+1, 2*(j-1)+2) = -AIMAG( MC(i,j) )
5301
M(2*(i-1)+2, 2*(j-1)+1) = AIMAG( MC(i,j) )
5302
M(2*(i-1)+2, 2*(j-1)+2) = REAL( MC(i,j) )
5303
END DO
5304
END DO
5305
5306
! flip mass matrix for periodic elimination
5307
IF( Solver % PeriodicFlipActive ) THEN
5308
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, M )
5309
END IF
5310
5311
CALL UpdateMassMatrix( A, M, n, x % DOFs, x % Perm(Indexes(1:n)), &
5312
A % MassValues )
5313
DEALLOCATE( M )
5314
!------------------------------------------------------------------------------
5315
END SUBROUTINE DefaultUpdateMassC
5316
!------------------------------------------------------------------------------
5317
5318
5319
5320
!------------------------------------------------------------------------------
5321
RECURSIVE SUBROUTINE DefaultUpdateDampR( B, UElement, USolver )
5322
!------------------------------------------------------------------------------
5323
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
5324
TYPE(Element_t), OPTIONAL, TARGET :: UElement
5325
REAL(KIND=dp) :: B(:,:)
5326
5327
TYPE(Solver_t), POINTER :: Solver
5328
TYPE(Matrix_t), POINTER :: A
5329
TYPE(Variable_t), POINTER :: x
5330
TYPE(Element_t), POINTER :: Element, P1, P2
5331
5332
INTEGER :: i,j,n
5333
INTEGER, POINTER :: Indexes(:)
5334
5335
IF ( PRESENT( USolver ) ) THEN
5336
Solver => USolver
5337
ELSE
5338
Solver => CurrentModel % Solver
5339
END IF
5340
5341
A => Solver % Matrix
5342
x => Solver % Variable
5343
5344
Element => GetCurrentElement( UElement )
5345
5346
Indexes => GetIndexStore()
5347
n = GetElementDOFs( Indexes, Element, Solver )
5348
5349
IF ( ParEnv % PEs > 1 ) THEN
5350
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
5351
P1 => Element % BoundaryInfo % Left
5352
P2 => Element % BoundaryInfo % Right
5353
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
5354
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
5355
P2 % PartIndex/=ParEnv % myPE )RETURN
5356
5357
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
5358
P2 % PartIndex/=ParEnv % myPE ) B=B/2;
5359
ELSE IF ( ASSOCIATED(P1) ) THEN
5360
IF ( P1 % PartIndex /= ParEnv % myPE ) RETURN
5361
ELSE IF ( ASSOCIATED(P2) ) THEN
5362
IF ( P2 % PartIndex /= ParEnv % myPE ) RETURN
5363
END IF
5364
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
5365
RETURN
5366
END IF
5367
END IF
5368
5369
!$OMP CRITICAL
5370
IF ( .NOT. ASSOCIATED( A % DampValues ) ) THEN
5371
ALLOCATE( A % DampValues(SIZE(A % Values)) )
5372
A % DampValues = 0.0d0
5373
END IF
5374
!$OMP END CRITICAL
5375
5376
! flip damp matrix for periodic elimination
5377
IF( Solver % PeriodicFlipActive ) THEN
5378
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, B )
5379
END IF
5380
5381
CALL UpdateMassMatrix( A, B, n, x % DOFs, x % Perm(Indexes(1:n)), &
5382
A % DampValues )
5383
5384
IF( Solver % PeriodicFlipActive ) THEN
5385
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, B )
5386
END IF
5387
!------------------------------------------------------------------------------
5388
END SUBROUTINE DefaultUpdateDampR
5389
!------------------------------------------------------------------------------
5390
5391
5392
5393
!------------------------------------------------------------------------------
5394
SUBROUTINE DefaultUpdateDampC( BC, UElement, USolver )
5395
!------------------------------------------------------------------------------
5396
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
5397
TYPE(Element_t), OPTIONAL, TARGET :: UElement
5398
COMPLEX(KIND=dp) :: BC(:,:)
5399
5400
TYPE(Solver_t), POINTER :: Solver
5401
TYPE(Matrix_t), POINTER :: A
5402
TYPE(Variable_t), POINTER :: x
5403
TYPE(Element_t), POINTER :: Element, P1, P2
5404
5405
REAL(KIND=dp), ALLOCATABLE :: B(:,:)
5406
5407
INTEGER :: i,j,n,DOFs
5408
INTEGER, POINTER :: Indexes(:)
5409
5410
IF ( PRESENT( USolver ) ) THEN
5411
Solver => USolver
5412
ELSE
5413
Solver => CurrentModel % Solver
5414
END IF
5415
5416
A => Solver % Matrix
5417
x => Solver % Variable
5418
5419
Element => GetCurrentElement( UElement )
5420
5421
DOFs = x % DOFs
5422
Indexes => GetIndexStore()
5423
n = GetElementDOFs( Indexes, Element, Solver )
5424
5425
IF ( ParEnv % PEs > 1 ) THEN
5426
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
5427
P1 => Element % BoundaryInfo % Left
5428
P2 => Element % BoundaryInfo % Right
5429
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
5430
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
5431
P2 % PartIndex/=ParEnv % myPE )RETURN
5432
5433
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
5434
P2 % PartIndex/=ParEnv % myPE ) BC=BC/2
5435
ELSE IF ( ASSOCIATED(P1) ) THEN
5436
IF ( P1 % PartIndex/=ParEnv % myPE ) RETURN
5437
ELSE IF ( ASSOCIATED(P2) ) THEN
5438
IF ( P2 % PartIndex/=ParEnv % myPE ) RETURN
5439
END IF
5440
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
5441
RETURN
5442
END IF
5443
END IF
5444
5445
!$OMP CRITICAL
5446
IF ( .NOT. ASSOCIATED( A % DampValues ) ) THEN
5447
ALLOCATE( A % DampValues(SIZE(A % Values)) )
5448
A % DampValues = 0.0d0
5449
END IF
5450
!$OMP END CRITICAL
5451
5452
ALLOCATE( B(DOFs*n, DOFs*n) )
5453
DO i=1,n*DOFs/2
5454
DO j=1,n*DOFs/2
5455
B(2*(i-1)+1, 2*(j-1)+1) = REAL( BC(i,j) )
5456
B(2*(i-1)+1, 2*(j-1)+2) = -AIMAG( BC(i,j) )
5457
B(2*(i-1)+2, 2*(j-1)+1) = AIMAG( BC(i,j) )
5458
B(2*(i-1)+2, 2*(j-1)+2) = REAL( BC(i,j) )
5459
END DO
5460
END DO
5461
5462
IF( Solver % PeriodicFlipActive ) THEN
5463
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, B )
5464
END IF
5465
5466
CALL UpdateMassMatrix( A, B, n, x % DOFs, x % Perm(Indexes(1:n)), &
5467
A % DampValues )
5468
DEALLOCATE( B )
5469
!------------------------------------------------------------------------------
5470
END SUBROUTINE DefaultUpdateDampC
5471
!------------------------------------------------------------------------------
5472
5473
5474
5475
!------------------------------------------------------------------------------
5476
SUBROUTINE DefaultUpdateBulkR( B, F, UElement, USolver )
5477
!------------------------------------------------------------------------------
5478
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
5479
TYPE(Element_t), OPTIONAL, TARGET :: UElement
5480
REAL(KIND=dp) :: B(:,:), F(:)
5481
5482
TYPE(Solver_t), POINTER :: Solver
5483
TYPE(Matrix_t), POINTER :: A
5484
TYPE(Variable_t), POINTER :: x
5485
TYPE(Element_t), POINTER :: Element, P1, P2
5486
5487
INTEGER :: i,j,n
5488
INTEGER, POINTER :: Indexes(:)
5489
5490
IF ( PRESENT( USolver ) ) THEN
5491
Solver => USolver
5492
ELSE
5493
Solver => CurrentModel % Solver
5494
END IF
5495
5496
A => Solver % Matrix
5497
x => Solver % Variable
5498
5499
Element => GetCurrentElement( UElement )
5500
5501
Indexes => GetIndexStore()
5502
n = GetElementDOFs( Indexes, Element, Solver )
5503
5504
IF ( ParEnv % PEs > 1 ) THEN
5505
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
5506
P1 => Element % BoundaryInfo % Left
5507
P2 => Element % BoundaryInfo % Right
5508
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
5509
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
5510
P2 % PartIndex/=ParEnv % myPE )RETURN
5511
5512
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
5513
P2 % PartIndex/=ParEnv % myPE ) THEN
5514
B=B/2; F=F/2;
5515
END IF
5516
ELSE IF ( ASSOCIATED(P1) ) THEN
5517
IF ( P1 % PartIndex /= ParEnv % myPE ) RETURN
5518
ELSE IF ( ASSOCIATED(P2) ) THEN
5519
IF ( P2 % PartIndex /= ParEnv % myPE ) RETURN
5520
END IF
5521
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
5522
RETURN
5523
END IF
5524
END IF
5525
5526
!$OMP CRITICAL
5527
IF ( .NOT. ASSOCIATED( A % BulkValues ) ) THEN
5528
ALLOCATE( A % BulkValues(SIZE(A % Values)) )
5529
A % BulkValues = 0.0_dp
5530
END IF
5531
!$OMP END CRITICAL
5532
5533
!$OMP CRITICAL
5534
IF ( .NOT. ASSOCIATED( A % BulkRHS ) ) THEN
5535
ALLOCATE( A % BulkRHS(SIZE(A % RHS)) )
5536
A % BulkRHS = 0.0_dp
5537
END IF
5538
!$OMP END CRITICAL
5539
5540
5541
! If we have any antiperiodic entries we need to check them all!
5542
IF( Solver % PeriodicFlipActive ) THEN
5543
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, B )
5544
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
5545
END IF
5546
5547
CALL UpdateGlobalEquations( A,B,A % BulkRHS,f,n,x % DOFs,x % Perm(Indexes(1:n)), &
5548
GlobalValues=A % BulkValues )
5549
5550
IF( Solver % PeriodicFlipActive ) THEN
5551
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, B )
5552
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
5553
END IF
5554
5555
!------------------------------------------------------------------------------
5556
END SUBROUTINE DefaultUpdateBulkR
5557
!------------------------------------------------------------------------------
5558
5559
5560
5561
!------------------------------------------------------------------------------
5562
SUBROUTINE DefaultUpdateBulkC( BC, FC, UElement, USolver )
5563
!------------------------------------------------------------------------------
5564
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
5565
TYPE(Element_t), OPTIONAL, TARGET :: UElement
5566
COMPLEX(KIND=dp) :: BC(:,:), FC(:)
5567
5568
TYPE(Solver_t), POINTER :: Solver
5569
TYPE(Matrix_t), POINTER :: A
5570
TYPE(Variable_t), POINTER :: x
5571
TYPE(Element_t), POINTER :: Element, P1, P2
5572
5573
REAL(KIND=dp), ALLOCATABLE :: B(:,:),F(:)
5574
5575
INTEGER :: i,j,n,DOFs
5576
INTEGER, POINTER :: Indexes(:)
5577
5578
IF ( PRESENT( USolver ) ) THEN
5579
Solver => USolver
5580
ELSE
5581
Solver => CurrentModel % Solver
5582
END IF
5583
5584
A => Solver % Matrix
5585
x => Solver % Variable
5586
5587
Element => GetCurrentElement( UElement )
5588
5589
DOFs = x % DOFs
5590
Indexes => GetIndexStore()
5591
n = GetElementDOFs( Indexes, Element, Solver )
5592
5593
IF ( ParEnv % PEs > 1 ) THEN
5594
IF ( ASSOCIATED(Element % BoundaryInfo) ) THEN
5595
P1 => Element % BoundaryInfo % Left
5596
P2 => Element % BoundaryInfo % Right
5597
IF ( ASSOCIATED(P1) .AND. ASSOCIATED(P2) ) THEN
5598
IF ( P1 % PartIndex/=ParEnv % myPE .AND. &
5599
P2 % PartIndex/=ParEnv % myPE )RETURN
5600
5601
IF ( P1 % PartIndex/=ParEnv % myPE .OR. &
5602
P2 % PartIndex/=ParEnv % myPE ) THEN
5603
BC=BC/2; FC=FC/2;
5604
END IF
5605
ELSE IF ( ASSOCIATED(P1) ) THEN
5606
IF ( P1 % PartIndex/=ParEnv % myPE ) RETURN
5607
ELSE IF ( ASSOCIATED(P2) ) THEN
5608
IF ( P2 % PartIndex/=ParEnv % myPE ) RETURN
5609
END IF
5610
ELSE IF ( Element % PartIndex/=ParEnv % myPE ) THEN
5611
RETURN
5612
END IF
5613
END IF
5614
5615
5616
!$OMP CRITICAL
5617
IF ( .NOT. ASSOCIATED( A % BulkValues ) ) THEN
5618
ALLOCATE( A % BulkValues(SIZE(A % Values)) )
5619
A % BulkValues = 0.0_dp
5620
END IF
5621
!$OMP END CRITICAL
5622
5623
!$OMP CRITICAL
5624
IF ( .NOT. ASSOCIATED( A % BulkRHS ) ) THEN
5625
ALLOCATE( A % BulkRHS(SIZE(A % RHS)) )
5626
A % BulkRHS = 0.0_dp
5627
END IF
5628
!$OMP END CRITICAL
5629
5630
ALLOCATE( B(DOFs*n, DOFs*n), F(DOFs*n) )
5631
DO i=1,n*DOFs/2
5632
DO j=1,n*DOFs/2
5633
F( 2*(i-1)+1 ) = REAL( FC(i) )
5634
F( 2*(i-1)+2 ) = AIMAG( FC(i) )
5635
5636
B(2*(i-1)+1, 2*(j-1)+1) = REAL( BC(i,j) )
5637
B(2*(i-1)+1, 2*(j-1)+2) = -AIMAG( BC(i,j) )
5638
B(2*(i-1)+2, 2*(j-1)+1) = AIMAG( BC(i,j) )
5639
B(2*(i-1)+2, 2*(j-1)+2) = REAL( BC(i,j) )
5640
END DO
5641
END DO
5642
5643
IF( Solver % PeriodicFlipActive ) THEN
5644
CALL FlipPeriodicLocalMatrix( Solver, n, Indexes, x % dofs, B )
5645
CALL FlipPeriodicLocalForce( Solver, n, Indexes, x % dofs, f )
5646
END IF
5647
5648
CALL UpdateGlobalEquations( A,B,A % BulkRHS,f,n,x % DOFs,x % Perm(Indexes(1:n)), &
5649
GlobalValues=A % BulkValues )
5650
5651
DEALLOCATE( B, F )
5652
!------------------------------------------------------------------------------
5653
END SUBROUTINE DefaultUpdateBulkC
5654
!------------------------------------------------------------------------------
5655
5656
5657
SUBROUTINE DefaultUpdateDirichlet( Dvals, UElement, USolver, UIndexes, Dset )
5658
!------------------------------------------------------------------------------
5659
REAL(KIND=dp) :: Dvals(:)
5660
TYPE(Solver_t), OPTIONAL,TARGET :: USolver
5661
TYPE(Element_t), OPTIONAL, TARGET :: UElement
5662
INTEGER, OPTIONAL, TARGET :: UIndexes(:)
5663
LOGICAL, OPTIONAL :: Dset(:)
5664
5665
TYPE(Solver_t), POINTER :: Solver
5666
TYPE(Matrix_t), POINTER :: A
5667
TYPE(Variable_t), POINTER :: x
5668
TYPE(Element_t), POINTER :: Element
5669
5670
INTEGER :: i,j,n
5671
INTEGER, POINTER :: Indexes(:)
5672
5673
5674
IF ( PRESENT( USolver ) ) THEN
5675
Solver => USolver
5676
ELSE
5677
Solver => CurrentModel % Solver
5678
END IF
5679
5680
A => Solver % Matrix
5681
x => Solver % Variable
5682
5683
Element => GetCurrentElement( UElement )
5684
5685
IF( PRESENT( UIndexes ) ) THEN
5686
Indexes => Uindexes
5687
n = SIZE( Uindexes )
5688
ELSE
5689
Indexes => GetIndexStore()
5690
n = GetElementDOFs( Indexes, Element, Solver )
5691
END IF
5692
5693
DO i=1,n
5694
IF( PRESENT( Dset ) ) THEN
5695
IF( .NOT. Dset(i) ) CYCLE
5696
END IF
5697
CALL UpdateDirichletDof( A, Indexes(i), DVals(i) )
5698
END DO
5699
5700
END SUBROUTINE DefaultUpdateDirichlet
5701
5702
5703
5704
5705
!> Sets the Dirichlet conditions related to the variables of the active solver.
5706
!------------------------------------------------------------------------------------------
5707
SUBROUTINE DefaultDirichletBCs( USolver,Ux,UOffset,OffDiagonalMatrix)
5708
!------------------------------------------------------------------------------------------
5709
USE ElementDescription, ONLY: FaceElementOrientation
5710
USE LinearAlgebra, ONLY : SolveLinSys
5711
IMPLICIT NONE
5712
5713
INTEGER, OPTIONAL :: UOffset
5714
LOGICAL, OPTIONAL :: OffDiagonalMatrix
5715
TYPE(Variable_t), OPTIONAL, TARGET :: Ux
5716
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
5717
!--------------------------------------------------------------------------------------------
5718
TYPE(Matrix_t), POINTER :: A
5719
TYPE(Variable_t), POINTER :: x
5720
TYPE(Solver_t), POINTER :: Solver
5721
TYPE(ValueListEntry_t), POINTER :: ptr
5722
TYPE(ValueList_t), POINTER :: BC, Params
5723
TYPE(Element_t), POINTER :: Element, Parent, Edge, Face, SaveElement
5724
5725
REAL(KIND=dp), ALLOCATABLE :: Work(:), STIFF(:,:)
5726
REAL(KIND=dp), POINTER :: b(:)
5727
REAL(KIND=dp), POINTER :: DiagScaling(:)
5728
REAL(KIND=dp) :: xx, s, dval, Cond
5729
REAL(KIND=dp) :: DefaultDOFs(4)
5730
5731
INTEGER, ALLOCATABLE :: lInd(:), gInd(:)
5732
INTEGER :: FDofMap(6,4)
5733
INTEGER :: i, j, k, kk, l, m, n, nd, nb, np, mb, nn, ni, nj, i0
5734
INTEGER :: NDOFs, EDOFs, FDOFs, DOF, local, numEdgeDofs, istat, n_start, Offset
5735
INTEGER :: ActiveFaceId, BasisDegree
5736
5737
LOGICAL :: ReverseSign(6)
5738
LOGICAL :: Flag,Found, ConstantValue, ScaleSystem, DirichletComm
5739
LOGICAL :: PiolaTransform, SecondKindBasis
5740
LOGICAL, ALLOCATABLE :: ReleaseDir(:)
5741
LOGICAL :: ReleaseAny, NodalBCsWithBraces,AllConstrained
5742
LOGICAL :: CheckRight, AugmentedEigenSystem
5743
LOGICAL :: SimplicialElements
5744
5745
CHARACTER(:), ALLOCATABLE :: Name
5746
5747
SAVE gInd, lInd, STIFF, Work
5748
!--------------------------------------------------------------------------------------------
5749
5750
IF ( PRESENT( USolver ) ) THEN
5751
Solver => USolver
5752
ELSE
5753
Solver => CurrentModel % Solver
5754
END IF
5755
5756
Params => GetSolverParams(Solver)
5757
5758
IF ( GetString(Params,'Linear System Solver',Found)=='feti') THEN
5759
IF ( GetLogical(Params,'Total FETI', Found)) RETURN
5760
END IF
5761
5762
A => Solver % Matrix
5763
b => A % RHS
5764
IF ( PRESENT(Ux) ) THEN
5765
x => Ux
5766
ELSE
5767
x => Solver % Variable
5768
END IF
5769
5770
IF(.NOT.ALLOCATED(A % ConstrainedDOF)) THEN
5771
ALLOCATE(A % ConstrainedDOF(A % NumberOfRows))
5772
A % ConstrainedDOF = .FALSE.
5773
ELSE
5774
IF (SIZE(A % ConstrainedDOF) < A % NumberOfRows) THEN
5775
DEALLOCATE(A % ConstrainedDOF)
5776
ALLOCATE(A % ConstrainedDOF(A % NumberOfRows))
5777
A % ConstrainedDOF = .FALSE.
5778
END IF
5779
END IF
5780
5781
IF(.NOT.ALLOCATED(A % Dvalues)) THEN
5782
ALLOCATE(A % Dvalues(A % NumberOfRows))
5783
A % Dvalues = 0._dp
5784
ELSE
5785
IF (SIZE(A % Dvalues) < A % NumberOfRows) THEN
5786
DEALLOCATE(A % Dvalues)
5787
ALLOCATE(A % Dvalues(A % NumberOfRows))
5788
A % Dvalues = 0._dp
5789
END IF
5790
END IF
5791
5792
! Create soft limiters to be later applied by the Dirichlet conditions
5793
! This is done only once for each solver, hence the complex logic.
5794
!---------------------------------------------------------------------
5795
IF( ListGetLogical( Params,'Apply Limiter',Found) ) THEN
5796
IF( ListGetLogical( Params,'Linear System Limiter',Found) ) THEN
5797
! This is intended for cases when the linear solver comes with limiters.
5798
CALL PopulateLimiterValues( Solver )
5799
ELSE
5800
CALL DetermineSoftLimiter( Solver )
5801
5802
! It is difficult to determine whether loads should be computed before or after setting the limiter.
5803
! There are cases where both alternative are needed.
5804
IF(ListGetLogical( Params,'Apply Limiter Loads After',Found) ) THEN
5805
DO DOF=1,x % DOFs
5806
name = TRIM(x % name)
5807
IF (x % DOFs>1) name=ComponentName(name,DOF)
5808
CALL SetNodalLoads( CurrentModel,A,A % rhs, &
5809
Name,DOF,x % DOFs,x % Perm )
5810
END DO
5811
END IF
5812
END IF
5813
END IF
5814
5815
5816
5817
Offset = 0
5818
IF(PRESENT(UOffset)) Offset=UOffset
5819
5820
n = Solver % Mesh % MaxElementDOFs
5821
IF ( .NOT. ALLOCATED( gInd ) ) THEN
5822
ALLOCATE( gInd(n), lInd(n), STIFF(n,n), Work(n), stat=istat )
5823
IF ( istat /= 0 ) &
5824
CALL Fatal('DefUtils::DefaultDirichletBCs','Memory allocation failed.' )
5825
ELSE IF ( SIZE(gInd) < n ) THEN
5826
DEALLOCATE( gInd, lInd, STIFF, Work )
5827
ALLOCATE( gInd(n), lInd(n), STIFF(n,n), Work(n), stat=istat )
5828
IF ( istat /= 0 ) &
5829
CALL Fatal('DefUtils::DefaultDirichletBCs','Memory allocation failed.' )
5830
END IF
5831
5832
ReleaseAny = ListCheckPrefixAnyBC(CurrentModel, 'release '//TRIM(x % name)//' {e}')
5833
IF( ReleaseAny ) THEN
5834
CALL Info('DefaultDirichletBCs','Getting ready to block some Dirichlet BCs!',Level=7)
5835
ALLOCATE( ReleaseDir( SIZE( A % DValues ) ) )
5836
ReleaseDir = .FALSE.
5837
END IF
5838
5839
NodalBCsWithBraces = .FALSE.
5840
NDOFs = MAXVAL(Solver % Def_Dofs(:,:,1))
5841
IF (NDOFs > 0) THEN
5842
DO DOF=1,x % DOFs
5843
name = TRIM(x % name)
5844
IF (x % DOFs > 1) name = ComponentName(name,DOF)
5845
NodalBCsWithBraces = ListCheckPrefixAnyBC(CurrentModel, Name//' {n}')
5846
IF (NodalBCsWithBraces) THEN
5847
CALL Info('DefaultDirichletBCs', '{n} construct is now used to set BCs', Level=7)
5848
CALL Info('DefaultDirichletBCs', I2S(NDOFs)//'-component {n} definition is handled', Level=7)
5849
EXIT
5850
END IF
5851
END DO
5852
END IF
5853
5854
IF ( x % DOFs > 1 ) THEN
5855
CALL SetDirichletBoundaries( CurrentModel,A, b, GetVarName(x),-1,x % DOFs,x % Perm )
5856
END IF
5857
5858
CALL Info('DefUtils::DefaultDirichletBCs', &
5859
'Setting Dirichlet boundary conditions', Level=10)
5860
5861
5862
! ----------------------------------------------------------------------
5863
! Perform some preparations if BCs for p-approximation will be handled:
5864
! ----------------------------------------------------------------------
5865
IF (.NOT. NodalBCsWithBraces) THEN
5866
DO DOF=1,x % DOFs
5867
name = TRIM(x % name)
5868
IF ( x % DOFs > 1 ) name = ComponentName(name,DOF)
5869
5870
IF( .NOT. ListCheckPresentAnyBC( CurrentModel, name ) ) CYCLE
5871
5872
SaveElement => GetCurrentElement()
5873
DO i=1,Solver % Mesh % NumberOfBoundaryElements
5874
Element => GetBoundaryElement(i)
5875
5876
! Get parent element:
5877
! -------------------
5878
Parent => Element % BoundaryInfo % Left
5879
IF ( .NOT. ASSOCIATED( Parent ) ) &
5880
Parent => Element % BoundaryInfo % Right
5881
5882
IF ( .NOT. ASSOCIATED(Parent) ) CYCLE
5883
5884
BC => GetBC(Element)
5885
IF ( .NOT.ASSOCIATED(BC) ) CYCLE
5886
! Element % BodyId = Parent % BodyId
5887
IF ( .NOT. ActiveBoundaryElement(Element) ) CYCLE
5888
5889
ptr => ListFind(BC, Name,Found )
5890
IF ( .NOT. ASSOCIATED(ptr) ) CYCLE
5891
5892
Constantvalue = ( ptr % type /= LIST_TYPE_CONSTANT_SCALAR_PROC )
5893
5894
5895
IF ( isActivePElement(Parent,Solver)) THEN
5896
n = GetElementNOFNodes()
5897
! Get indexes of boundary dofs:
5898
CALL mGetBoundaryIndexesFromParent( Solver % Mesh, Element, gInd, numEdgeDofs )
5899
DO k=n+1,numEdgeDofs
5900
nb = x % Perm( gInd(k) )
5901
IF ( nb <= 0 ) CYCLE
5902
nb = Offset + x % DOFs * (nb-1) + DOF
5903
5904
IF ( ConstantValue ) THEN
5905
A % ConstrainedDOF(nb) = .TRUE.
5906
A % Dvalues(nb) = 0._dp
5907
ELSE
5908
CALL ZeroRow( A, nb )
5909
A % RHS(nb) = 0._dp
5910
END IF
5911
END DO
5912
ELSE
5913
! To do: Check whether BCs for edge/face elements must be set via L2 projection.
5914
CYCLE
5915
END IF
5916
END DO
5917
5918
SaveElement => SetCurrentElement(SaveElement)
5919
END DO
5920
END IF
5921
5922
IF (NodalBCsWithBraces) THEN
5923
CALL Info('DefaultDirichletBCs','Setting nodal dofs with {n} construct', Level=15)
5924
!
5925
! NOTE: This is still simplistic implementation and lacks many options which work
5926
! in the case of standard BCs for nodal (Lagrange) interpolation approximations.
5927
! TO DO: Consider how the functionality of the subroutines SetNodalLoads and SetDirichletBoundaries
5928
! could be enabled in the case of {n} construct.
5929
!
5930
DO DOF=1,x % DOFs
5931
DO m=1,NDOFs
5932
name = TRIM(x % name)
5933
IF ( x % DOFs > 1 ) THEN
5934
name = ComponentName(name,DOF)//' {n}'
5935
ELSE
5936
name = name//' {n}'
5937
END IF
5938
5939
! When the component names are created for example from E[E Re:1 E Im:1], we now have name = "E Re {n}" or "E Im {n}".
5940
! Finally, we append this by the field index, so that we may seek values for "E Re {n} m" and "E Im {n} m", where
5941
! m = 1,...,NDOFs when an element definition "n:NDOFs e:..." is given.
5942
5943
IF (NDOFs > 1) name = name//' '//I2S(m)
5944
5945
! print *, '====== m is ', m
5946
! print *, '====== DOF is ', DOF
5947
! print *, 'operating name ', name
5948
5949
SaveElement => GetCurrentElement()
5950
DO i=1,Solver % Mesh % NumberOfBoundaryElements
5951
Element => GetBoundaryElement(i)
5952
5953
BC => GetBC(Element)
5954
IF ( .NOT.ASSOCIATED(BC) ) CYCLE
5955
IF ( .NOT. ListCheckPresent(BC, TRIM(Name)) ) CYCLE
5956
5957
Cond = SUM(GetReal(BC,GetVarName(Solver % Variable)//' Condition',Found))/n
5958
IF (Cond>0) CYCLE
5959
5960
nd = GetElementDOFs(gInd, Element)
5961
n = Element % TYPE % NumberOfNodes
5962
5963
Work(1:n) = GetReal(BC, Name, Found, Element)
5964
5965
! print *, 'permutation size for single-field', nd
5966
! print *, 'element % ndofs, nofnodes ', element % ndofs, Element % TYPE % NumberOfNodes
5967
! print *, 'global indexes for single field', gind(1:element % ndofs)
5968
! print *, 'the field values ', Work(1:n)
5969
5970
DO j=1,n
5971
k = (j-1) * NDOFs + m
5972
l = x % Perm(gInd(k))
5973
5974
l = x % DOFs * (l-1) + DOF
5975
5976
A % ConstrainedDOF(l) = .TRUE.
5977
A % Dvalues(l) = Work(j)
5978
END DO
5979
END DO
5980
SaveElement => SetCurrentElement(SaveElement)
5981
END DO
5982
END DO
5983
5984
ELSE
5985
! -------------------------------------------------------------------------------------
5986
! Set BCs for fields which are approximated using H1-conforming basis functions
5987
! (either Lagrange basis or hierarchic p-basis):
5988
! -------------------------------------------------------------------------------------
5989
DO DOF=1,x % DOFs
5990
name = TRIM(x % name)
5991
IF (x % DOFs>1) name=ComponentName(name,DOF)
5992
5993
CALL SetDirichletBoundaries( CurrentModel, A, b, &
5994
Name, DOF, x % DOFs, x % Perm, Offset, OffDiagonalMatrix )
5995
5996
! ----------------------------------------------------------------------------
5997
! Set Dirichlet BCs for edge and face dofs which come from approximating with
5998
! p-elements:
5999
! ----------------------------------------------------------------------------
6000
IF( .NOT. ListCheckPresentAnyBC( CurrentModel, name ) ) CYCLE
6001
6002
CALL Info('DefUtils::DefaultDirichletBCs', &
6003
'p-element condition setup: '//name, Level=15)
6004
6005
SaveElement => GetCurrentElement()
6006
DO i=1,Solver % Mesh % NumberOfBoundaryElements
6007
Element => GetBoundaryElement(i)
6008
BC => GetBC()
6009
IF ( .NOT.ASSOCIATED(BC) ) CYCLE
6010
6011
! Get parent element:
6012
! -------------------
6013
Parent => Element % BoundaryInfo % Left
6014
IF ( .NOT. ASSOCIATED( Parent ) ) THEN
6015
Parent => Element % BoundaryInfo % Right
6016
END IF
6017
IF ( .NOT. ASSOCIATED( Parent ) ) CYCLE
6018
6019
! Here set constraints for p-approximation only:
6020
! -----------------------------------------------------
6021
IF (.NOT.isActivePElement(Parent, Solver)) CYCLE
6022
6023
! Element % BodyId = Parent % BodyId
6024
IF ( .NOT. ActiveBoundaryElement(Element) ) CYCLE
6025
6026
IF ( .NOT. ListCheckPresent(BC, Name) ) CYCLE
6027
6028
ptr => ListFind(BC, Name,Found )
6029
Constantvalue = Ptr % Type /= LIST_TYPE_CONSTANT_SCALAR_PROC
6030
6031
IF ( ConstantValue ) CYCLE
6032
6033
SELECT CASE(Parent % Type % Dimension )
6034
CASE(2)
6035
! If no edges do not try to set boundary conditions
6036
! @todo This should changed to EXIT
6037
IF ( .NOT. ASSOCIATED( Solver % Mesh % Edges ) ) CYCLE
6038
6039
! If boundary edge has no dofs move on to next edge
6040
IF (Element % BDOFs <= 0) CYCLE
6041
6042
! Number of nodes for this element
6043
n = Element % TYPE % NumberOfNodes
6044
6045
! Get indexes for boundary and values for dofs associated to them
6046
CALL mGetBoundaryIndexesFromParent( Solver % Mesh, Element, gInd, nd)
6047
CALL LocalBcBDOFs( BC, Element, nd, Name, STIFF, Work )
6048
6049
AllConstrained = .TRUE.
6050
DO l=1,n
6051
nb = x % Perm( gInd(l) )
6052
IF ( nb <= 0 ) CYCLE
6053
nb = Offset + x % DOFs * (nb-1) + DOF
6054
6055
IF(A % ConstrainedDOF(nb)) THEN
6056
s = A % Dvalues(nb)
6057
DO k=n+1,nd
6058
Work(k) = Work(k) - s*STIFF(k,l)
6059
STIFF(k,l) = 0.0_dp
6060
END DO
6061
ELSE
6062
AllConstrained = .FALSE.
6063
END IF
6064
END DO
6065
6066
IF(AllConstrained.AND.CoordinateSystemDimension()<=2) THEN
6067
IF(nd==n+1) THEN
6068
Work(nd) = Work(nd) / STIFF(nd,nd)
6069
ELSE
6070
CALL SolveLinSys(STIFF(n+1:nd,n+1:nd), Work(n+1:nd), nd-n)
6071
END IF
6072
6073
DO l=n+1,nd
6074
nb = x % Perm( gInd(l) )
6075
IF ( nb <= 0 ) CYCLE
6076
nb = Offset + x % DOFs * (nb-1) + DOF
6077
6078
A % Dvalues(nb) = Work(l)
6079
A % ConstrainedDOF(nb) = .TRUE.
6080
END DO
6081
ELSE
6082
! Contribute this boundary to global system
6083
! (i.e solve global boundary problem)
6084
A % Symmetric = .FALSE.
6085
DO k=1,nd
6086
nb = x % Perm( gInd(k) )
6087
IF ( nb <= 0 ) CYCLE
6088
nb = Offset + x % DOFs * (nb-1) + DOF
6089
IF(.NOT.A % ConstrainedDOF(nb)) THEN
6090
A % RHS(nb) = A % RHS(nb) + Work(k)
6091
DO l=n+1,nd
6092
mb = x % Perm( gInd(l) )
6093
IF ( mb <= 0 ) CYCLE
6094
mb = Offset + x % DOFs * (mb-1) + DOF
6095
DO kk=A % Rows(nb)+DOF-1,A % Rows(nb+1)-1,x % DOFs
6096
IF ( A % Cols(kk) == mb ) THEN
6097
A % Values(kk) = A % Values(kk) + STIFF(k,l)
6098
EXIT
6099
END IF
6100
END DO
6101
END DO
6102
END IF
6103
END DO
6104
END IF
6105
6106
CASE(3)
6107
! If no faces present do not try to set boundary conditions
6108
! @todo This should be changed to EXIT
6109
IF ( .NOT. ASSOCIATED(Solver % Mesh % Faces) ) CYCLE
6110
6111
! Parameters of element
6112
n = Element % TYPE % NumberOfNodes
6113
6114
! Get global boundary indexes and solve dofs associated to them
6115
CALL mGetBoundaryIndexesFromParent( Solver % Mesh, Element, gInd, nd )
6116
6117
! If boundary face has no dofs skip to next boundary element
6118
IF (nd == n) CYCLE
6119
6120
! Get local solution
6121
CALL LocalBcBDofs( BC, Element, nd, Name, STIFF, Work )
6122
6123
DO l=1,n
6124
nb = x % Perm( gInd(l) )
6125
IF ( nb <= 0 ) CYCLE
6126
nb = Offset + x % DOFs * (nb-1) + DOF
6127
6128
IF(A % ConstrainedDOF(nb)) THEN
6129
s = A % Dvalues(nb)
6130
DO k=n+1,nd
6131
Work(k) = Work(k) - s*STIFF(k,l)
6132
STIFF(k,l) = 0
6133
STIFF(l,k) = 0
6134
END DO
6135
END IF
6136
END DO
6137
6138
! Contribute this entry to global boundary problem
6139
A % Symmetric = .FALSE.
6140
DO k=1,nd
6141
nb = x % Perm( gInd(k) )
6142
IF ( nb <= 0 ) CYCLE
6143
nb = Offset + x % DOFs * (nb-1) + DOF
6144
6145
IF(.NOT.A % ConstrainedDOF(nb)) THEN
6146
A % RHS(nb) = A % RHS(nb) + Work(k)
6147
DO l=n+1,nd
6148
mb = x % Perm( gInd(l) )
6149
IF ( mb <= 0 ) CYCLE
6150
mb = Offset + x % DOFs * (mb-1) + DOF
6151
DO kk=A % Rows(nb)+DOF-1,A % Rows(nb+1)-1,x % DOFs
6152
IF ( A % Cols(kk) == mb ) THEN
6153
A % Values(kk) = A % Values(kk) + STIFF(k,l)
6154
EXIT
6155
END IF
6156
END DO
6157
END DO
6158
END IF
6159
END DO
6160
END SELECT
6161
END DO
6162
6163
SaveElement => SetCurrentElement(SaveElement)
6164
END DO
6165
END IF
6166
6167
! BLOCK
6168
!------------------------------------
6169
DO DOF=1,x % DOFs
6170
IF(.NOT. ReleaseAny) CYCLE
6171
6172
name = TRIM(x % name)
6173
IF (x % DOFs>1) name=ComponentName(name,DOF)
6174
6175
IF ( .NOT. ListCheckPrefixAnyBC(CurrentModel, 'release '//TRIM(Name)//' {e}') ) CYCLE
6176
6177
CALL Info('SetDefaultDirichlet','Release edge dofs from intersecting BCs',Level=15)
6178
6179
SaveElement => GetCurrentElement()
6180
DO i=1,Solver % Mesh % NumberOfBoundaryElements
6181
Element => GetBoundaryElement(i)
6182
6183
BC => GetBC()
6184
IF ( .NOT.ASSOCIATED(BC) ) CYCLE
6185
IF ( .NOT. ListGetLogical(BC, 'release '//TRIM(Name)//' {e}', Found ) ) CYCLE
6186
6187
! Get parent element:
6188
! -------------------
6189
Parent => Element % BoundaryInfo % Left
6190
IF ( .NOT. ASSOCIATED( Parent ) ) THEN
6191
Parent => Element % BoundaryInfo % Right
6192
END IF
6193
IF ( .NOT. ASSOCIATED( Parent ) ) CYCLE
6194
np = Parent % TYPE % NumberOfNodes
6195
6196
IF(.NOT. ASSOCIATED( Solver % Mesh % Edges ) ) CYCLE
6197
SELECT CASE(GetElementFamily(Element))
6198
6199
CASE(3,4)
6200
CALL PickActiveFace(Solver % Mesh, Parent, Element, Face, j)
6201
6202
IF (.NOT. ASSOCIATED(Face)) CYCLE
6203
Face % BodyId = Parent % BodyId
6204
IF ( .NOT. ActiveBoundaryElement(Face) ) CYCLE
6205
6206
DO l=1,Face % TYPE % NumberOfEdges
6207
Edge => Solver % Mesh % Edges(Face % EdgeIndexes(l))
6208
EDOFs = Edge % BDOFs
6209
IF (EDOFs == 0) CYCLE
6210
6211
Edge % BodyId = Parent % BodyId
6212
n = GetElementDOFs(gInd,Edge)
6213
6214
IF (Solver % Def_Dofs(2,Parent % BodyId,1) > 0) THEN
6215
n_start = Edge % NDOFs
6216
ELSE
6217
n_start = 0
6218
END IF
6219
6220
DO j=1,EDOFs
6221
k = n_start + j
6222
nb = x % Perm(gInd(k))
6223
IF ( nb <= 0 ) CYCLE
6224
nb = Offset + x % DOFs*(nb-1) + DOF
6225
ReleaseDir(nb) = .TRUE.
6226
END DO
6227
END DO
6228
END SELECT
6229
END DO
6230
SaveElement => SetCurrentElement(SaveElement)
6231
END DO
6232
6233
6234
!
6235
! Apply special couple loads for 3-D models of solids:
6236
!
6237
CALL SetCoupleLoads(CurrentModel, x % Perm, A, b, x % DOFs )
6238
6239
! ----------------------------------------------------------------------------
6240
! Set Dirichlet BCs for edge and face dofs which arise from approximating with
6241
! edge (curl-conforming) or face (div-conforming) elements:
6242
! ----------------------------------------------------------------------------
6243
CALL EdgeElementStyle(Params, PiolaTransform, SecondKindBasis, BasisDegree = BasisDegree)
6244
SimplicialElements = ListGetLogical(Params, 'Simplicial Mesh', Found)
6245
6246
DO DOF=1,x % DOFs
6247
name = TRIM(x % name)
6248
IF (x % DOFs>1) name=ComponentName(name,DOF)
6249
6250
IF ( .NOT. ListCheckPrefixAnyBC(CurrentModel, Name//' {e}') .AND. &
6251
.NOT. ListCheckPrefixAnyBC(CurrentModel, Name//' {f}') ) CYCLE
6252
6253
CALL Info('SetDefaultDirichlet','Setting edge and face dofs',Level=15)
6254
6255
SaveElement => GetCurrentElement()
6256
DO i=1,Solver % Mesh % NumberOfBoundaryElements
6257
Element => GetBoundaryElement(i)
6258
6259
BC => GetBC(Element)
6260
IF ( .NOT.ASSOCIATED(BC) ) CYCLE
6261
IF ( .NOT. ListCheckPrefix(BC, Name//' {e}') .AND. &
6262
.NOT. ListCheckPrefix(BC, Name//' {f}') ) CYCLE
6263
6264
Cond = SUM(GetReal(BC,GetVarName(Solver % Variable)//' Condition',Found))/n
6265
IF(Cond>0) CYCLE
6266
6267
! Get parent element:
6268
! -------------------
6269
Parent => Element % BoundaryInfo % Left
6270
IF ( ASSOCIATED( Parent ) ) THEN
6271
IF (Parent % BodyId < 1) THEN
6272
CheckRight = .TRUE.
6273
ELSE
6274
CheckRight = .FALSE.
6275
END IF
6276
ELSE
6277
CheckRight = .TRUE.
6278
END IF
6279
6280
IF (CheckRight) THEN
6281
Parent => Element % BoundaryInfo % Right
6282
IF ( ASSOCIATED( Parent ) ) THEN
6283
IF (Parent % BodyId < 1) THEN
6284
CALL Warn('SetDefaultDirichlet', 'Cannot set a BC owing to a missing parent body index')
6285
CYCLE
6286
END IF
6287
END IF
6288
END IF
6289
IF ( .NOT. ASSOCIATED( Parent ) ) CYCLE
6290
np = Parent % TYPE % NumberOfNodes
6291
6292
IF ( ListCheckPrefix(BC, Name//' {e}') ) THEN
6293
!--------------------------------------------------------------------------------
6294
! We now devote this branch for handling edge (curl-conforming) finite elements
6295
! which, in addition to edge DOFs, may also have DOFs associated with faces.
6296
!--------------------------------------------------------------------------------
6297
IF ( ASSOCIATED( Solver % Mesh % Edges ) ) THEN
6298
SELECT CASE(GetElementFamily(Element))
6299
CASE(2)
6300
6301
CALL PickActiveFace(Solver % Mesh, Parent, Element, Edge, j)
6302
6303
IF ( .NOT. ASSOCIATED(Edge) ) CYCLE
6304
Edge % BodyId = Parent % BodyId
6305
IF ( .NOT. ActiveBoundaryElement(Edge) ) CYCLE
6306
6307
EDOFs = Edge % BDOFs ! The number of DOFs associated with edges
6308
IF (EDOFs < 1) CYCLE
6309
6310
AugmentedEigenSystem = ListGetLogical(Params, 'Eigen System Augmentation', Found)
6311
IF (AugmentedEigenSystem) THEN
6312
EDOFs = EDOFs/2
6313
END IF
6314
6315
n = Edge % TYPE % NumberOfNodes
6316
CALL VectorElementEdgeDOFs(BC,Edge,n,Parent,np,Name//' {e}',Work, &
6317
EDOFs, SecondKindBasis, BasisDegree = BasisDegree, &
6318
SimplicialMesh = SimplicialElements)
6319
6320
n=GetElementDOFs(gInd,Edge)
6321
6322
IF (Solver % Def_Dofs(2,Parent % BodyId,1) > 0) THEN
6323
n_start = Edge % NDOFs
6324
ELSE
6325
n_start = 0
6326
END IF
6327
6328
DO j=1,EDOFs
6329
IF (AugmentedEigenSystem) THEN
6330
k = n_start + 2*j - 1
6331
ELSE
6332
k = n_start + j
6333
END IF
6334
nb = x % Perm(gInd(k))
6335
IF ( nb <= 0 ) CYCLE
6336
nb = Offset + x % DOFs*(nb-1) + DOF
6337
6338
A % ConstrainedDOF(nb) = .TRUE.
6339
A % Dvalues(nb) = Work(j)
6340
END DO
6341
6342
CASE(3,4)
6343
CALL PickActiveFace(Solver % Mesh, Parent, Element, Face, j)
6344
6345
IF (.NOT. ASSOCIATED(Face)) CYCLE
6346
Face % BodyId = Parent % BodyId
6347
IF ( .NOT. ActiveBoundaryElement(Face) ) CYCLE
6348
6349
! ---------------------------------------------------------------------
6350
! Set first constraints for DOFs associated with edges. Save the values
6351
! of DOFs in the array Work(:), so that the possible remaining DOFs
6352
! associated with the face can be computed after this.
6353
! ---------------------------------------------------------------------
6354
i0 = 0
6355
DO l=1,Face % TYPE % NumberOfEdges
6356
Edge => Solver % Mesh % Edges(Face % EdgeIndexes(l))
6357
EDOFs = Edge % BDOFs
6358
IF (EDOFs < 1) CYCLE
6359
6360
Edge % BodyId = Parent % BodyId
6361
n = Edge % TYPE % NumberOfNodes
6362
6363
CALL VectorElementEdgeDOFs(BC, Edge, n, Parent, np, Name//' {e}', &
6364
Work(i0+1:i0+EDOFs), EDOFs, SecondKindBasis, &
6365
BasisDegree = BasisDegree, &
6366
SimplicialMesh = SimplicialElements)
6367
6368
n = GetElementDOFs(gInd,Edge)
6369
6370
IF (Solver % Def_Dofs(2,Parent % BodyId,1) > 0) THEN
6371
n_start = Edge % NDOFs
6372
ELSE
6373
n_start = 0
6374
END IF
6375
6376
DO j=1,EDOFs
6377
k = n_start + j
6378
nb = x % Perm(gInd(k))
6379
IF ( nb <= 0 ) CYCLE
6380
nb = Offset + x % DOFs*(nb-1) + DOF
6381
6382
A % ConstrainedDOF(nb) = .TRUE.
6383
A % Dvalues(nb) = Work(i0+j)
6384
END DO
6385
i0 = i0 + EDOFs
6386
END DO
6387
6388
! ---------------------------------------------------------------------
6389
! Set constraints for face DOFs via seeking the best approximation in L2.
6390
! We use the variational equation (u x n,v') = (g x n - u0 x n,v) where
6391
! u0 denotes the part of the interpolating function u+u0 which is already
6392
! known and v is a test function for the Galerkin method.
6393
! ---------------------------------------------------------------------
6394
IF (Face % BDOFs > 0) THEN
6395
EDOFs = i0 ! The count of edge DOFs set so far
6396
n = Face % TYPE % NumberOfNodes
6397
6398
CALL SolveLocalFaceDOFs(BC, Face, n, Name//' {e}', Work, EDOFs, &
6399
Face % BDOFs, SecondKindBasis, BasisDegree)
6400
6401
Face % BodyId = Parent % BodyId
6402
6403
n = GetElementDOFs(GInd,Face)
6404
DO j=1,Face % BDOFs
6405
nb = x % Perm(GInd(n-Face % BDOFs+j)) ! The last entries should be face-DOF indices
6406
IF ( nb <= 0 ) CYCLE
6407
nb = Offset + x % DOFs*(nb-1) + DOF
6408
6409
A % ConstrainedDOF(nb) = .TRUE.
6410
A % Dvalues(nb) = Work(EDOFs+j)
6411
END DO
6412
END IF
6413
6414
END SELECT
6415
END IF
6416
ELSE IF ( ListCheckPrefix(BC, Name//' {f}') ) THEN
6417
!--------------------------------------------------------------------------
6418
! This branch should be able to handle BCs for face (div-conforming)
6419
! elements. Now this works only for RT(0), ABF(0) and BMD(1) in 2D and
6420
! for a 48-DOF brick and the Nedelec tetrahedron of the first and second kind
6421
! in 3D.
6422
!--------------------------------------------------------------------------
6423
SELECT CASE(GetElementFamily())
6424
CASE(2)
6425
6426
CALL PickActiveFace(Solver % Mesh, Parent, Element, Edge, j)
6427
6428
IF (.NOT. ASSOCIATED(Edge)) CYCLE
6429
Edge % BodyId = Parent % BodyId
6430
IF ( .NOT. ActiveBoundaryElement(Edge) ) CYCLE
6431
6432
EDOFs = Edge % BDOFs ! The number of DOFs associated with edges
6433
6434
IF (EDOFs < 1) CYCLE
6435
6436
n = Edge % TYPE % NumberOfNodes
6437
CALL VectorElementEdgeDOFs(BC,Edge,n,Parent,np,Name//' {f}',Work, &
6438
EDOFs, SecondKindBasis, FaceElement=.TRUE.)
6439
6440
n=GetElementDOFs(gInd,Edge)
6441
6442
IF (Solver % Def_Dofs(2,Parent % BodyId,1) > 0) THEN
6443
n_start = Edge % NDOFs
6444
ELSE
6445
n_start = 0
6446
END IF
6447
DO j=1,EDOFs
6448
k = n_start + j
6449
nb = x % Perm(gInd(k))
6450
IF ( nb <= 0 ) CYCLE
6451
nb = Offset + x % DOFs*(nb-1) + DOF
6452
6453
A % ConstrainedDOF(nb) = .TRUE.
6454
A % Dvalues(nb) = Work(j)
6455
END DO
6456
6457
CASE(3)
6458
6459
CALL PickActiveFace(Solver % Mesh, Parent, Element, Face, ActiveFaceId)
6460
6461
IF (.NOT. ASSOCIATED(Face)) CYCLE
6462
Face % BodyId = Parent % BodyId
6463
IF ( .NOT. ActiveBoundaryElement(Face) ) CYCLE
6464
6465
FDOFs = Face % BDOFs
6466
6467
IF (FDOFs > 0) THEN
6468
CALL FaceElementOrientation(Parent, ReverseSign, ActiveFaceId)
6469
IF (SecondKindBasis) &
6470
CALL FaceElementBasisOrdering(Parent, FDofMap, ActiveFaceId)
6471
n = Face % TYPE % NumberOfNodes
6472
6473
CALL FaceElementDOFs(BC, Face, n, Parent, ActiveFaceId, &
6474
Name//' {f}', Work, FDOFs, SecondKindBasis)
6475
6476
IF (SecondKindBasis) THEN
6477
!
6478
! Conform to the orientation and ordering used in the
6479
! assembly of the global equations
6480
!
6481
DefaultDOFs(1:FDOFs) = Work(1:FDOFs)
6482
IF (ReverseSign(ActiveFaceId)) THEN
6483
S = -1.0d0
6484
ELSE
6485
S = 1.0d0
6486
END IF
6487
6488
DO j=1,FDOFs
6489
k = FDofMap(ActiveFaceId,j)
6490
Work(j) = S * DefaultDOFs(k)
6491
END DO
6492
ELSE
6493
IF (ReverseSign(ActiveFaceId)) Work(1:FDOFs) = -1.0d0*Work(1:FDOFs)
6494
END IF
6495
6496
n = GetElementDOFs(GInd,Face)
6497
!
6498
! Make an offset by the count of nodal DOFs. This provides
6499
! the right starting point if edge DOFs are not present.
6500
!
6501
IF (Solver % Def_Dofs(3,Parent % BodyId,1) > 0) THEN
6502
n_start = Face % NDOFs
6503
ELSE
6504
n_start = 0
6505
END IF
6506
!
6507
! Check if we need to increase the offset by the count of
6508
! edge DOFs:
6509
!
6510
IF ( ASSOCIATED(Face % EdgeIndexes) .AND. &
6511
Solver % Def_Dofs(3,Parent % BodyId,2) > 0) THEN
6512
EDOFs = 0
6513
DO l=1,Face % TYPE % NumberOfEdges
6514
Edge => Solver % Mesh % Edges(Face % EdgeIndexes(l))
6515
EDOFs = EDOFs + Edge % BDOFs
6516
END DO
6517
n_start = n_start + EDOFs
6518
END IF
6519
6520
DO j=1,FDOFs
6521
k = n_start + j
6522
nb = x % Perm(gInd(k))
6523
IF ( nb <= 0 ) CYCLE
6524
nb = Offset + x % DOFs*(nb-1) + DOF
6525
6526
A % ConstrainedDOF(nb) = .TRUE.
6527
A % Dvalues(nb) = Work(j)
6528
END DO
6529
END IF
6530
6531
CASE(4)
6532
6533
CALL PickActiveFace(Solver % Mesh, Parent, Element, Face, ActiveFaceId)
6534
6535
IF (.NOT. ASSOCIATED(Face)) CYCLE
6536
Face % BodyId = Parent % BodyId
6537
IF ( .NOT. ActiveBoundaryElement(Face) ) CYCLE
6538
6539
FDOFs = Face % BDOFs
6540
6541
IF (FDOFs > 0) THEN
6542
CALL FaceElementBasisOrdering(Parent, FDofMap, ActiveFaceId, ReverseSign)
6543
n = Face % TYPE % NumberOfNodes
6544
6545
CALL FaceElementDOFs(BC, Face, n, Parent, ActiveFaceId, &
6546
Name//' {f}', Work, FDOFs)
6547
6548
!
6549
! Conform to the orientation and ordering used in the
6550
! assembly of the global equations
6551
!
6552
DefaultDOFs(1:FDOFs) = Work(1:FDOFs)
6553
IF (ReverseSign(ActiveFaceId)) THEN
6554
S = -1.0d0
6555
ELSE
6556
S = 1.0d0
6557
END IF
6558
6559
DO j=1,FDOFs
6560
k = FDofMap(ActiveFaceId,j)
6561
Work(j) = S * DefaultDOFs(k)
6562
END DO
6563
6564
n = GetElementDOFs(GInd,Face)
6565
6566
!
6567
! Make an offset by the count of nodal DOFs. This provides
6568
! the right starting point if edge DOFs are not present.
6569
!
6570
IF (Solver % Def_Dofs(4,Parent % BodyId,1) > 0) THEN
6571
n_start = Face % NDOFs
6572
ELSE
6573
n_start = 0
6574
END IF
6575
!
6576
! Check if we need to increase the offset by the count of
6577
! edge DOFs:
6578
!
6579
IF ( ASSOCIATED(Face % EdgeIndexes) .AND. &
6580
Solver % Def_Dofs(4,Parent % BodyId,2) > 0) THEN
6581
EDOFs = 0
6582
DO l=1,Face % TYPE % NumberOfEdges
6583
Edge => Solver % Mesh % Edges(Face % EdgeIndexes(l))
6584
EDOFs = EDOFs + Edge % BDOFs
6585
END DO
6586
n_start = n_start + EDOFs
6587
END IF
6588
6589
DO j=1,FDOFs
6590
k = n_start + j
6591
nb = x % Perm(gInd(k))
6592
IF ( nb <= 0 ) CYCLE
6593
nb = Offset + x % DOFs*(nb-1) + DOF
6594
6595
A % ConstrainedDOF(nb) = .TRUE.
6596
A % Dvalues(nb) = Work(j)
6597
END DO
6598
END IF
6599
6600
CASE DEFAULT
6601
CALL Warn('DefaultDirichletBCs', 'Cannot set face element DOFs for this element shape')
6602
END SELECT
6603
END IF
6604
END DO
6605
SaveElement => SetCurrentElement(SaveElement)
6606
END DO
6607
6608
IF( ReleaseAny) THEN
6609
IF( InfoActive(20) ) THEN
6610
k = COUNT( A % ConstrainedDOF )
6611
CALL Info('DefaultDirichletBCs', &
6612
'Original number of of Dirichlet BCs: '//I2S(k))
6613
k = COUNT( ReleaseDir )
6614
CALL Info('DefaultDirichletBCs',&
6615
'Marked number of Dirichlet BCs not to set: '//I2S(k))
6616
k = COUNT( ReleaseDir .AND. A % ConstrainedDOF )
6617
CALL Info('DefaultDirichletBCs',&
6618
'Ignoring number of Dirichlet BCs: '//I2S(k))
6619
END IF
6620
WHERE( ReleaseDir )
6621
A % ConstrainedDOF = .FALSE.
6622
END WHERE
6623
END IF
6624
6625
! Add the possible constraint modes structures
6626
!----------------------------------------------------------
6627
IF ( GetLogical(Params,'Constraint Modes Analysis',Found) ) THEN
6628
CALL SetConstraintModesBoundaries( CurrentModel, Solver, A, b, x % Name, x % DOFs, x % Perm )
6629
END IF
6630
6631
#ifdef HAVE_FETI4I
6632
IF(C_ASSOCIATED(A % PermonMatrix)) THEN
6633
CALL Info('DefUtils::DefaultDirichletBCs','Permon matrix, Dirichlet conditions registered but not set!', Level=5)
6634
RETURN
6635
END IF
6636
#endif
6637
6638
! This is set outside so that it can be called more flexibilly
6639
CALL EnforceDirichletConditions( Solver, A, b )
6640
6641
6642
CALL Info('DefUtils::DefaultDirichletBCs','Dirichlet boundary conditions set', Level=12)
6643
!------------------------------------------------------------------------------
6644
END SUBROUTINE DefaultDirichletBCs
6645
!------------------------------------------------------------------------------
6646
6647
6648
!------------------------------------------------------------------------------
6649
!> This subroutine computes the values of DOFs that are associated with
6650
!> mesh edges in the case of vector-valued (edge or face) finite elements, so that
6651
!> the vector-valued interpolant of the BC data can be constructed.
6652
!> The values of the DOFs are defined as D = S*(g.e,v)_E where the unit vector e
6653
!> can be either tangential or normal to the edge, g is vector-valued data,
6654
!> v is a polynomial on the edge E, and S reverses sign if necessary.
6655
!------------------------------------------------------------------------------
6656
SUBROUTINE VectorElementEdgeDOFs(BC, Element, n, Parent, np, Name, Integral, EDOFs, &
6657
SecondFamily, FaceElement, BasisDegree, SimplicialMesh)
6658
!------------------------------------------------------------------------------
6659
USE ElementDescription, ONLY: GetEdgeMap
6660
IMPLICIT NONE
6661
6662
TYPE(ValueList_t), POINTER :: BC !< The list of boundary condition values
6663
TYPE(Element_t), POINTER :: Element !< The boundary element handled
6664
INTEGER :: n !< The number of boundary element nodes
6665
TYPE(Element_t) :: Parent !< The parent element of the boundary element
6666
INTEGER :: np !< The number of parent element nodes
6667
CHARACTER(LEN=*) :: Name !< The name of boundary condition
6668
REAL(KIND=dp) :: Integral(:) !< The values of DOFs
6669
INTEGER, OPTIONAL :: EDOFs !< The number of DOFs
6670
LOGICAL, OPTIONAL :: SecondFamily !< To select the element family
6671
LOGICAL, OPTIONAL :: FaceElement !< If .TRUE., e is normal to the edge
6672
INTEGER, OPTIONAL :: BasisDegree
6673
LOGICAL, OPTIONAL :: SimplicialMesh
6674
!------------------------------------------------------------------------------
6675
TYPE(Nodes_t), SAVE :: Nodes, Pnodes
6676
TYPE(ElementType_t), POINTER :: SavedType
6677
TYPE(GaussIntegrationPoints_t) :: IP
6678
6679
LOGICAL :: Lstat, ReverseSign, SecondKindBasis, DivConforming
6680
LOGICAL :: SecondOrder, ThirdOrder
6681
LOGICAL :: Simplicial, ErvinStyle = .FALSE.
6682
INTEGER, POINTER :: Edgemap(:,:)
6683
INTEGER :: i,j,k,p,DOFs
6684
INTEGER :: i1,i2,i3
6685
6686
REAL(KIND=dp) :: Basis(n),Load(n),Vload(3,n),VL(3),e(3),d(3)
6687
REAL(KIND=dp) :: E21(3),E32(3)
6688
REAL(KIND=dp) :: u,v,L,s,DetJ,sgn
6689
!------------------------------------------------------------------------------
6690
DOFs = 1
6691
IF (PRESENT(EDOFs)) THEN
6692
IF (EDOFs > 3) THEN
6693
CALL Fatal('VectorElementEdgeDOFs','Cannot handle more than 3 DOFs per edge')
6694
ELSE
6695
DOFs = EDOFs
6696
END IF
6697
END IF
6698
6699
SecondOrder = .FALSE.
6700
ThirdOrder = .FALSE.
6701
IF (PRESENT(BasisDegree)) THEN
6702
SecondOrder = BasisDegree == 2
6703
IF (.NOT. SecondOrder) ThirdOrder = BasisDegree == 3
6704
ELSE
6705
6706
END IF
6707
6708
IF (PRESENT(SecondFamily)) THEN
6709
SecondKindBasis = SecondFamily
6710
IF (SecondKindBasis) THEN
6711
IF (SecondOrder) THEN
6712
IF (DOFs /= 3) CALL Fatal('VectorElementEdgeDOFs','3 DOFs per edge expected')
6713
ELSE
6714
IF (DOFs /= 2) CALL Fatal('VectorElementEdgeDOFs','2 DOFs per edge expected')
6715
END IF
6716
END IF
6717
ELSE
6718
SecondKindBasis = .FALSE.
6719
END IF
6720
6721
IF (PRESENT(FaceElement)) THEN
6722
DivConforming = FaceElement
6723
ELSE
6724
DivConforming = .FALSE.
6725
END IF
6726
6727
IF (PRESENT(SimplicialMesh)) THEN
6728
Simplicial = SimplicialMesh
6729
ELSE
6730
Simplicial = .FALSE.
6731
END IF
6732
6733
! Get the nodes of the boundary and parent elements:
6734
!CALL GetElementNodes(Nodes, Element)
6735
!CALL GetElementNodes(PNodes, Parent)
6736
!Remove references to DefUtils
6737
CALL CopyElementNodesFromMesh(Nodes, CurrentModel % Solver % Mesh, &
6738
n, Element % NodeIndexes)
6739
CALL CopyElementNodesFromMesh(PNodes, CurrentModel % Solver % Mesh, &
6740
np, Parent % NodeIndexes)
6741
6742
6743
ReverseSign = .FALSE.
6744
sgn = 1.0d0
6745
EdgeMap => GetEdgeMap(GetElementFamily(Parent))
6746
DO i=1,SIZE(EdgeMap,1)
6747
j=EdgeMap(i,1)
6748
k=EdgeMap(i,2)
6749
IF ( Parent % NodeIndexes(j)==Element % NodeIndexes(1) .AND. &
6750
Parent % NodeIndexes(k)==Element % NodeIndexes(2) ) THEN
6751
EXIT
6752
ELSE IF (Parent % NodeIndexes(j)==Element % NodeIndexes(2) .AND. &
6753
Parent % NodeIndexes(k)==Element % NodeIndexes(1) ) THEN
6754
! This is the right edge but has opposite orientation as compared
6755
! with the listing of the parent element edges
6756
ReverseSign = .TRUE.
6757
sgn = -1.0d0
6758
EXIT
6759
END IF
6760
END DO
6761
6762
Load(1:n) = GetReal( BC, Name, Lstat, Element )
6763
6764
i = LEN_TRIM(Name)
6765
VLoad(1,1:n) = GetReal(BC,Name(1:i)//' 1',Lstat,element)
6766
VLoad(2,1:n) = GetReal(BC,Name(1:i)//' 2',Lstat,element)
6767
VLoad(3,1:n) = GetReal(BC,Name(1:i)//' 3',Lstat,element)
6768
6769
e(1) = PNodes % x(k) - PNodes % x(j)
6770
e(2) = PNodes % y(k) - PNodes % y(j)
6771
e(3) = PNodes % z(k) - PNodes % z(j)
6772
e = e/SQRT(SUM(e**2))
6773
IF (DivConforming) THEN
6774
! The boundary normal is needed instead of the tangent vector.
6775
! First, find the element director d that makes the parent
6776
! element an oriented surface.
6777
i1 = EdgeMap(1,1)
6778
i2 = EdgeMap(1,2)
6779
i3 = EdgeMap(2,2)
6780
E21(1) = PNodes % x(i2) - PNodes % x(i1)
6781
E21(2) = PNodes % y(i2) - PNodes % y(i1)
6782
E21(3) = PNodes % z(i2) - PNodes % z(i1)
6783
E32(1) = PNodes % x(i3) - PNodes % x(i2)
6784
E32(2) = PNodes % y(i3) - PNodes % y(i2)
6785
E32(3) = PNodes % z(i3) - PNodes % z(i2)
6786
d = CrossProduct(E21, E32)
6787
d = d/SQRT(SUM(d**2))
6788
! Set e to be the outward normal to the parent element:
6789
e = CrossProduct(e, d)
6790
END IF
6791
6792
Integral = 0._dp
6793
IF (SecondOrder .AND. SecondKindBasis) THEN
6794
IP = GaussPoints(Element,3)
6795
ELSE
6796
IP = GaussPoints(Element)
6797
END IF
6798
6799
DO p=1,IP % n
6800
Lstat = ElementInfo( Element, Nodes, IP % u(p), &
6801
IP % v(p), IP % w(p), DetJ, Basis )
6802
s = IP % s(p) * DetJ
6803
6804
L = SUM(Load(1:n)*Basis(1:n))
6805
VL = MATMUL(Vload(:,1:n),Basis(1:n))
6806
6807
IF (SecondKindBasis) THEN
6808
u = IP % u(p)
6809
IF (SecondOrder) THEN
6810
Integral(1)=Integral(1)+s*(L+SUM(VL*e))
6811
v = -3.0d0 * u
6812
Integral(2)=Integral(2)+sgn*s*(L+SUM(VL*e))*v
6813
v = 2.5d0 * (1.0d0 - 3.0d0 * u**2)
6814
Integral(3)=Integral(3)+s*(L+SUM(VL*e))*v
6815
ELSE
6816
IF (ErvinStyle .OR. DivConforming) THEN
6817
v = 0.5d0*(1.0d0-sqrt(3.0d0)*u)
6818
Integral(1)=Integral(1)+s*(L+SUM(VL*e))*v
6819
v = 0.5d0*(1.0d0+sqrt(3.0d0)*u)
6820
Integral(2)=Integral(2)+s*(L+SUM(VL*e))*v
6821
ELSE
6822
Integral(1)=Integral(1)+s*(L+SUM(VL*e))
6823
v = -3.0d0 * u
6824
Integral(2)=Integral(2)+sgn*s*(L+SUM(VL*e))*v
6825
END IF
6826
END IF
6827
ELSE
6828
u = IP % u(p)
6829
IF (ThirdOrder .AND. Simplicial) THEN
6830
! This is the same as the case of second-kind basis of degree 2
6831
! TO DO: restructure to avoid repetition
6832
Integral(1)=Integral(1)+s*(L+SUM(VL*e))
6833
v = -3.0d0 * u
6834
Integral(2)=Integral(2)+sgn*s*(L+SUM(VL*e))*v
6835
v = 2.5d0 * (1.0d0 - 3.0d0 * u**2)
6836
Integral(3)=Integral(3)+s*(L+SUM(VL*e))*v
6837
ELSE IF (SecondOrder .AND. Simplicial) THEN
6838
! This is analogous to the case of second-kind basis
6839
Integral(1)=Integral(1)+s*(L+SUM(VL*e))
6840
v = -3.0d0 * u
6841
Integral(2)=Integral(2)+sgn*s*(L+SUM(VL*e))*v
6842
ELSE
6843
Integral(1)=Integral(1)+s*(L+SUM(VL*e))
6844
IF (.NOT. DivConforming) THEN
6845
! This branch is concerned with the second-order curl-conforming elements
6846
IF (DOFs>1) THEN
6847
v = Basis(2)-Basis(1)
6848
! The parent element must define the default for the positive tangent associated
6849
! with the edge. Thus, if the boundary element handled has an opposite orientation,
6850
! the sign must be reversed to get the positive coordinate associated with the
6851
! parent element edge.
6852
IF (ReverseSign) v = -1.0d0*v
6853
Integral(2)=Integral(2)+s*(L+SUM(VL*e))*v
6854
END IF
6855
END IF
6856
END IF
6857
END IF
6858
END DO
6859
6860
j = Parent % NodeIndexes(j)
6861
IF ( ParEnv % PEs>1 ) &
6862
j=CurrentModel % Mesh % ParallelInfo % GlobalDOFs(j)
6863
6864
k = Parent % NodeIndexes(k)
6865
IF ( ParEnv % PEs>1 ) &
6866
k=CurrentModel % Mesh % ParallelInfo % GlobalDOFs(k)
6867
6868
IF (k < j) THEN
6869
IF (SecondKindBasis) THEN
6870
IF (SecondOrder) THEN
6871
Integral(1)=-Integral(1)
6872
Integral(3)=-Integral(3)
6873
ELSE
6874
IF (ErvinStyle .OR. DivConforming) THEN
6875
Integral(1)=-Integral(1)
6876
Integral(2)=-Integral(2)
6877
ELSE
6878
Integral(1)=-Integral(1)
6879
END IF
6880
END IF
6881
ELSE
6882
Integral(1)=-Integral(1)
6883
END IF
6884
END IF
6885
!------------------------------------------------------------------------------
6886
END SUBROUTINE VectorElementEdgeDOFs
6887
!------------------------------------------------------------------------------
6888
6889
6890
!------------------------------------------------------------------------------
6891
!> This subroutine computes the values of DOFs that are associated with
6892
!> mesh faces in the case of curl-conforming (edge) finite elements, so that
6893
!> the edge finite element interpolant of the BC data can be constructed.
6894
!> The values of the DOFs are obtained as the best approximation in L2 when
6895
!> the values of the DOFs associated with edges are given.
6896
!------------------------------------------------------------------------------
6897
SUBROUTINE SolveLocalFaceDOFs(BC, Element, n, Name, DOFValues, &
6898
EDOFs, FDOFs, SecondKindBasis, BasisDegree)
6899
!------------------------------------------------------------------------------
6900
IMPLICIT NONE
6901
6902
TYPE(ValueList_t), POINTER :: BC !< The list of boundary condition values
6903
TYPE(Element_t), POINTER :: Element !< The boundary element handled
6904
INTEGER :: n !< The number of boundary element nodes
6905
CHARACTER(LEN=*) :: Name !< The name of boundary condition
6906
REAL(KIND=dp) :: DOFValues(:) !< The values of DOFs
6907
INTEGER :: EDOFs !< The number of edge DOFs
6908
INTEGER :: FDOFs !< The number of face DOFs
6909
LOGICAL :: SecondKindBasis !< Use Nedelec's second family
6910
INTEGER :: BasisDegree !< The polynomial order of basis
6911
!------------------------------------------------------------------------------
6912
TYPE(Nodes_t), SAVE :: Nodes
6913
TYPE(GaussIntegrationPoints_t) :: IP
6914
6915
LOGICAL :: Lstat
6916
6917
INTEGER :: i,j,p,DOFs
6918
6919
REAL(KIND=dp) :: Basis(n),Vload(3,n),VL(3),Normal(3)
6920
REAL(KIND=dp) :: EdgeBasis(EDOFs+FDOFs,3)
6921
REAL(KIND=dp) :: Mass(FDOFs,FDOFs), Force(FDOFs)
6922
REAL(KIND=dp) :: v,s,DetJ
6923
!------------------------------------------------------------------------------
6924
6925
Mass = 0.0d0
6926
Force = 0.0d0
6927
6928
! Remove dependencies to DefUtils
6929
CALL CopyElementNodesFromMesh(Nodes, CurrentModel % Solver % Mesh, &
6930
n, Element % NodeIndexes)
6931
!CALL GetElementNodes(Nodes, Element)
6932
6933
i = LEN_TRIM(Name)
6934
VLoad(1,1:n)=GetReal(BC,Name(1:i)//' 1',Lstat,element)
6935
VLoad(2,1:n)=GetReal(BC,Name(1:i)//' 2',Lstat,element)
6936
VLoad(3,1:n)=GetReal(BC,Name(1:i)//' 3',Lstat,element)
6937
6938
IP = GaussPoints(Element, EdgeBasis=.TRUE., PReferenceElement=.TRUE., &
6939
EdgeBasisDegree=BasisDegree)
6940
6941
DO p=1,IP % n
6942
6943
Lstat = EdgeElementInfo( Element, Nodes, IP % u(p), IP % v(p), IP % w(p), &
6944
DetF=DetJ, Basis=Basis, EdgeBasis=EdgeBasis, SecondFamily = SecondKindBasis, &
6945
BasisDegree=BasisDegree, ApplyPiolaTransform=.TRUE., TangentialTrMapping=.TRUE.)
6946
6947
Normal = NormalVector(Element, Nodes, IP % u(p), IP % v(p), .FALSE.)
6948
6949
VL = MATMUL(Vload(:,1:n),Basis(1:n))
6950
6951
s = IP % s(p) * DetJ
6952
6953
DO i=1,FDOFs
6954
DO j=1,FDOFs
6955
Mass(i,j) = Mass(i,j) + SUM(EdgeBasis(EDOFs+i,:) * EdgeBasis(EDOFs+j,:)) * s
6956
END DO
6957
Force(i) = Force(i) + SUM(CrossProduct(VL,Normal) * EdgeBasis(EDOFs+i,:)) * s
6958
DO j=1,EDOFs
6959
Force(i) = Force(i) - DOFValues(j) * SUM(EdgeBasis(j,:) * EdgeBasis(EDOFs+i,:)) * s
6960
END DO
6961
END DO
6962
END DO
6963
6964
CALL LUSolve(FDOFs, Mass(1:FDOFs,1:FDOFs), Force(1:FDOFs))
6965
DOFValues(EDOFs+1:EDOFs+FDOFs) = Force(1:FDOFs)
6966
!------------------------------------------------------------------------------
6967
END SUBROUTINE SolveLocalFaceDOFs
6968
!------------------------------------------------------------------------------
6969
6970
!------------------------------------------------------------------------------
6971
!> This subroutine computes the values of DOFs that are associated with
6972
!> mesh faces in the case of face (vector-valued) finite elements, so that
6973
!> the vector-valued interpolant of the BC data can be constructed.
6974
!> The values of the DOFs are defined as D = S*(g.n,v)_F where the unit vector n
6975
!> is normal to the face, g is vector-valued data, v is a polynomial on the face F,
6976
!> and S reverses sign if necessary. This subroutine performs neither sign
6977
!> reversions nor the permutations of DOFs, i.e. the DOFs are returned in
6978
!> the default form.
6979
! TO DO: This may need an update when new 3-D elements are added.
6980
!------------------------------------------------------------------------------
6981
SUBROUTINE FaceElementDOFs(BC, Element, n, Parent, FaceId, Name, Integral, &
6982
FDOFs, SecondFamily)
6983
!------------------------------------------------------------------------------
6984
IMPLICIT NONE
6985
6986
TYPE(ValueList_t), POINTER, INTENT(IN) :: BC !< The list of boundary condition values
6987
TYPE(Element_t), POINTER, INTENT(IN) :: Element !< The boundary element handled
6988
INTEGER, INTENT(IN) :: n !< The number of boundary element nodes
6989
TYPE(Element_t), POINTER, INTENT(IN) :: Parent !< The parent element of the boundary element
6990
INTEGER, INTENT(IN) :: FaceId !< The parent element face corresponding to Element
6991
CHARACTER(LEN=*), INTENT(IN) :: Name !< The variable name in the boundary condition
6992
REAL(KIND=dp), INTENT(OUT) :: Integral(:) !< The values of DOFs
6993
INTEGER, OPTIONAL, INTENT(IN) :: FDOFs !< The number of DOFs
6994
LOGICAL, OPTIONAL, INTENT(IN) :: SecondFamily !< To select the element family
6995
!------------------------------------------------------------------------------
6996
TYPE(Nodes_t), SAVE :: Nodes
6997
TYPE(Element_t), POINTER :: ElementCopy
6998
TYPE(GaussIntegrationPoints_t) :: IP
6999
LOGICAL :: SecondKindBasis, stat, ElementCopyCreated
7000
INTEGER :: TetraFaceMap(4,3), BrickFaceMap(6,4), ActiveFaceMap(4)
7001
INTEGER :: DOFs, i, j, p
7002
REAL(KIND=dp) :: VLoad(3,n), LOAD(n), VL(3), L, Normal(3), Basis(n), DetJ, s
7003
REAL(KIND=dp) :: f(3), u, v
7004
REAL(KIND=dp) :: Mass(4,4), rhs(4)
7005
!------------------------------------------------------------------------------
7006
IF (.NOT.(GetElementFamily(Parent) == 5 .OR. GetElementFamily(Parent) == 8)) &
7007
CALL Fatal('FaceElementDOFs','A tetrahedral or hexahedral parent element supposed')
7008
7009
IF (PRESENT(FDOFs)) THEN
7010
DOFs = FDOFs
7011
ELSE
7012
DOFs = 1
7013
END IF
7014
7015
ElementCopyCreated = .FALSE.
7016
7017
SELECT CASE(GetElementFamily(Element))
7018
CASE(3)
7019
7020
IF (DOFs > 3) CALL Fatal('FaceElementDOFs', &
7021
'Cannot yet handle more than 3 DOFs per 3-node face')
7022
7023
IF (PRESENT(SecondFamily)) THEN
7024
SecondKindBasis = SecondFamily
7025
IF (SecondKindBasis .AND. (DOFs /= 3) ) &
7026
CALL Fatal('FaceElementDOFs','3 DOFs per face expected')
7027
ELSE
7028
SecondKindBasis = .FALSE.
7029
END IF
7030
IF (.NOT. SecondKindBasis .AND. DOFs > 1) &
7031
CALL Fatal('FaceElementDOFs','An unexpected DOFs count per face')
7032
7033
IF (SecondKindBasis) THEN
7034
TetraFaceMap(1,:) = [ 2, 1, 3 ]
7035
TetraFaceMap(2,:) = [ 1, 2, 4 ]
7036
TetraFaceMap(3,:) = [ 2, 3, 4 ]
7037
TetraFaceMap(4,:) = [ 3, 1, 4 ]
7038
7039
ActiveFaceMap(1:3) = TetraFaceMap(FaceId,1:3)
7040
7041
IF (ANY(Element % NodeIndexes(1:3) /= Parent % NodeIndexes(ActiveFaceMap(1:3)))) THEN
7042
!
7043
! The parent element face is indexed differently than the boundary element.
7044
! Create a copy of the boundary element which is indexed as the parent element
7045
! face so that we can return the values of DOFs in the default order.
7046
! Reordering is supposed to be done outside this subroutine.
7047
!
7048
ElementCopyCreated = .TRUE.
7049
ElementCopy => AllocateElement()
7050
ElementCopy % Type => Element % Type
7051
ALLOCATE(ElementCopy % NodeIndexes(3))
7052
ElementCopy % NodeIndexes(1:3) = Parent % NodeIndexes(ActiveFaceMap(1:3))
7053
ElementCopy % BodyId = Element % BodyId
7054
ElementCopy % BoundaryInfo => Element % BoundaryInfo
7055
ELSE
7056
ElementCopy => Element
7057
END IF
7058
ELSE
7059
ElementCopy => Element
7060
END IF
7061
!CALL GetElementNodes(Nodes, ElementCopy)
7062
CALL CopyElementNodesFromMesh(Nodes, CurrentModel % Solver % Mesh, &
7063
ElementCopy % Type % NumberOfNodes, ElementCopy % NodeIndexes)
7064
7065
Load(1:n) = GetReal(BC, Name, stat, ElementCopy)
7066
7067
i = LEN_TRIM(Name)
7068
VLoad(1,1:n) = GetReal(BC, Name(1:i)//' 1', stat, ElementCopy)
7069
VLoad(2,1:n) = GetReal(BC, Name(1:i)//' 2', stat, ElementCopy)
7070
VLoad(3,1:n) = GetReal(BC, Name(1:i)//' 3', stat, ElementCopy)
7071
7072
IP = GaussPoints(ElementCopy, 3) ! Feasible for a triangular face
7073
Integral(:) = 0.0d0
7074
DO p=1,IP % n
7075
stat = ElementInfo(ElementCopy, Nodes, IP % u(p), &
7076
IP % v(p), IP % w(p), DetJ, Basis)
7077
!
7078
! We need a normal that points outwards from the parent element.
7079
! The following function call should be consistent with this goal
7080
! in the case of a volume-vacuum interface provided a target body
7081
! for the normal has not been given to blur the situation.
7082
! TO DO: Modify to allow other scenarios
7083
!
7084
Normal = NormalVector(ElementCopy, Nodes, IP % u(p), IP % v(p), .TRUE.)
7085
7086
VL = MATMUL(VLoad(:,1:n), Basis(1:n))
7087
L = SUM(Load(1:n)*Basis(1:n)) + SUM(VL*Normal)
7088
7089
s = IP % s(p) * DetJ
7090
7091
IF (SecondKindBasis) THEN
7092
! Standard coordinates mapped to the p-element coordinates:
7093
u = -1.0d0 + 2.0d0*IP % u(p) + IP % v(p)
7094
v = sqrt(3.0d0)*IP % v(p)
7095
!
7096
! The weight functions for the evaluation of DOFs:
7097
f(1) = sqrt(3.0d0) * 0.5d0 * (1.0d0 - 2.0d0*u + 1.0d0/3.0d0 - 2.0d0/sqrt(3.0d0)*v)
7098
f(2) = sqrt(3.0d0) * 0.5d0 * (1.0d0 + 2.0d0*u + 1.0d0/3.0d0 - 2.0d0/sqrt(3.0d0)*v)
7099
f(3) = sqrt(3.0d0) * (-1.0d0/3.0d0 + 2.0d0/sqrt(3.0d0)*v)
7100
7101
DO i=1,DOFs
7102
Integral(i) = Integral(i) + L * f(i) * s
7103
END DO
7104
ELSE
7105
Integral(1) = Integral(1) + L * s
7106
END IF
7107
END DO
7108
7109
CASE(4)
7110
IF (DOFs /= 4) CALL Fatal('FaceElementDOFs','4 DOFs per 4-node face expected')
7111
7112
BrickFaceMap(1,:) = (/ 2, 1, 4, 3 /)
7113
BrickFaceMap(2,:) = (/ 5, 6, 7, 8 /)
7114
BrickFaceMap(3,:) = (/ 1, 2, 6, 5 /)
7115
BrickFaceMap(4,:) = (/ 2, 3, 7, 6 /)
7116
BrickFaceMap(5,:) = (/ 3, 4, 8, 7 /)
7117
BrickFaceMap(6,:) = (/ 4, 1, 5, 8 /)
7118
7119
ActiveFaceMap(1:4) = BrickFaceMap(FaceId,1:4)
7120
7121
IF (ANY(Element % NodeIndexes(1:4) /= Parent % NodeIndexes(ActiveFaceMap(1:4)))) THEN
7122
!
7123
! The parent element face is indexed differently than the boundary element.
7124
! Create a copy of the boundary element which is indexed as the parent element
7125
! face so that we can return the values of DOFs in the default order.
7126
! Reordering is supposed to be done outside this subroutine.
7127
!
7128
ElementCopyCreated = .TRUE.
7129
ElementCopy => AllocateElement()
7130
ElementCopy % Type => Element % Type
7131
ALLOCATE(ElementCopy % NodeIndexes(4))
7132
ElementCopy % NodeIndexes(1:4) = Parent % NodeIndexes(ActiveFaceMap(1:4))
7133
ElementCopy % BodyId = Element % BodyId
7134
ElementCopy % BoundaryInfo => Element % BoundaryInfo
7135
ELSE
7136
ElementCopy => Element
7137
END IF
7138
7139
!CALL GetElementNodes(Nodes, ElementCopy)
7140
CALL CopyElementNodesFromMesh(Nodes, CurrentModel % Solver % Mesh, &
7141
ElementCopy % Type % NumberOfNodes, ElementCopy % NodeIndexes)
7142
7143
7144
Load(1:n) = GetReal(BC, Name, stat, ElementCopy)
7145
7146
i = LEN_TRIM(Name)
7147
VLoad(1,1:n) = GetReal(BC, Name(1:i)//' 1', stat, ElementCopy)
7148
VLoad(2,1:n) = GetReal(BC, Name(1:i)//' 2', stat, ElementCopy)
7149
VLoad(3,1:n) = GetReal(BC, Name(1:i)//' 3', stat, ElementCopy)
7150
7151
IP = GaussPoints(ElementCopy, 4)
7152
7153
Mass = 0.0d0
7154
rhs = 0.0d0
7155
7156
DO p=1,IP % n
7157
stat = ElementInfo(ElementCopy, Nodes, IP % u(p), &
7158
IP % v(p), IP % w(p), DetJ, Basis)
7159
!
7160
! We need a normal that points outwards from the parent element.
7161
! The following function call should be consistent with this goal
7162
! in the case of a volume-vacuum interface provided a target body
7163
! for the normal has not been given to blur the situation.
7164
! TO DO: Modify to allow other scenarios
7165
!
7166
Normal = NormalVector(ElementCopy, Nodes, IP % u(p), IP % v(p), .TRUE.)
7167
7168
VL = MATMUL(VLoad(:,1:n), Basis(1:n))
7169
L = SUM(Load(1:n)*Basis(1:n)) + SUM(VL*Normal)
7170
s = IP % s(p) * DetJ
7171
7172
DO i=1,DOFs
7173
DO j=1,DOFs
7174
! Note: here a non-existent DetJ is not a mistake
7175
Mass(i,j) = Mass(i,j) + Basis(i) * Basis(j) * IP % s(p)
7176
END DO
7177
rhs(i) = rhs(i) + L * Basis(i) * s
7178
END DO
7179
END DO
7180
7181
CALL LUSolve(DOFs, Mass(1:DOFs,1:DOFs), rhs(1:DOFs))
7182
Integral(1:DOFs) = rhs(1:DOFs)
7183
7184
END SELECT
7185
IF (ElementCopyCreated) DEALLOCATE(ElementCopy % NodeIndexes)
7186
!------------------------------------------------------------------------------
7187
END SUBROUTINE FaceElementDOFs
7188
!------------------------------------------------------------------------------
7189
7190
7191
!> In the case of p-approximation, compute the element stiffness matrix and
7192
!> force vector in order to assemble a system of equations for approximating
7193
!> a given Dirichlet condition
7194
!------------------------------------------------------------------------------
7195
SUBROUTINE LocalBcBDOFs(BC, Element, nd, Name, STIFF, Force )
7196
!------------------------------------------------------------------------------
7197
7198
IMPLICIT NONE
7199
7200
TYPE(ValueList_t), POINTER :: BC !< The list of boundary condition values
7201
TYPE(Element_t), POINTER :: Element !< The boundary element handled
7202
INTEGER :: nd !< The number of DOFs in the boundary element
7203
CHARACTER(LEN=*) :: Name !< The name of boundary condition
7204
REAL(KIND=dp) :: STIFF(:,:) !< The element stiffness matrix
7205
REAL(KIND=dp) :: Force(:) !< The element force vector
7206
!------------------------------------------------------------------------------
7207
TYPE(GaussIntegrationPoints_t) :: IP
7208
INTEGER :: p,q,t
7209
REAL(KIND=dp) :: Basis(nd)
7210
REAL(KIND=dp) :: xip,yip,zip,s,DetJ,Load
7211
LOGICAL :: stat
7212
TYPE(Nodes_t) :: Nodes
7213
SAVE Nodes
7214
!------------------------------------------------------------------------------
7215
7216
! Get nodes of boundary elements parent and gauss points for boundary
7217
CALL GetElementNodes( Nodes, Element )
7218
IP = GaussPoints( Element )
7219
7220
FORCE(1:nd) = 0.0d0
7221
STIFF(1:nd,1:nd) = 0.0d0
7222
7223
DO t=1,IP % n
7224
stat = ElementInfo( Element, Nodes, IP % u(t), &
7225
IP % v(t), IP % w(t), DetJ, Basis )
7226
7227
s = IP % s(t) * DetJ
7228
7229
! Get value of boundary condition
7230
xip = SUM( Basis(1:nd) * Nodes % x(1:nd) )
7231
yip = SUM( Basis(1:nd) * Nodes % y(1:nd) )
7232
zip = SUM( Basis(1:nd) * Nodes % z(1:nd) )
7233
Load = ListGetConstReal( BC, Name, x=xip,y=yip,z=zip )
7234
7235
! Build local stiffness matrix and force vector
7236
DO p=1,nd
7237
DO q=1,nd
7238
STIFF(p,q) = STIFF(p,q) + s * Basis(p)*Basis(q)
7239
END DO
7240
FORCE(p) = FORCE(p) + s * Load * Basis(p)
7241
END DO
7242
END DO
7243
!------------------------------------------------------------------------------
7244
END SUBROUTINE LocalBcBDOFs
7245
!------------------------------------------------------------------------------
7246
7247
7248
!------------------------------------------------------------------------------
7249
!> Finishes the bulk assembly of the matrix equation.
7250
!> Optionally save the matrix for later use.
7251
!------------------------------------------------------------------------------
7252
SUBROUTINE DefaultFinishBulkAssembly( Solver, BulkUpdate, RHSUpdate )
7253
!------------------------------------------------------------------------------
7254
TYPE(Solver_t), OPTIONAL, TARGET :: Solver
7255
LOGICAL, OPTIONAL :: BulkUpdate ! Direct control on whether matrices are saved
7256
LOGICAL, OPTIONAL :: RHSUpdate ! Direct control on whether RHS is saved
7257
7258
TYPE(Solver_t), POINTER :: PSolver
7259
TYPE(ValueList_t), POINTER :: Params
7260
LOGICAL :: Bupd, UpdateRHS, Found
7261
INTEGER :: n
7262
CHARACTER(:), ALLOCATABLE :: str
7263
LOGICAL :: Transient
7264
REAL(KIND=dp) :: SScond
7265
INTEGER :: Order
7266
TYPE(Matrix_t), POINTER :: A
7267
7268
IF( PRESENT( Solver ) ) THEN
7269
PSolver => Solver
7270
ELSE
7271
PSolver => CurrentModel % Solver
7272
END IF
7273
7274
Params => GetSolverParams( PSolver )
7275
7276
IF( ListGetLogical( Params,'Bulk Assembly Timing',Found ) ) THEN
7277
CALL CheckTimer('BulkAssembly'//GetVarName(PSolver % Variable), Level=5, Delete=.TRUE. )
7278
END IF
7279
7280
! Reset colouring
7281
PSolver % CurrentColour = 0
7282
7283
IF ( PRESENT(RHSUpdate) ) THEN
7284
UpdateRHS = RHSUpdate
7285
ELSE
7286
UpdateRHS = .TRUE.
7287
END IF
7288
7289
BUpd = .FALSE.
7290
IF ( PRESENT(BulkUpdate) ) THEN
7291
BUpd = BulkUpdate
7292
ELSE
7293
BUpd = GetLogical( Params,'Calculate Loads', Found )
7294
IF( BUpd ) THEN
7295
str = GetString( Params,'Calculate Loads Slot', Found )
7296
IF(Found) THEN
7297
BUpd = ( str == 'bulk assembly')
7298
END IF
7299
END IF
7300
BUpd = BUpd .OR. GetLogical( Params,'Constant Bulk System', Found )
7301
BUpd = BUpd .OR. GetLogical( Params,'Save Bulk System', Found )
7302
BUpd = BUpd .OR. GetLogical( Params,'Constant Bulk Matrix', Found )
7303
BUpd = BUpd .OR. GetLogical( Params,'Constraint Modes Analysis',Found)
7304
BUpd = BUpd .OR. GetLogical( Params,'Control Use Loads',Found )
7305
END IF
7306
7307
IF( BUpd ) THEN
7308
str = GetString( Params,'Equation',Found)
7309
CALL Info('DefaultFinishBulkAssembly','Saving bulk values for: '//str, Level=8 )
7310
IF( GetLogical( Params,'Constraint Modes Mass Lumping',Found) ) THEN
7311
CALL CopyBulkMatrix( PSolver % Matrix, BulkMass = .TRUE., BulkRHS = UpdateRHS )
7312
ELSE
7313
CALL CopyBulkMatrix( PSolver % Matrix, BulkMass = ASSOCIATED(PSolver % Matrix % MassValues), &
7314
BulkDamp = ASSOCIATED(PSolver % Matrix % DampValues), BulkRHS = UpdateRHS )
7315
END IF
7316
END IF
7317
7318
IF( GetLogical( Params,'Bulk System Multiply',Found ) ) THEN
7319
CALL Info('DefaultFinishBulkAssembly','Multiplying matrix equation',Level=10)
7320
CALL LinearSystemMultiply( PSolver )
7321
END IF
7322
7323
IF ( ListGetLogical( Params,'Linear System Save',Found )) THEN
7324
str = GetString( Params,'Linear System Save Slot', Found )
7325
IF(Found .AND. str == 'bulk assembly') THEN
7326
CALL SaveLinearSystem( PSolver )
7327
END IF
7328
END IF
7329
7330
IF( ListGetLogical( PSolver % Values,'Boundary Assembly Timing',Found ) ) THEN
7331
CALL ResetTimer('BoundaryAssembly'//GetVarName(PSolver % Variable) )
7332
END IF
7333
7334
IF( InfoActive( 30 ) ) THEN
7335
A => PSolver % Matrix
7336
IF(ASSOCIATED(A)) THEN
7337
CALL VectorValuesRange(A % Values,SIZE(A % Values),'A_bulk')
7338
IF(ASSOCIATED(A % rhs)) THEN
7339
CALL VectorValuesRange(A % rhs,SIZE(A % rhs),'b_bulk')
7340
END IF
7341
END IF
7342
END IF
7343
7344
END SUBROUTINE DefaultFinishBulkAssembly
7345
7346
7347
!------------------------------------------------------------------------------
7348
!> Finished the boundary assembly of the matrix equation.
7349
!> Optionally save the matrix for later use.
7350
!------------------------------------------------------------------------------
7351
SUBROUTINE DefaultFinishBoundaryAssembly( Solver, BulkUpdate )
7352
!------------------------------------------------------------------------------
7353
TYPE(Solver_t), OPTIONAL, TARGET :: Solver
7354
LOGICAL, OPTIONAL :: BulkUpdate
7355
TYPE(Solver_t), POINTER :: PSolver
7356
TYPE(ValueList_t), POINTER :: Params
7357
LOGICAL :: Bupd, Found, DoIt
7358
INTEGER :: n
7359
TYPE(Matrix_t), POINTER :: A
7360
CHARACTER(:), ALLOCATABLE :: str, name
7361
TYPE(Variable_t), POINTER :: x
7362
INTEGER :: dof
7363
7364
IF( PRESENT( Solver ) ) THEN
7365
PSolver => Solver
7366
ELSE
7367
PSolver => CurrentModel % Solver
7368
END IF
7369
7370
Params => GetSolverParams(PSolver)
7371
A => PSolver % Matrix
7372
x => PSolver % Variable
7373
7374
! Set the nodal loads. This needs to be done before any contacts or limiters since otherwise
7375
! the given nodal loads will not be considered properly.
7376
DoIt = .TRUE.
7377
IF( ListGetLogical( Params,'Apply Limiter',Found ) ) THEN
7378
IF(ListGetLogical( Params,'Apply Limiter Loads After',Found) ) DoIt = .FALSE.
7379
END IF
7380
IF( DoIt ) THEN
7381
DO DOF=1,x % DOFs
7382
name = TRIM(x % name)
7383
IF (x % DOFs>1) name=ComponentName(name,DOF)
7384
CALL SetNodalLoads( CurrentModel,A,A % rhs, &
7385
Name,DOF,x % DOFs,x % Perm )
7386
END DO
7387
END IF
7388
7389
IF( ListGetLogical( Params,'Boundary Assembly Timing',Found ) ) THEN
7390
CALL CheckTimer('BoundaryAssembly'//GetVarName(x), Level=5, Delete=.TRUE. )
7391
END IF
7392
7393
! Reset colouring
7394
PSolver % CurrentBoundaryColour = 0
7395
7396
BUpd = .FALSE.
7397
IF ( PRESENT(BulkUpdate) ) THEN
7398
BUpd = BulkUpdate
7399
IF ( .NOT. BUpd ) RETURN
7400
ELSE
7401
BUpd = GetLogical( Params,'Calculate Loads', Found )
7402
IF( BUpd ) THEN
7403
str = GetString( Params,'Calculate Loads Slot', Found )
7404
IF(Found) THEN
7405
BUpd = str == 'boundary assembly'
7406
ELSE
7407
BUpd = .FALSE.
7408
END IF
7409
BUpd = BUpd .OR. GetLogical( Params,'Constant System', Found )
7410
END IF
7411
END IF
7412
7413
IF( BUpd ) THEN
7414
CALL Info('DefaultFinishBoundaryAssembly','Saving system values for Solver: '&
7415
//TRIM(x % Name), Level=8)
7416
CALL CopyBulkMatrix( PSolver % Matrix )
7417
END IF
7418
7419
IF ( ListGetLogical( Params,'Linear System Save',Found )) THEN
7420
str=GetString( Params,'Linear System Save Slot', Found )
7421
IF(Found .AND. str == 'boundary assembly') THEN
7422
CALL SaveLinearSystem( PSolver )
7423
END IF
7424
END IF
7425
7426
! Create contact BCs using mortar conditions.
7427
!---------------------------------------------------------------------
7428
IF( ListGetLogical( Params,'Apply Contact BCs',Found) ) THEN
7429
CALL DetermineContact( PSolver )
7430
END IF
7431
7432
IF( InfoActive( 30 ) ) THEN
7433
IF(ASSOCIATED(A)) THEN
7434
CALL VectorValuesRange(A % Values,SIZE(A % Values),'A0')
7435
IF( ASSOCIATED( A % rhs) ) THEN
7436
CALL VectorValuesRange(A % rhs,SIZE(A % rhs),'b0')
7437
END IF
7438
END IF
7439
END IF
7440
7441
END SUBROUTINE DefaultFinishBoundaryAssembly
7442
7443
7444
7445
!------------------------------------------------------------------------------
7446
!> Finished the assembly of the matrix equation, mainly effects in transient simulation
7447
!> Also may be used to set implicit relaxation on the linear system before
7448
!> applying Dirichlet conditions. If flux corrected transport is applied then
7449
!> make the initial linear system to be of low order.
7450
!------------------------------------------------------------------------------
7451
SUBROUTINE DefaultFinishAssembly( Solver )
7452
!------------------------------------------------------------------------------
7453
TYPE(Solver_t), OPTIONAL, TARGET :: Solver
7454
7455
INTEGER :: order, n
7456
LOGICAL :: Found, Transient
7457
TYPE(ValueList_t), POINTER :: Params
7458
TYPE(Solver_t), POINTER :: PSolver
7459
TYPE(Matrix_t), POINTER :: A
7460
REAL(KIND=dp) :: sscond
7461
CHARACTER(:), ALLOCATABLE :: str
7462
7463
IF( PRESENT( Solver ) ) THEN
7464
PSolver => Solver
7465
ELSE
7466
PSolver => CurrentModel % Solver
7467
END IF
7468
A => PSolver % Matrix
7469
7470
Params => GetSolverParams(PSolver)
7471
7472
! Nonlinear timestepping needs a copy of the linear system from previous
7473
! timestep. Hence the saving of the linear system is enforced.
7474
IF( ListGetLogical( Params,'Nonlinear Timestepping', Found ) ) THEN
7475
CALL Info('DefaultFinishAssembly','Saving system values for Solver: '&
7476
//TRIM(PSolver % Variable % Name), Level=8)
7477
CALL CopyBulkMatrix( A )
7478
END IF
7479
7480
! Makes a low order matrix of the initial one saving original values
7481
! to BulkValues. Also created a lumped mass matrix.
7482
IF( ListGetLogical( Params,'Linear System FCT',Found ) ) THEN
7483
IF( PSolver % Variable % Dofs == 1 ) THEN
7484
CALL CRS_FCTLowOrder( A )
7485
ELSE
7486
CALL Fatal('DefaultFinishAssembly','FCT scheme implemented only for one dof')
7487
END IF
7488
END IF
7489
7490
IF(GetLogical(Params,'Use Global Mass Matrix',Found)) THEN
7491
7492
Transient = GetString( CurrentModel % Simulation, 'Simulation Type') == 'transient'
7493
IF( Transient ) THEN
7494
SSCond = ListGetCReal( PSolver % Values,'Steady State Condition',Found )
7495
IF( Found .AND. SSCond > 0.0_dp ) Transient = .FALSE.
7496
END IF
7497
7498
IF( Transient ) THEN
7499
order = GetInteger(Params,'Time Derivative Order',Found)
7500
IF(.NOT.Found) Order = PSolver % TimeOrder
7501
7502
SELECT CASE(order)
7503
7504
CASE(1)
7505
CALL Default1stOrderTimeGlobal(PSolver)
7506
7507
CASE(2)
7508
CALL Default2ndOrderTimeGlobal(PSolver)
7509
END SELECT
7510
END IF
7511
END IF
7512
7513
CALL FinishAssembly( PSolver, A % RHS )
7514
7515
IF( GetLogical( Params,'Linear System Multiply',Found ) ) THEN
7516
CALL Info('DefaultFinishAssembly','Multiplying matrix equation',Level=10)
7517
CALL LinearSystemMultiply( PSolver )
7518
END IF
7519
7520
IF( ListCheckPrefix( Params,'Linear System Diagonal Min') ) THEN
7521
CALL LinearSystemMinDiagonal( PSolver )
7522
END IF
7523
7524
IF ( ListGetLogical( Params,'Linear System Save',Found )) THEN
7525
str = GetString( Params,'Linear System Save Slot', Found )
7526
IF(Found .AND. str == 'assembly') THEN
7527
CALL SaveLinearSystem( PSolver )
7528
END IF
7529
END IF
7530
7531
!------------------------------------------------------------------------------
7532
END SUBROUTINE DefaultFinishAssembly
7533
!------------------------------------------------------------------------------
7534
7535
7536
7537
!> Returns integration points for edge or face of p element
7538
!------------------------------------------------------------------------------
7539
FUNCTION GaussPointsBoundary(Element, boundary, np) RESULT(gaussP)
7540
!------------------------------------------------------------------------------
7541
USE PElementMaps, ONLY : getElementBoundaryMap
7542
USE Integration
7543
IMPLICIT NONE
7544
7545
! Parameters
7546
TYPE(Element_t) :: Element
7547
INTEGER, INTENT(IN) :: boundary, np
7548
7549
TYPE( GaussIntegrationPoints_t ) :: gaussP
7550
TYPE(Nodes_t) :: bNodes
7551
TYPE(Element_t) :: mapElement
7552
TYPE(Element_t), POINTER :: RefElement
7553
INTEGER :: i, n, eCode, bMap(4)
7554
REAL(KIND=dp), TARGET :: x(4), y(4), z(4)
7555
REAL(KIND=dp), POINTER CONTIG :: xP(:), yP(:), zP(:)
7556
7557
SELECT CASE(Element % TYPE % ElementCode / 100)
7558
! Triangle and Quadrilateral
7559
CASE (3,4)
7560
n = 2
7561
eCode = 202
7562
! Tetrahedron
7563
CASE (5)
7564
n = 3
7565
eCode = 303
7566
! Pyramid
7567
CASE (6)
7568
! Select edge element by boundary
7569
IF (boundary == 1) THEN
7570
n = 4
7571
eCode = 404
7572
ELSE
7573
n = 3
7574
eCode = 303
7575
END IF
7576
! Wedge
7577
CASE (7)
7578
! Select edge element by boundary
7579
SELECT CASE (boundary)
7580
CASE (1,2)
7581
n = 3
7582
eCode = 303
7583
CASE (3,4,5)
7584
n = 4
7585
eCode = 404
7586
END SELECT
7587
! Brick
7588
CASE (8)
7589
n = 4
7590
eCode = 404
7591
CASE DEFAULT
7592
WRITE (*,*) 'DefUtils::GaussPointsBoundary: Unsupported element type'
7593
END SELECT
7594
7595
! Get element boundary map
7596
bMap(1:4) = getElementBoundaryMap(Element, boundary)
7597
! Get ref nodes for element
7598
xP => x
7599
yP => y
7600
zP => z
7601
CALL GetRefPElementNodes( Element % Type,xP,yP,zP )
7602
ALLOCATE(bNodes % x(n), bNodes % y(n), bNodes % z(n))
7603
7604
! Set coordinate points of destination
7605
DO i=1,n
7606
IF (bMap(i) == 0) CYCLE
7607
bNodes % x(i) = x(bMap(i))
7608
bNodes % y(i) = y(bMap(i))
7609
bNodes % z(i) = z(bMap(i))
7610
END DO
7611
7612
! Get element to map from
7613
mapElement % TYPE => GetElementType(eCode)
7614
CALL AllocateVector(mapElement % NodeIndexes, mapElement % TYPE % NumberOfNodes)
7615
7616
! Get gauss points and map them to given element
7617
gaussP = GaussPoints( mapElement, np )
7618
7619
CALL MapGaussPoints( mapElement, mapElement % TYPE % NumberOfNodes, gaussP, bNodes )
7620
7621
! Deallocate memory
7622
DEALLOCATE(bNodes % x, bNodes % y, bNodes % z, MapElement % NodeIndexes)
7623
!------------------------------------------------------------------------------
7624
END FUNCTION GaussPointsBoundary
7625
!------------------------------------------------------------------------------
7626
7627
7628
!------------------------------------------------------------------------------
7629
SUBROUTINE MapGaussPoints( Element, n, gaussP, Nodes )
7630
!------------------------------------------------------------------------------
7631
IMPLICIT NONE
7632
7633
TYPE(Element_t) :: Element
7634
TYPE(GaussIntegrationPoints_t) :: gaussP
7635
TYPE(Nodes_t) :: Nodes
7636
INTEGER :: n
7637
7638
INTEGER :: i
7639
REAL(KIND=dp) :: xh,yh,zh,sh, DetJ
7640
REAL(KIND=dp) :: Basis(n)
7641
LOGICAL :: stat
7642
7643
! Map each gauss point from reference element to given nodes
7644
DO i=1,gaussP % n
7645
stat = ElementInfo( Element, Nodes, gaussP % u(i), gaussP % v(i), gaussP % w(i), &
7646
DetJ, Basis )
7647
7648
IF (.NOT. stat) THEN
7649
CALL Fatal( 'DefUtils::MapGaussPoints', 'Element to map degenerate')
7650
END IF
7651
7652
! Get mapped points
7653
sh = gaussP % s(i) * DetJ
7654
xh = SUM( Basis(1:n) * Nodes % x(1:n) )
7655
yh = SUM( Basis(1:n) * Nodes % y(1:n) )
7656
zh = SUM( Basis(1:n) * Nodes % z(1:n) )
7657
! Set mapped points
7658
gaussP % u(i) = xh
7659
gaussP % v(i) = yh
7660
gaussP % w(i) = zh
7661
gaussP % s(i) = sh
7662
END DO
7663
!------------------------------------------------------------------------------
7664
END SUBROUTINE MapGaussPoints
7665
!------------------------------------------------------------------------------
7666
7667
7668
!> Calculate global AND local indexes of boundary dofs for given p-element
7669
!> lying on a boundary.
7670
!------------------------------------------------------------------------------
7671
SUBROUTINE getBoundaryIndexesGL( Mesh, Element, BElement, lIndexes, gIndexes, indSize )
7672
!------------------------------------------------------------------------------
7673
!
7674
! ARGUMENTS:
7675
!
7676
! Type(Mesh_t) :: Mesh
7677
! INPUT: Finite element mesh containing edges and faces of elements
7678
!
7679
! Type(Element_t) :: Element
7680
! INPUT: Parent of boundary element to get indexes for
7681
!
7682
! Type(Element_t) :: BElement
7683
! INPUT: Boundary element to get indexes for
7684
!
7685
! INTEGER :: lIndexes(:), gIndexes(:)
7686
! OUTPUT: Calculated indexes of boundary element in local and
7687
! global system
7688
!
7689
! INTEGER :: indSize
7690
! OUTPUT: Size of created index vector, i.e. how many indexes were created
7691
! starting from index 1
7692
!
7693
!------------------------------------------------------------------------------
7694
IMPLICIT NONE
7695
7696
! Parameters
7697
TYPE(Mesh_t) :: Mesh
7698
TYPE(Element_t) :: Element
7699
TYPE(Element_t), POINTER :: BElement
7700
INTEGER :: indSize, lIndexes(:), gIndexes(:)
7701
! Variables
7702
TYPE(Element_t), POINTER :: Edge, Face
7703
INTEGER :: i,j,k,n,edgeDofSum, faceOffSet, edgeOffSet(12), localBoundary, nNodes, bMap(4), &
7704
faceEdgeMap(4)
7705
LOGICAL :: stat
7706
7707
! Clear indexes
7708
lIndexes = 0
7709
gIndexes = 0
7710
7711
! Get boundary map and number of nodes on boundary
7712
localBoundary = BElement % PDefs % localNumber
7713
nNodes = BElement % TYPE % NumberOfNodes
7714
bMap(1:4) = getElementBoundaryMap(Element, localBoundary)
7715
n = nNodes + 1
7716
7717
! Assign local and global node indexes
7718
lIndexes(1:nNodes) = bMap(1:nNodes)
7719
gIndexes(1:nNodes) = Element % NodeIndexes(lIndexes(1:nNodes))
7720
7721
! Assign rest of indexes
7722
SELECT CASE(Element % TYPE % DIMENSION)
7723
CASE (2)
7724
edgeDofSum = Element % TYPE % NumberOfNodes
7725
7726
IF (SIZE(lIndexes) < nNodes + Mesh % MaxEdgeDOFs) THEN
7727
WRITE (*,*) 'DefUtils::getBoundaryIndexes: Not enough space reserved for edge indexes'
7728
RETURN
7729
END IF
7730
7731
DO i=1,Element % TYPE % NumberOfEdges
7732
Edge => Mesh % Edges( Element % EdgeIndexes(i) )
7733
7734
! For boundary edge add local and global indexes
7735
IF (localBoundary == i) THEN
7736
DO j=1,Edge % BDOFs
7737
lIndexes(n) = edgeDofSum + j
7738
gIndexes(n) = Mesh % NumberOfNodes + &
7739
(Element % EdgeIndexes(localBoundary)-1) * Mesh % MaxEdgeDOFs + j
7740
n = n+1
7741
END DO
7742
EXIT
7743
END IF
7744
7745
edgeDofSum = edgeDofSum + Edge % BDOFs
7746
END DO
7747
7748
indSize = n - 1
7749
CASE (3)
7750
IF (SIZE(lIndexes) < nNodes + (Mesh % MaxEdgeDOFs * BElement % TYPE % NumberOfEdges) +&
7751
Mesh % MaxFaceDofs) THEN
7752
WRITE (*,*) 'DefUtils::getBoundaryIndexes: Not enough space reserved for edge indexes'
7753
RETURN
7754
END IF
7755
7756
! Get offsets for each edge
7757
edgeOffSet = 0
7758
faceOffSet = 0
7759
edgeDofSum = 0
7760
DO i=1,Element % TYPE % NumberOfEdges
7761
Edge => Mesh % Edges( Element % EdgeIndexes(i) )
7762
edgeOffSet(i) = edgeDofSum
7763
edgeDofSum = edgeDofSum + Edge % BDOFs
7764
END DO
7765
7766
! Get offset for faces
7767
faceOffSet = edgeDofSum
7768
7769
! Add element edges to local indexes
7770
faceEdgeMap(1:4) = getFaceEdgeMap(Element, localBoundary)
7771
Face => Mesh % Faces( Element % FaceIndexes(localBoundary) )
7772
DO i=1,Face % TYPE % NumberOfEdges
7773
Edge => Mesh % Edges( Face % EdgeIndexes(i) )
7774
7775
IF (Edge % BDOFs <= 0) CYCLE
7776
7777
DO j=1,Edge % BDOFs
7778
lIndexes(n) = Element % TYPE % NumberOfNodes + edgeOffSet(faceEdgeMap(i)) + j
7779
gIndexes(n) = Mesh % NumberOfNodes +&
7780
( Face % EdgeIndexes(i)-1)*Mesh % MaxEdgeDOFs + j
7781
n=n+1
7782
END DO
7783
END DO
7784
7785
DO i=1,Element % TYPE % NumberOfFaces
7786
Face => Mesh % Faces( Element % FaceIndexes(i) )
7787
7788
IF (Face % BDOFs <= 0) CYCLE
7789
7790
! For boundary face add local and global indexes
7791
IF (localBoundary == i) THEN
7792
DO j=1,Face % BDOFs
7793
lIndexes(n) = Element % TYPE % NumberOfNodes + faceOffSet + j
7794
gIndexes(n) = Mesh % NumberOfNodes + &
7795
Mesh % NumberOfEdges * Mesh % MaxEdgeDOFs + &
7796
(Element % FaceIndexes(localBoundary)-1) * Mesh % MaxFaceDOFs + j
7797
n=n+1
7798
END DO
7799
EXIT
7800
END IF
7801
7802
faceOffSet = faceOffSet + Face % BDOFs
7803
END DO
7804
7805
indSize = n - 1
7806
END SELECT
7807
END SUBROUTINE getBoundaryIndexesGL
7808
7809
7810
7811
!------------------------------------------------------------------------------
7812
SUBROUTINE GetParentUVW( Element,n,Parent,np,U,V,W,Basis )
7813
!------------------------------------------------------------------------------
7814
TYPE(Element_t) :: Element, Parent
7815
INTEGER :: n, np
7816
REAL(KIND=dp) :: U,V,W,Basis(:)
7817
!------------------------------------------------------------------------------
7818
INTEGER :: i,j
7819
REAL(KIND=dp), POINTER :: LU(:), LV(:), LW(:)
7820
7821
LU => Parent % TYPE % NodeU
7822
LV => Parent % TYPE % NodeV
7823
LW => Parent % TYPE % NodeW
7824
7825
U = 0.0_dp
7826
V = 0.0_dp
7827
W = 0.0_dp
7828
DO i = 1,n
7829
DO j = 1,np
7830
IF ( Element % NodeIndexes(i) == Parent % NodeIndexes(j) ) THEN
7831
U = U + Basis(i) * LU(j)
7832
V = V + Basis(i) * LV(j)
7833
W = W + Basis(i) * LW(j)
7834
EXIT
7835
END IF
7836
END DO
7837
END DO
7838
!------------------------------------------------------------------------------
7839
END SUBROUTINE GetParentUVW
7840
!------------------------------------------------------------------------------
7841
7842
7843
!> Returns flag telling whether Newton linearization is active
7844
!------------------------------------------------------------------------------
7845
FUNCTION GetNewtonActive( USolver ) RESULT( NewtonActive )
7846
LOGICAL :: NewtonActive
7847
TYPE(Solver_t), OPTIONAL, TARGET :: USolver
7848
7849
IF ( PRESENT( USolver ) ) THEN
7850
NewtonActive = USolver % NewtonActive
7851
ELSE
7852
NewtonActive = CurrentModel % Solver % NewtonActive
7853
END IF
7854
END FUNCTION GetNewtonActive
7855
7856
7857
!------------------------------------------------------------------------------
7858
FUNCTION GetBoundaryEdgeIndex(Boundary,nedge) RESULT(n)
7859
!------------------------------------------------------------------------------
7860
IMPLICIT NONE
7861
INTEGER :: n,nedge
7862
TYPE(Element_t) :: Boundary
7863
!------------------------------------------------------------------------------
7864
TYPE(Mesh_t), POINTER :: Mesh
7865
Mesh => GetMesh()
7866
n = FindBoundaryEdgeIndex(Mesh,Boundary,nedge)
7867
!------------------------------------------------------------------------------
7868
END FUNCTION GetBoundaryEdgeIndex
7869
!------------------------------------------------------------------------------
7870
7871
7872
!------------------------------------------------------------------------------
7873
FUNCTION GetBoundaryFaceIndex(Boundary) RESULT(n)
7874
!------------------------------------------------------------------------------
7875
IMPLICIT NONE
7876
INTEGER :: n
7877
TYPE(Element_t) :: Boundary
7878
!------------------------------------------------------------------------------
7879
TYPE(Mesh_t), POINTER :: Mesh
7880
Mesh => GetMesh()
7881
n = FindBoundaryFaceIndex(Mesh,Boundary)
7882
!------------------------------------------------------------------------------
7883
END FUNCTION GetBoundaryFaceIndex
7884
!------------------------------------------------------------------------------
7885
7886
FUNCTION GetNOFColours(USolver) RESULT( ncolours )
7887
IMPLICIT NONE
7888
TYPE(Solver_t), TARGET, OPTIONAL :: USolver
7889
INTEGER :: ncolours
7890
7891
ncolours = 1
7892
IF ( PRESENT( USolver ) ) THEN
7893
IF( ASSOCIATED( USolver % ColourIndexList ) ) THEN
7894
ncolours = USolver % ColourIndexList % n
7895
USolver % CurrentColour = 0
7896
END IF
7897
ELSE
7898
IF( ASSOCIATED( CurrentModel % Solver % ColourIndexList ) ) THEN
7899
ncolours = CurrentModel % Solver % ColourIndexList % n
7900
CurrentModel % Solver % CurrentColour = 0
7901
END IF
7902
END IF
7903
7904
CALL Info('GetNOFColours','Number of colours: '//I2S(ncolours),Level=12)
7905
END FUNCTION GetNOFColours
7906
7907
FUNCTION GetNOFBoundaryColours(USolver) RESULT( ncolours )
7908
IMPLICIT NONE
7909
TYPE(Solver_t), TARGET, OPTIONAL :: USolver
7910
INTEGER :: ncolours
7911
7912
ncolours = 1
7913
IF ( PRESENT( USolver ) ) THEN
7914
IF( ASSOCIATED( USolver % BoundaryColourIndexList ) ) THEN
7915
ncolours = USolver % BoundaryColourIndexList % n
7916
USolver % CurrentBoundaryColour = 0
7917
END IF
7918
ELSE
7919
IF( ASSOCIATED( CurrentModel % Solver % BoundaryColourIndexList ) ) THEN
7920
ncolours = CurrentModel % Solver % BoundaryColourIndexList % n
7921
CurrentModel % Solver % CurrentBoundaryColour = 0
7922
END IF
7923
END IF
7924
7925
CALL Info('GetNOFBoundaryColours','Number of colours: '//I2S(ncolours),Level=12)
7926
END FUNCTION GetNOFBoundaryColours
7927
7928
! Check given colourings are valid and see if they are free of race conditions.
7929
SUBROUTINE CheckColourings(Solver)
7930
IMPLICIT NONE
7931
TYPE(Solver_t) :: Solver
7932
7933
TYPE(Mesh_t), POINTER :: Mesh
7934
TYPE(Graph_t), POINTER :: Colours
7935
TYPE(Graph_t), POINTER :: BoundaryColours
7936
7937
TYPE(Element_t), POINTER :: Element
7938
7939
INTEGER, ALLOCATABLE :: Indexes(:), DOFIndexes(:)
7940
INTEGER :: col, elem, belem, NDOF, dof
7941
LOGICAL :: errors
7942
7943
errors = .FALSE.
7944
7945
Mesh => Solver % Mesh
7946
Colours => Solver % ColourIndexList
7947
BoundaryColours => Solver % BoundaryColourIndexList
7948
7949
! Allocate workspace and initialize it
7950
ALLOCATE(Indexes(MAX(Mesh % NumberOfNodes,&
7951
Mesh % NumberOfBulkElements*Mesh % MaxElementDOFs,&
7952
Mesh%NumberOfBoundaryElements*Mesh % MaxElementDOFs)), &
7953
DOFIndexes(Mesh % MaxElementDOFs))
7954
Indexes = 0
7955
7956
! Check that every element has a colour
7957
IF (ASSOCIATED(Colours)) THEN
7958
DO col=1,Colours % N
7959
DO elem=Colours % Ptr(col), Colours%Ptr(col+1)-1
7960
Indexes(Colours % Ind(elem))=Indexes(Colours % Ind(elem))+1
7961
END DO
7962
END DO
7963
DO elem=1,Mesh % NumberOfBulkElements
7964
IF (Indexes(elem) < 1 .OR. Indexes(elem) > 1) THEN
7965
CALL Warn('CheckColourings','Element not colored correctly: '//i2s(elem))
7966
errors = .TRUE.
7967
END IF
7968
END DO
7969
7970
Indexes = 0
7971
! Check that colouring is free of race conditions
7972
DO col=1,Colours % N
7973
DO elem=Colours % Ptr(col), Colours%Ptr(col+1)-1
7974
Element => Mesh % Elements(Colours % Ind(elem))
7975
NDOF = GetElementDOFs( DOFIndexes, Element, Solver )
7976
DO dof=1,NDOF
7977
Indexes(DOFIndexes(dof))=Indexes(DOFIndexes(dof))+1
7978
END DO
7979
END DO
7980
! Check colouring
7981
DO dof=1,Mesh % NumberOfBulkElements*Mesh % MaxElementDOFs
7982
IF (Indexes(dof)>1) THEN
7983
CALL Warn('CheckColourings','DOF not colored correctly: '//i2s(dof))
7984
errors = .TRUE.
7985
END IF
7986
Indexes(dof)=0
7987
END DO
7988
END DO
7989
END IF
7990
7991
! Check that every boundary element has a colour
7992
IF (ASSOCIATED(BoundaryColours)) THEN
7993
7994
DO col=1,BoundaryColours % N
7995
DO elem=BoundaryColours % Ptr(col), BoundaryColours%Ptr(col+1)-1
7996
Indexes(BoundaryColours % Ind(elem))=Indexes(BoundaryColours % Ind(elem))+1
7997
END DO
7998
END DO
7999
DO elem=Mesh % NumberOfBulkElements+1,Mesh % NumberOfBulkElements + Mesh % NumberOfBoundaryElements
8000
belem = elem - Mesh % NumberOfBulkElements
8001
IF (Indexes(belem) < 1 .OR. Indexes(belem) > 1) THEN
8002
CALL Warn('CheckColourings','Boundary element not colored correctly: '//i2s(belem))
8003
errors = .TRUE.
8004
END IF
8005
END DO
8006
8007
Indexes = 0
8008
! Check that colouring is free of race conditions
8009
DO col=1,BoundaryColours % N
8010
DO elem=BoundaryColours % Ptr(col), BoundaryColours%Ptr(col+1)-1
8011
Element => Mesh % Elements(Mesh % NumberOfBulkElements + BoundaryColours % Ind(elem))
8012
NDOF = GetElementDOFs( DOFIndexes, Element, Solver, NotDG=.TRUE. )
8013
! WRITE (*,'(2(A,I0))') 'BELEM=', elem, ', CMAP=', BoundaryColours % Ind(elem)
8014
! WRITE (*,*) DOFIndexes(1:NDOF)
8015
DO dof=1,NDOF
8016
Indexes(DOFIndexes(dof))=Indexes(DOFIndexes(dof))+1
8017
! WRITE (*,'(4(A,I0))') 'EID=', Element % ElementIndex,', dof=', dof, &
8018
! ', ind=', DOFIndexes(dof), ', colour=', col
8019
END DO
8020
END DO
8021
! Check colouring
8022
DO dof=1,Mesh % NumberOfBulkElements*Mesh % MaxElementDOFs
8023
IF (Indexes(dof)>1) THEN
8024
CALL Warn('CheckColourings','Boundary DOF not colored correctly: '//i2s(dof))
8025
errors = .TRUE.
8026
END IF
8027
Indexes(dof)=0
8028
END DO
8029
END DO
8030
END IF
8031
8032
IF (errors) THEN
8033
CALL Warn('CheckColourings','Mesh colouring contained errors')
8034
END IF
8035
8036
DEALLOCATE(Indexes, DOFIndexes)
8037
END SUBROUTINE CheckColourings
8038
8039
8040
END MODULE DefUtils
8041
8042
!> \} // end of subgroup
8043
!> \} // end of group
8044
8045
8046