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