Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/BlockSolve.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
!> \ingroup ElmerLib
26
!> \{
27
!-----------------------------------------------------------------------------
28
!> Module for solution of matrix equation utilizing block strategies.
29
!-----------------------------------------------------------------------------
30
31
MODULE BlockSolve
32
33
USE ParallelUtils
34
USE Integration
35
USE ListMatrix
36
USE ElementUtils, ONLY : FreeMatrix
37
USE MatrixAssembly, ONLY : AddToMatrixElement
38
USE IterativeMethods, ONLY : PseudoZDotProd
39
USE IterSolve, ONLY : IterSolver
40
USE ElementDescription, ONLY : ElementInfo, EdgeElementInfo
41
USE SolverUtils, ONLY : LagrangeMultiplierName, SolveLinearSystem, ScaleLinearSystem, &
42
BackScaleLinearSystem, AMGXMatrixVectorMultiply, AMGXSolver, DiagonalMatrixSumming, &
43
StructureCouplingAssembly, FSICouplingAssembly, SaveLinearSystem, &
44
MassMatrixAssembly, VectorValuesRange, LaplaceMatrixAssembly
45
USE MeshUtils, ONLY : SaveProjector
46
USE DefUtils, ONLY : DefaultSolve, GetElementDOFs, GetElementNodes, GetLogical
47
48
IMPLICIT NONE
49
50
TYPE(BlockMatrix_t), POINTER, SAVE :: TotMatrix
51
52
LOGICAL, PRIVATE :: isParallel=.FALSE.
53
54
TYPE(Solver_t), POINTER, SAVE :: SolverRef
55
TYPE(Variable_t), POINTER :: SolverVar => Null()
56
TYPE(Matrix_t), POINTER :: SolverMatrix => Null(), SaveMatrix
57
58
CONTAINS
59
60
! Create matrix S=P((diag(A))^-1)Q
61
!------------------------------------------------------------------------
62
FUNCTION CreateSchurApproximation(A,P,Q) RESULT ( S )
63
64
TYPE(Matrix_t), POINTER :: A, P, Q
65
TYPE(Matrix_t), POINTER :: S, R
66
67
INTEGER :: n, i, j, k, l, j2, k2
68
REAL(KIND=dp) :: val
69
LOGICAL :: Found
70
71
CALL Info('CreateSchurApproximation','Creating Shcur complement for preconditioning!',Level=20)
72
73
NULLIFY(S)
74
IF(.NOT. ASSOCIATED(P) .OR. .NOT. ASSOCIATED(Q)) THEN
75
CALL Info('CreateSchurApproximation','Constraint matrix not associated!')
76
RETURN
77
END IF
78
S => AllocateMatrix()
79
80
n = P % NumberOfRows
81
IF(n == 0) THEN
82
CALL Info('CreateSchurApproximation','No rows in Constraint matrix!')
83
RETURN
84
END IF
85
86
S % FORMAT = MATRIX_LIST
87
88
! Add the corner entry to give the max size for list.
89
CALL List_AddToMatrixElement(S % ListMatrix, n, n, 0.0_dp )
90
91
DO i=1,n
92
DO j=P % Rows(i),P % Rows(i+1)-1
93
k = P % Cols(j)
94
val = P % Values(j) / A % Values(A % Diag(k))
95
DO j2= Q % Rows(k),Q % Rows(k+1)-1
96
k2 = Q % Cols(j2)
97
CALL List_AddToMatrixElement(S % ListMatrix, i, k2, -val * Q % Values(j2) )
98
END DO
99
END DO
100
END DO
101
102
CALL List_toCRSMatrix(S)
103
104
val = 1.0_dp * SIZE(S % Values) / SIZE(P % Values)
105
WRITE(Message,'(A,ES12.3)') 'Schur matrix increase factor: ',val
106
CALL Info('CreateSchurApproximation',Message)
107
108
!ALLOCATE( S % rhs(S % NumberOfRows))
109
!S % rhs = 0.0_dp
110
111
IF( InfoActive(20) ) THEN
112
CALL VectorValuesRange(P % Values,SIZE(P % Values),'Constraint')
113
CALL VectorValuesRange(S % Values,SIZE(S % Values),'Schur')
114
END IF
115
116
END FUNCTION CreateSchurApproximation
117
118
119
120
!-----------------------------------------------------------------------------------
121
!> If a block variable does not exist it will be created.
122
!> Here only normal nodal elements are supported for the moment.
123
!> Then also the creation of permutation vector is straight-forward.
124
!> Note that no reordering is currently performed.
125
!
126
!> There is limitation regarding non-nodal elements which stems partly from the fact
127
!> that an elementtype is solver specific while this one solver could have a number of
128
!> different elementtypes for different equations.
129
!-----------------------------------------------------------------------------------
130
FUNCTION CreateBlockVariable( Solver, VariableNo, VarName, ExtDofs, ExtPerm ) RESULT ( Var )
131
132
TYPE(Solver_t), POINTER :: Solver
133
INTEGER :: VariableNo
134
CHARACTER(LEN=*) :: VarName
135
INTEGER, OPTIONAL :: ExtDofs
136
INTEGER, POINTER, OPTIONAL :: ExtPerm(:)
137
TYPE(Variable_t), POINTER :: Var
138
139
TYPE(Solver_t), POINTER :: PSolver
140
TYPE(ValueList_t), POINTER :: Params
141
TYPE(Mesh_t), POINTER :: Mesh
142
TYPE(Element_t), POINTER :: Element
143
INTEGER :: i,j,t,n,ndeg,body_id,body_id_prev,eq_id,solver_id,Dofs,nsize
144
INTEGER, POINTER :: VarPerm(:), ActiveVariables(:)
145
INTEGER, ALLOCATABLE :: Indexes(:)
146
REAL(KIND=dp), POINTER :: Values(:)
147
LOGICAL :: Hit, GotIt
148
CHARACTER(:), ALLOCATABLE :: str
149
150
LOGICAL :: GlobalBubbles, Found
151
INTEGER :: MaxNDOFs, MaxDGDOFs, MaxEDOFs, MaxFDOFs, MaxBDOFs
152
153
154
CALL Info('CreateBlockVariable','Creating block variables',Level=8)
155
156
Mesh => Solver % Mesh
157
Params => Solver % Values
158
159
IF( PRESENT( ExtDofs ) ) THEN
160
Dofs = ExtDofs
161
ELSE
162
str = 'Variable '//I2S(VariableNo)//' Dofs'
163
Dofs = ListGetInteger( Params,str, GotIt )
164
IF(.NOT. GotIt) Dofs = 1
165
END IF
166
167
IF( PRESENT( ExtPerm ) ) THEN
168
nsize = MAXVAL( ExtPerm )
169
varPerm => ExtPerm
170
GOTO 100
171
END IF
172
173
Ndeg = 0
174
MaxNDOFs = 0
175
MaxBDOFs = 0
176
MaxDGDOFs = 0
177
DO i=1, Mesh % NumberOFBulkElements
178
Element => Mesh % Elements(i)
179
MaxNDOFs = MAX( MaxNDOFs, Element % NDOFs )
180
MaxBDOFs = MAX( MaxBDOFs, Element % BDOFs )
181
MaxDGDOFs = MAX( MaxDGDOFs, Element % DGDOFs )
182
END DO
183
184
MaxEDOFs = 0
185
DO i=1, Mesh % NumberOFEdges
186
Element => Solver % Mesh % Edges(i)
187
MaxEDOFs = MAX( MaxEDOFs, Element % BDOFs )
188
END DO
189
190
MaxFDOFs = 0
191
DO i=1, Mesh % NumberOFFaces
192
Element => Solver % Mesh % Faces(i)
193
MaxFDOFs = MAX( MaxFDOFs, Element % BDOFs )
194
END DO
195
196
GlobalBubbles = ListGetLogical( Params, 'Bubbles in Global System', Found )
197
IF (.NOT.Found) GlobalBubbles = .TRUE.
198
199
Ndeg = Ndeg + Mesh % NumberOfNodes
200
IF ( MaxEDOFs > 0 ) Ndeg = Ndeg + MaxEDOFs * Mesh % NumberOFEdges
201
IF ( MaxFDOFs > 0 ) Ndeg = Ndeg + MaxFDOFs * Mesh % NumberOFFaces
202
IF ( GlobalBubbles ) &
203
Ndeg = Ndeg + MaxBDOFs * Mesh % NumberOfBulkElements
204
IF ( ListGetLogical( Params, 'Discontinuous Galerkin', Found ) ) &
205
Ndeg = MAX( NDeg, MaxDGDOFs * ( Mesh % NumberOfBulkElements + &
206
Mesh % NumberOfBoundaryElements) )
207
208
ALLOCATE( VarPerm(ndeg) )
209
VarPerm = 0
210
211
solver_id = 0
212
DO i = 1, CurrentModel % NumberOfSolvers
213
PSolver => CurrentModel % Solvers(i)
214
IF( ASSOCIATED( Solver, PSolver ) ) THEN
215
solver_id = i
216
EXIT
217
END IF
218
END DO
219
220
ALLOCATE(Indexes(Mesh % MaxElementDOFs))
221
body_id_prev = -1
222
DO t=1,Mesh % NumberOfBulkElements + Mesh % NumberOFBoundaryElements
223
Element => Mesh % Elements(t)
224
CurrentModel % CurrentElement => Element
225
226
body_id = Element % BodyId
227
IF( body_id /= body_id_prev ) THEN
228
Hit = .FALSE.
229
body_id_prev = body_id
230
231
IF( body_id < 1 ) CYCLE
232
eq_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values,'Equation')
233
IF( eq_id < 1 ) CYCLE
234
235
str='Active Variables['//i2s(solver_id)//']'
236
ActiveVariables => ListGetIntegerArray(CurrentModel % Equations(eq_id) % Values, str)
237
IF(.NOT. ASSOCIATED(ActiveVariables)) THEN
238
ActiveVariables => ListGetIntegerArray( CurrentModel % Equations(eq_id) % Values, &
239
'Active Variables')
240
END IF
241
IF( .NOT. ASSOCIATED(ActiveVariables)) CYCLE
242
IF( .NOT. ANY(ActiveVariables == VariableNo) ) CYCLE
243
Hit = .TRUE.
244
END IF
245
246
IF( Hit ) THEN
247
n=GetElementDOFs(Indexes)
248
VarPerm(Indexes(1:n)) = 1
249
END IF
250
END DO
251
252
j = 0
253
DO i = 1, SIZE(VarPerm)
254
IF( VarPerm(i) > 0 ) THEN
255
j = j + 1
256
VarPerm(i) = j
257
END IF
258
END DO
259
nsize = j
260
261
100 IF( nsize == 0 ) THEN
262
CALL Info('CreateBlockVariable','Variable '//TRIM(VarName)//' of size zero.', Level=10 )
263
END IF
264
265
CALL Info('CreateBlockVariable','Creating variable: '//TRIM(VarName), Level=6 )
266
267
CALL VariableAddVector( Mesh % Variables, Mesh, Solver, &
268
TRIM(VarName), Dofs, Perm = VarPerm )
269
270
WRITE( Message,'(A,I0,A)') 'Creating variable '//TRIM(VarName)//' with ',Dofs,' dofs'
271
CALL Info('CreateBlockVariable', Message)
272
273
Var => VariableGet( Mesh % Variables, VarName )
274
275
END FUNCTION CreateBlockVariable
276
277
278
!-------------------------------------------------------------------
279
!> This subroutine initializes the block matrix structure so that the
280
!> matrices and vectors have a natural location to save.
281
!------------------------------------------------------------------
282
SUBROUTINE BlockInitMatrix( Solver, BlockMatrix, BlockDofs, FieldDofs, SkipVar )
283
284
IMPLICIT NONE
285
286
TYPE(Solver_t), TARGET :: Solver
287
INTEGER :: BlockDofs
288
TYPE(BlockMatrix_t), POINTER :: BlockMatrix
289
INTEGER, OPTIONAL :: FieldDofs
290
LOGICAL, OPTIONAL :: SkipVar
291
292
TYPE(Solver_t), POINTER :: PSolver
293
INTEGER, POINTER :: BlockStruct(:), SlaveSolvers(:)
294
LOGICAL :: GotBlockStruct, GotSlaveSolvers, Found
295
TYPE(Matrix_t), POINTER :: Amat
296
INTEGER :: i,j,k,n,Novar
297
TYPE(ValueList_t), POINTER :: Params
298
TYPE(Variable_t), POINTER :: Var
299
CHARACTER(:), ALLOCATABLE :: VarName, str
300
LOGICAL :: UseSolverMatrix, IsComplex
301
CHARACTER(*), PARAMETER :: Caller = 'BlockInitMatrix'
302
303
304
BlockMatrix => Solver % BlockMatrix
305
IF (ASSOCIATED(BlockMatrix)) THEN
306
CALL Info(Caller,'Using existing block matrix',Level=10)
307
RETURN
308
END IF
309
310
CALL Info(Caller,'Initializing block matrix',Level=10)
311
312
Params => Solver % Values
313
IsComplex = ListGetLogical( Params,'Linear System Complex',Found)
314
IF( IsComplex ) THEN
315
CALL Info(Caller,'Assuming block matrix to be complex!',Level=10)
316
ELSE
317
CALL Info(Caller,'Assuming block matrix to be real!',Level=10)
318
END IF
319
320
ALLOCATE(Solver % BlockMatrix)
321
BlockMatrix => Solver % BlockMatrix
322
323
BlockStruct => ListGetIntegerArray( Params,'Block Structure',GotBlockStruct)
324
BlockMatrix % GotBlockStruct = GotBlockStruct
325
326
IF( GotBlockStruct ) THEN
327
IF( SIZE( BlockStruct ) /= BlockDofs ) THEN
328
CALL Fatal(Caller,'Incompatible size of > Block Structure < given!')
329
END IF
330
IF( MINVAL( BlockStruct ) < 1 .OR. MAXVAL( BlockStruct ) > BlockDofs ) THEN
331
CALL Fatal(Caller,'Incompatible values in > Block Structure < given!')
332
END IF
333
NoVar = MAXVAL( BlockStruct )
334
CALL Info(Caller,'Using given block structure of size: '//I2S(SIZE( BlockStruct)),Level=8)
335
BlockMatrix % BlockStruct => BlockStruct
336
337
ALLOCATE( BlockMatrix % InvBlockStruct(NoVar) )
338
BlockMatrix % InvBlockStruct = 0
339
DO i=1,BlockDofs
340
j = BlockStruct(i)
341
IF( BlockMatrix % InvBlockStruct(j) == 0 ) THEN
342
BlockMatrix % InvBlockStruct(j) = i
343
ELSE
344
! Block structure is not bijection for this component
345
BlockMatrix % InvBlockStruct(j) = -1
346
END IF
347
END DO
348
ELSE
349
CALL Info(Caller,'Inheriting blocks from variable dofs',Level=8)
350
NoVar = BlockDofs
351
CALL Info(Caller,'Inheriting block count '//I2S(NoVar)//' from variable dofs',Level=8)
352
END IF
353
354
355
IF( BlockMatrix % NoVar == NoVar ) THEN
356
CALL Info(Caller,'Reusing existing blockmatrix structures!',Level=6)
357
RETURN
358
ELSE IF( BlockMatrix % Novar /= 0 ) THEN
359
CALL Fatal(Caller,'Previous blockmatrix was of different size?')
360
ELSE
361
CALL Info(Caller,'Block matrix will be of size '//I2S(NoVar),Level=6)
362
END IF
363
364
BlockMatrix % Solver => Solver
365
BlockMatrix % NoVar = NoVar
366
367
368
ALLOCATE( BlockMatrix % SubMatrix(NoVar,NoVar) )
369
CALL Info(Caller,'Allocating block matrix of size '//I2S(NoVar),Level=10)
370
DO i=1,NoVar
371
DO j=1,NoVar
372
DO k=1,2
373
Amat => NULL()
374
Amat => AllocateMatrix()
375
Amat % ListMatrix => NULL()
376
Amat % FORMAT = MATRIX_LIST
377
Amat % NumberOfRows = 0
378
AMat % COMPLEX = IsComplex
379
IF( k==1) THEN
380
! First cycle creates the holder for standard matrix
381
BlockMatrix % Submatrix(i,j) % Mat => Amat
382
ELSE
383
! Second cycle creates the optional holder for preconditioning matrix
384
BlockMatrix % Submatrix(i,j) % PrecMat => Amat
385
END IF
386
END DO
387
END DO
388
END DO
389
390
ALLOCATE( BlockMatrix % SubMatrixActive(NoVar,NoVar) )
391
BlockMatrix % SubMatrixActive = .FALSE.
392
393
ALLOCATE( BlockMatrix % SubVector(NoVar))
394
DO i=1,NoVar
395
BlockMatrix % Subvector(i) % Var => NULL()
396
END DO
397
398
ALLOCATE( BlockMatrix % Offset(NoVar+1))
399
BlockMatrix % Offset = 0
400
BlockMatrix % maxsize = 0
401
402
403
IF( PRESENT( SkipVar ) ) THEN
404
IF( SkipVar ) THEN
405
CALL Info(Caller,'Skipping creation of block variables for now',Level=10)
406
BlockMatrix % ParentMatrix => Solver % Matrix
407
RETURN
408
END IF
409
END IF
410
411
412
! We may have different size of block matrix than the number of actual components.
413
! For example, when we have a projector of a scalar field our block size is (2,2)
414
! but we can only create the (1,1) from the initial matrix system.
415
IF( PRESENT( FieldDofs ) ) THEN
416
CALL Info(Caller,'Number of field components: '//I2S(FieldDofs))
417
IF( Novar /= FieldDofs ) CALL Info(Caller,'Number of fields and blocks ('&
418
//I2S(NoVar)//') differ!')
419
IF(.NOT. GotBlockStruct ) NoVar = FieldDofs
420
END IF
421
422
423
! If we have just one variable and also one matrix then no need to look further
424
! This would probably just happen for testing purposes.
425
UseSolverMatrix = (NoVar == 1 )
426
IF( UseSolverMatrix ) THEN
427
UseSolverMatrix = ASSOCIATED( Solver % Variable )
428
END IF
429
IF( UseSolverMatrix ) THEN
430
UseSolverMatrix = ASSOCIATED( Solver % Matrix )
431
END IF
432
IF( UseSolverMatrix ) THEN
433
BlockMatrix % SubVector(1) % Var => Solver % Variable
434
! BlockMatrix % SubMatrix(1,1) % Mat => Solver % Matrix
435
436
n = SIZE( Solver % Variable % Values )
437
BlockMatrix % Offset(1) = 0
438
BlockMatrix % Offset(2) = n
439
BlockMatrix % MaxSize = n
440
BlockMatrix % TotSize = n
441
CALL Info(Caller,'Using solver variable directly as block variable!',Level=10)
442
RETURN
443
END IF
444
445
SlaveSolvers => ListGetIntegerArray( Params, &
446
'Block Solvers', GotSlaveSolvers )
447
448
449
DO i = 1,NoVar
450
IF( GotSlaveSolvers ) THEN
451
IF(i==1) CALL Info(Caller,'Using slave solver variables as block variables!',Level=10)
452
453
j = SlaveSolvers(i)
454
455
CALL Info(Caller,'Associating block '//I2S(i)//' with solver: '//I2S(j),Level=10)
456
457
PSolver => CurrentModel % Solvers(j)
458
Var => PSolver % Variable
459
VarName = TRIM(Var % Name)
460
461
BlockMatrix % SubVector(i) % Solver => PSolver
462
BlockMatrix % SubMatrix(i,i) % Mat => PSolver % Matrix
463
464
ELSE
465
str = 'Variable '//I2S(i)
466
467
VarName = ListGetString( Params, str, Found )
468
IF(.NOT. Found ) THEN
469
IF( BlockMatrix % GotBlockStruct ) THEN
470
VarName = 'BlockVar '//I2S(i)
471
ELSE
472
VarName = ComponentName(Solver % Variable % Name,i)
473
END IF
474
END IF
475
Var => VariableGet( Solver % Mesh % Variables, VarName )
476
END IF
477
478
!-----------------------------------------------------------------------------------
479
! If variable does not exist it will be created.
480
! Here it is assumed that all components have the same number of dofs
481
! described by the same permutation vector. If the components are
482
! accounted in normal manner [1,2,3,...] then it suffices just to have
483
! pointers to the components of the full vector.
484
!-----------------------------------------------------------------------------------
485
IF(ASSOCIATED( Var ) ) THEN
486
CALL Info(Caller,'Using existing variable > '//VarName//' <')
487
ELSE
488
PSolver => Solver
489
IF( BlockMatrix % GotBlockStruct ) THEN
490
CALL Info(Caller,'Variable > '//VarName//' < does not exist, creating from existing Perm')
491
j = COUNT( BlockMatrix % BlockStruct == i )
492
IF( j == 0 ) THEN
493
CALL Fatal(Caller,'Invalid > Block Structure < given!')
494
END IF
495
Var => CreateBlockVariable(PSolver, i, VarName, j, Solver % Variable % Perm )
496
ELSE
497
Var => CreateBlockVariable(PSolver, i, VarName )
498
END IF
499
CALL Info(Caller,'Variable > '//VarName//' < does not exist, creating')
500
END IF
501
502
BlockMatrix % SubVector(i) % Var => Var
503
n = SIZE(Var % Values)
504
505
BlockMatrix % Offset(i+1) = BlockMatrix % Offset(i) + n
506
BlockMatrix % MaxSize = MAX( BlockMatrix % MaxSize, n )
507
END DO
508
509
BlockMatrix % TotSize = BlockMatrix % Offset( NoVar + 1 )
510
511
CALL Info(Caller,'All done',Level=12)
512
513
END SUBROUTINE BlockInitMatrix
514
515
516
517
!-------------------------------------------------------------------
518
!> This subroutine creates the missing component variables.
519
!------------------------------------------------------------------
520
SUBROUTINE BlockInitVar( Solver, BlockMatrix, BlockIndex )
521
522
IMPLICIT NONE
523
524
TYPE(Solver_t), TARGET :: Solver
525
TYPE(BlockMatrix_t), POINTER :: BlockMatrix
526
INTEGER, POINTER, OPTIONAL :: BlockIndex(:)
527
528
TYPE(Solver_t), POINTER :: PSolver
529
TYPE(Matrix_t), POINTER :: Amat
530
INTEGER :: i,j,k,n,m,Novar
531
TYPE(ValueList_t), POINTER :: Params
532
TYPE(Variable_t), POINTER :: Var
533
CHARACTER(:), ALLOCATABLE :: VarName, str
534
TYPE(Mesh_t), POINTER :: Mesh
535
REAL(KIND=dp), POINTER :: Vals(:)
536
INTEGER, POINTER :: VarPerm(:)
537
TYPE(Matrix_t), POINTER :: B
538
LOGICAL :: AddVector
539
540
Params => Solver % Values
541
Mesh => Solver % Mesh
542
NoVar = BlockMatrix % NoVar
543
BlockMatrix % Offset = 0
544
545
DO i=1,NoVar
546
Amat => BlockMatrix % Submatrix(i,i) % Mat
547
n = Amat % NumberOfRows
548
IF(n == 0) THEN
549
CALL Info('BlockInitVar','Zero rows, skipping...')
550
END IF
551
552
BlockMatrix % Offset(i+1) = BlockMatrix % Offset(i) + n
553
BlockMatrix % MaxSize = MAX( BlockMatrix % MaxSize, n )
554
555
! Is this inherited from AddMatrix ?
556
AddVector = BlockMatrix % Subvector(i) % AddVector
557
558
IF(AddVector) THEN
559
VarName = LagrangeMultiplierName( Solver )
560
ELSE
561
VarName = ComponentName("Block variable",i)
562
END IF
563
Var => VariableGet( Mesh % Variables, VarName )
564
565
IF(.NOT. ASSOCIATED( Var ) ) THEN
566
CALL Info('BlockInitVar','Variable > '//VarName//' < for size '&
567
//I2S(n)//' does not exist, creating')
568
PSolver => Solver
569
NULLIFY( Vals )
570
ALLOCATE( Vals(n) )
571
Vals = 0.0_dp
572
573
IF(AddVector) THEN
574
CALL VariableAddVector( Mesh % Variables,Mesh,PSolver,VarName,Solver % Variable % Dofs,Vals,&
575
Output = .FALSE. )
576
577
ELSE IF( PRESENT(BlockIndex) ) THEN
578
CALL Info('BlockInitVar','Using BlockIndex to pick variable and perm',Level=20)
579
NULLIFY(VarPerm)
580
m = SIZE(Solver % Variable % Values)
581
ALLOCATE(VarPerm(m))
582
VarPerm = 0
583
584
k = 0
585
DO j=1,SIZE(Solver % Variable % Values)
586
IF(BlockIndex(j) == i) THEN
587
k = k+1
588
VarPerm(j) = k
589
END IF
590
END DO
591
592
CALL VariableAdd( Mesh % Variables,Mesh,PSolver,VarName,1,Vals,&
593
Output = .FALSE., Perm = VarPerm )
594
ELSE
595
CALL VariableAdd( Mesh % Variables,Mesh,PSolver,VarName,1,Vals,&
596
Output = .FALSE. )
597
END IF
598
Var => VariableGet( Mesh % Variables, VarName )
599
ELSE
600
Var % Values = 0.0_dp
601
END IF
602
BlockMatrix % SubVector(i) % Var => Var
603
604
! We cannot initialize addvector as the dofs are not part of the original monolithic system!
605
IF(AddVector) CYCLE
606
607
IF(PRESENT(BlockIndex)) THEN
608
B => BlockMatrix % SubMatrix(i,i) % Mat
609
610
IF( ParEnv % PEs == 1 ) THEN
611
! IF(.NOT. ASSOCIATED(B % InvPerm) ) CALL Fatal('BlockInitVar','InvPerm not present for block '//I2S(11*i))
612
IF(ASSOCIATED(B % InvPerm ) ) THEN
613
Var % Values = Solver % Variable % Values(B % InvPerm)
614
END IF
615
ELSE
616
IF(.NOT. ASSOCIATED(B % Perm) ) CALL Fatal('BlockInitVar','Perm not present for block '//I2S(11*i))
617
DO j=1,SIZE(B % Perm)
618
k = B % Perm(j)
619
IF(k==0) CYCLE
620
Var % Values(k) = Solver % Variable % Values(Solver % Matrix % Perm(j))
621
END DO
622
END IF
623
624
END IF
625
626
END DO
627
628
BlockMatrix % TotSize = BlockMatrix % Offset( NoVar + 1 )
629
630
CALL Info('BlockInitVar','Block variables initialized!',Level=12)
631
632
END SUBROUTINE BlockInitVar
633
634
635
!-------------------------------------------------------------------
636
!> This subroutine copies back the full vector from its components.
637
!------------------------------------------------------------------
638
SUBROUTINE BlockBackCopyVar( Solver, BlockMatrix )
639
640
IMPLICIT NONE
641
642
TYPE(Solver_t), TARGET :: Solver
643
TYPE(BlockMatrix_t), POINTER :: BlockMatrix
644
645
TYPE(Matrix_t), POINTER :: Amat
646
INTEGER :: i,j,k,n,m,Novar
647
TYPE(Variable_t), POINTER :: Var
648
649
CALL Info('BlockBackCopyVar','Copying values back to monolithic solution vector',Level=10)
650
651
NoVar = BlockMatrix % NoVar
652
653
m = SIZE( Solver % Variable % Values )
654
655
DO i=1,NoVar
656
IF(BlockMatrix % SubVector(i) % AddVector ) THEN
657
CALL Info('BlockBackCopyVar','Skipping AddVector '//I2S(i)//' that is not associcated to the original vector!',Level=20)
658
CYCLE
659
END IF
660
661
Amat => BlockMatrix % Submatrix(i,i) % Mat
662
n = Amat % NumberOfRows
663
Var => BlockMatrix % SubVector(i) % Var
664
665
IF(.NOT. ASSOCIATED(Amat % InvPerm) ) THEN
666
CALL Warn('BlockBackCopyVar','"Amat % InvPerm" not associated!')
667
CYCLE
668
END IF
669
670
! Copy the block part to the monolithic solution
671
IF(ASSOCIATED(Amat % Perm)) THEN
672
IF( ParEnv % PEs == 1 ) THEN
673
CALL Warn('BlockBackCopyVar','Why do we have Amat % Perm in serial?')
674
END IF
675
ELSE
676
IF( ParEnv % PEs > 1 ) THEN
677
CALL Warn('BlockBackCopyVar','Why do we not have Amat % Perm in parallel?')
678
END IF
679
END IF
680
681
! Note that confusingly InvPerm has different defintion in serial and parallel.
682
! In serial it points just to indexes of the original matrix.
683
! In parallel it points to all possible indexes that could be present.
684
IF( ParEnv % PEs > 1 ) THEN
685
DO j=1,SIZE(Amat % Perm)
686
k = Amat % Perm(j)
687
IF(k==0) CYCLE
688
Solver % Variable % Values(Solver % Matrix % Perm(j)) = Var % Values(k)
689
END DO
690
ELSE
691
WHERE(Amat % InvPerm > 0)
692
Solver % Variable % Values(Amat % InvPerm) = Var % Values
693
END WHERE
694
END IF
695
696
END DO
697
698
BlockMatrix % TotSize = BlockMatrix % Offset( NoVar + 1 )
699
700
CALL Info('BlockBackCopyVar','All done',Level=15)
701
702
END SUBROUTINE BlockBackCopyVar
703
704
705
706
!-------------------------------------------------------------------------------------
707
!> Picks the components of a full matrix to the submatrices of a block matrix.
708
!> On choice, the user may have exactly the same block matrix structure than
709
!> a leading component.
710
!-------------------------------------------------------------------------------------
711
SUBROUTINE BlockPickMatrix( Solver, NoVar )
712
713
TYPE(Solver_t) :: Solver
714
INTEGER :: Novar
715
716
INTEGER :: RowVar, ColVar
717
TYPE(Matrix_t), POINTER :: SolverMatrix
718
TYPE(Matrix_t), POINTER :: Amat
719
TYPE(ValueList_t), POINTER :: Params
720
LOGICAL :: ReuseMatrix, Found, EliminateZero
721
INTEGER::i,j,k,l,n
722
REAL(KIND=DP) :: SumAbsMat
723
724
CALL Info('BlockPickMatrix','Picking block matrix of size '//I2S(NoVar)//' from monolithic one',Level=10)
725
726
SolverMatrix => Solver % Matrix
727
Params => Solver % Values
728
729
ReuseMatrix = ListGetLogical( Params,'Block Matrix Reuse',Found)
730
EliminateZero = ListGetLogical( Params, &
731
'Block Eliminate Zero Submatrices', Found )
732
733
DO RowVar=1,NoVar
734
DO ColVar=1,NoVar
735
Amat => TotMatrix % Submatrix(RowVar,ColVar) % Mat
736
IF( TotMatrix % GotBlockStruct) THEN
737
! A generic picking method for submatrices
738
!----------------------------------------------------------------------
739
CALL Info('BlockPickMatrix','Picking generic block matrix ('&
740
//I2S(RowVar)//','//I2S(ColVar)//')',Level=20)
741
CALL CRS_BlockMatrixPick2(SolverMatrix,Amat,TotMatrix % BlockStruct,RowVar,ColVar)
742
ELSE
743
! Picking of standard submatrices of size one.
744
!----------------------------------------------------------------------
745
IF( ReuseMatrix ) THEN
746
IF( RowVar + ColVar > 2 .AND. Amat % NumberOfRows == 0 ) THEN
747
CALL Info('BlockPickMatrix','Copying block matrix topology ('&
748
//I2S(RowVar)//','//I2S(ColVar)//')',Level=20)
749
CALL CRS_CopyMatrixTopology( TotMatrix % Submatrix(1,1) % Mat, Amat )
750
END IF
751
END IF
752
CALL Info('BlockPickMatrix','Picking simple block matrix ('&
753
//I2S(RowVar)//','//I2S(ColVar)//')',Level=20)
754
CALL CRS_BlockMatrixPick(SolverMatrix,Amat,NoVar,RowVar,ColVar,RowVar == ColVar )
755
756
IF( EliminateZero ) THEN
757
IF( Amat % NumberOfRows > 0 ) THEN
758
SumAbsMat = SUM( ABS( Amat % Values ) )
759
IF( SumAbsMat < SQRT( TINY( SumAbsMat ) ) ) THEN
760
CALL Info('BlockPickMatrix','Matrix is actually all zero, eliminating it!',Level=12)
761
DEALLOCATE( Amat % Values )
762
IF( .NOT. ReuseMatrix ) THEN
763
DEALLOCATE( Amat % Rows, Amat % Cols )
764
IF( RowVar == ColVar ) DEALLOCATE( Amat % Diag, Amat % rhs )
765
END IF
766
Amat % NumberOfRows = 0
767
END IF
768
END IF
769
END IF
770
771
END IF
772
773
! CALL CRS_SortMatrix( Amat, .TRUE. )
774
END DO
775
END DO
776
777
BLOCK
778
INTEGER, POINTER :: BlockStruct(:),BlockPerm(:)
779
INTEGER :: nl,nk,nv,n0,nj
780
781
CALL Info('BlockPickMatrix','Creating permutation to map between block and mono vectors',Level=12)
782
783
n = SolverMatrix % NumberOfRows
784
IF(.NOT. ASSOCIATED( TotMatrix % BlockPerm ) ) THEN
785
ALLOCATE( TotMatrix % BlockPerm(n) )
786
END IF
787
BlockPerm => TotMatrix % BlockPerm
788
BlockPerm = 0
789
790
IF( TotMatrix % GotBlockStruct ) THEN
791
BlockStruct => TotMatrix % BlockStruct
792
793
! This is permutation for nontrivial block structure, for example (1 1 1 2)
794
nl = SIZE(BlockStruct) ! number of original components
795
nk = MAXVAL(BlockStruct) ! number of blocks
796
nv = n / nl ! size of each field
797
798
DO k=1,nk
799
n0 = COUNT(BlockStruct < k ) ! number of components prior to this block
800
nj = COUNT(BlockStruct == k ) ! number of components in this block
801
j = 0
802
DO l=1,nl
803
IF(BlockStruct(l) /= k) CYCLE
804
j = j+1
805
DO i=1,nv
806
BlockPerm(nv*n0+nj*(i-1)+j) = nl*(i-1)+l
807
END DO
808
END DO
809
END DO
810
ELSE
811
! This is trivial numbering for default block structure (1 2 3 4 ...)
812
nv = n/NoVar
813
DO j=1,NoVar
814
DO i=1,nv
815
BlockPerm((j-1)*nv+i) = Novar*(i-1) + j
816
END DO
817
END DO
818
END IF
819
END BLOCK
820
821
END SUBROUTINE BlockPickMatrix
822
823
824
!-------------------------------------------------------------------------------------
825
!> Picks the components of a full matrix to given domains or bodies.
826
!> The rest stays in 1st domain.
827
!-------------------------------------------------------------------------------------
828
SUBROUTINE BlockPickDofsPhysical( Solver, BlockIndex, NoVar )
829
830
TYPE(Solver_t), POINTER :: Solver
831
INTEGER, POINTER :: BlockIndex(:)
832
INTEGER :: Novar
833
834
INTEGER::i,j,k,t,n,MinBlock,MaxBlock,body_id,bf_id,bc_id,n_bf
835
TYPE(ValueList_t), POINTER :: List
836
TYPE(Mesh_t), POINTER :: Mesh
837
TYPE(Element_t), POINTER :: Element
838
LOGICAL :: Found
839
INTEGER :: ElemPerm(27)
840
INTEGER, POINTER :: Perm(:)
841
842
843
CALL Info('BlockPickDofsPhysical','Picking block matrix of size '&
844
//I2S(NoVar)//' from monolithic one',Level=10)
845
846
n_bf = CurrentModel % NumberOfBodyForces
847
848
MinBlock = HUGE(MinBlock)
849
MaxBlock = 0
850
DO i=1,n_bf + CurrentModel % NumberOfBCs
851
IF( i <= n_bf ) THEN
852
List => CurrentModel % BodyForces(i) % Values
853
ELSE
854
List => CurrentModel % BCs(i-n_bf) % Values
855
END IF
856
j = ListGetInteger( List,'Block Index',Found )
857
IF( Found ) THEN
858
MinBlock = MIN(j,MinBlock)
859
MaxBlock = MAX(j,MaxBlock)
860
END IF
861
END DO
862
863
IF( MaxBlock == 0 ) THEN
864
CALL Fatal('BlockPickDofsPhysical','Cannot create a physical block structure as no >Block Index< given!')
865
END IF
866
867
Mesh => Solver % Mesh
868
Perm => Solver % Variable % Perm
869
n = MAXVAL( Perm )
870
BlockIndex = 0
871
872
DO t=1, Mesh % NumberOfBulkElements + Mesh % NumberOfBoundaryElements
873
Element => Mesh % Elements(t)
874
IF( t <= Mesh % NumberOfBulkElements ) THEN
875
body_id = Element % BodyId
876
bf_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values,'Body Force', Found )
877
IF( bf_id == 0 ) CYCLE
878
List => CurrentModel % BodyForces(bf_id) % Values
879
ELSE
880
IF(.NOT. ASSOCIATED( Element % BoundaryInfo ) ) CYCLE
881
DO bc_id=1,CurrentModel % NumberOfBCs
882
IF ( Element % BoundaryInfo % Constraint == CurrentModel % BCs(bc_id) % Tag ) EXIT
883
END DO
884
IF ( bc_id > CurrentModel % NumberOfBCs ) CYCLE
885
List => CurrentModel % BCs(bc_id) % Values
886
END IF
887
888
j = ListGetInteger( List,'Block Index',Found )
889
IF( .NOT. Found ) CYCLE
890
891
n = Element % Type % NumberOfNodes
892
ElemPerm(1:n) = Perm( Element % NodeIndexes(1:n) )
893
IF( ANY(ElemPerm(1:n) == 0 ) ) CYCLE
894
895
BlockIndex( ElemPerm(1:n) ) = j
896
END DO
897
898
n = COUNT( BlockIndex == 0 )
899
IF( n > 0 ) THEN
900
CALL Info('BlockPickDofsPhysical','Number of indexes without block matrix index: '//I2S(n),Level=7)
901
IF( MinBlock > 1 ) THEN
902
k = 1
903
ELSE
904
MaxBlock = MaxBlock + 1
905
k = MaxBlock
906
END IF
907
WHERE( BlockIndex == 0 ) BlockIndex = k
908
ELSE
909
CALL Info('BlockPickDofsPhysical','All physical domains given block index',Level=10)
910
END IF
911
912
MaxBlock = ParallelReduction(MaxBlock, 2 )
913
NoVar = MaxBlock
914
915
END SUBROUTINE BlockPickDofsPhysical
916
917
918
919
!-------------------------------------------------------------------------------------
920
!> Arranges the DOFs of a H(div) approximation into groups
921
!-------------------------------------------------------------------------------------
922
SUBROUTINE BlockPickHdiv( Solver, BlockIndex, NoVar )
923
924
TYPE(Solver_t), POINTER :: Solver
925
INTEGER, POINTER :: BlockIndex(:)
926
INTEGER :: Novar
927
928
INTEGER :: i,j,n,nn,ne,nf,nb,nnis,neis,nfis,nbis
929
INTEGER :: nncount,necount,nfcount,nbcount
930
TYPE(Mesh_t), POINTER :: Mesh
931
LOGICAL :: Found
932
INTEGER, POINTER :: Perm(:)
933
934
935
CALL Info('BlockPickHdiv','Picking block matrix for mixed hdiv solver',Level=10)
936
937
Mesh => Solver % Mesh
938
nn = Mesh % NumberOfNodes
939
ne = Mesh % NumberOfEdges
940
nf = Mesh % NumberOfFaces
941
nb = Mesh % NumberOfBulkElements
942
943
! true/false flags whether dof type exists
944
nnis = 0
945
neis = 0
946
nfis = 0
947
nbis = 0
948
949
! counter of types of dofs
950
nncount = 0
951
necount = 0
952
nfcount = 0
953
nbcount = 0
954
955
Perm => Solver % Variable % Perm
956
n = SIZE( Perm )
957
958
DO i=1,n
959
j = Perm(i)
960
IF( j == 0 ) CYCLE
961
962
IF( i <= nn ) THEN
963
nnis = 1
964
nncount = nncount + 1
965
BlockIndex(j) = 1
966
ELSE IF( i <= nn + ne ) THEN
967
neis = 1
968
necount = necount + 1
969
BlockIndex(j) = nnis + 1
970
ELSE IF( i <= nn + ne + nf ) THEN
971
nfis = 1
972
nfcount = nfcount + 1
973
BlockIndex(j) = nnis + neis + 1
974
ELSE
975
nbis = 1
976
nbcount = nbcount + 1
977
BlockIndex(j) = nnis + neis + nfis + 1
978
END IF
979
END DO
980
981
IF( nncount > 0 ) CALL Info('BlockPickHdiv','Number of nodal dofs: '//I2S(nncount),Level=8)
982
IF( necount > 0 ) CALL Info('BlockPickHdiv','Number of edge dofs: '//I2S(necount),Level=8)
983
IF( nfcount > 0 ) CALL Info('BlockPickHdiv','Number of face dofs: '//I2S(nfcount),Level=8)
984
IF( nbcount > 0 ) CALL Info('BlockPickHdiv','Number of elemental dofs: '//I2S(nbcount),Level=8)
985
986
NoVar = nnis + neis + nfis + nbis
987
988
CALL Info('BlockPickHdiv','Found dofs related to '//I2S(NoVar)//' groups',Level=6)
989
990
END SUBROUTINE BlockPickHdiv
991
992
993
!-------------------------------------------------------------------------------------
994
!> Arranges the DOFs of a H(curl) approximation into groups
995
!-------------------------------------------------------------------------------------
996
SUBROUTINE BlockPickAV( Solver, BlockIndex, NoVar )
997
998
TYPE(Solver_t), POINTER :: Solver
999
INTEGER, POINTER :: BlockIndex(:)
1000
INTEGER :: Novar
1001
1002
INTEGER :: i,j,n,nn,ne,nf,nb,ais,vis,pis,dofs
1003
INTEGER :: vcount,acount,pcount
1004
TYPE(Mesh_t), POINTER :: Mesh
1005
LOGICAL :: Found, SplitComplex, SplitComplexHcurl, SplitPiola
1006
INTEGER, POINTER :: Perm(:)
1007
1008
1009
CALL Info('BlockPickAV','Picking block matrix for V and A dofs',Level=10)
1010
1011
1012
SplitPiola = ListGetLogical( Solver % Values,'Block Split Piola',Found )
1013
1014
Mesh => Solver % Mesh
1015
nn = Mesh % NumberOfNodes
1016
ne = Mesh % NumberOfEdges
1017
nf = Mesh % NumberOfFaces
1018
nb = Mesh % NumberOfBulkElements
1019
1020
! true/false flags whether dof type exists
1021
ais = 0
1022
vis = 0
1023
pis = 0
1024
1025
! counter of types of dofs
1026
vcount = 0
1027
acount = 0
1028
pcount = 0
1029
1030
Perm => Solver % Variable % Perm
1031
n = SIZE( Perm )
1032
BlockIndex = 0
1033
1034
dofs = Solver % Variable % Dofs
1035
IF(dofs > 2) THEN
1036
CALL Fatal('BlockPickAV','Only implemented for 1 or 2 dofs: '//I2S(dofs))
1037
END IF
1038
1039
DO i=1,n
1040
j = Perm(i)
1041
IF( j == 0 ) CYCLE
1042
1043
IF( i <= nn ) THEN
1044
vis = 1
1045
vcount = vcount + 1
1046
BlockIndex(dofs*j) = 1
1047
ELSE
1048
IF(SplitPiola .AND. i > nn+ne ) THEN
1049
pis = 1
1050
pcount = pcount + 1
1051
BlockIndex(dofs*j) = vis + ais + 1
1052
ELSE
1053
ais = 1
1054
acount = acount + 1
1055
BlockIndex(dofs*j) = vis + 1
1056
END IF
1057
END IF
1058
END DO
1059
1060
IF( vcount > 0 ) CALL Info('BlockPickAV','Number of nodal dofs: '//I2S(vcount),Level=8)
1061
IF( acount > 0 ) CALL Info('BlockPickAV','Number of edge dofs: '//I2S(acount),Level=8)
1062
IF( pcount > 0 ) CALL Info('BlockPickAV','Number of piola edge dofs: '//I2S(pcount),Level=8)
1063
1064
NoVar = vis + ais + pis
1065
1066
IF(dofs > 1) THEN
1067
SplitComplex = ListGetLogical( Solver % Values,'Block Split Complex',Found )
1068
SplitComplexHcurl = ListGetLogical( Solver % Values,'Block Split Complex Hcurl', Found )
1069
IF(SplitComplex .OR. SplitComplexHcurl ) THEN
1070
CALL Info('BlockPickAV','Applying different block numbering to Re/Im dofs',Level=8)
1071
! [1 2] -> [2 4] -> [1 2 3 4]
1072
BlockIndex = 2 * BlockIndex
1073
BlockIndex(1::2) = BlockIndex(2::2)-1
1074
NoVar = 2*NoVar
1075
1076
! Just split the Hcurl part, make the nodal ones have the same index.
1077
IF(SplitComplexHcurl) THEN
1078
IF(vcount > 0) THEN
1079
BlockIndex = MAX(1,BlockIndex - 1)
1080
NoVar = NoVar-1
1081
CALL Info('BlockPickAV','Moved nodal dofs to same block',Level=8)
1082
END IF
1083
END IF
1084
ELSE
1085
CALL Info('BlockPickAV','Applying same block numbering to Re/Im dofs',Level=8)
1086
BlockIndex(1::2) = BlockIndex(2::2)
1087
END IF
1088
END IF
1089
1090
CALL Info('BlockPickAV','Found dofs related to '//I2S(NoVar)//' groups',Level=6)
1091
1092
END SUBROUTINE BlockPickAV
1093
1094
1095
!-------------------------------------------------------------------------------------
1096
!> Splits complex matrix into Re and Im parts.
1097
!-------------------------------------------------------------------------------------
1098
SUBROUTINE BlockPickReIm( Solver, BlockIndex, NoVar )
1099
1100
TYPE(Solver_t), POINTER :: Solver
1101
INTEGER, POINTER :: BlockIndex(:)
1102
INTEGER :: Novar
1103
1104
INTEGER :: dofs
1105
1106
CALL Info('BlockPickReIm','Picking block matrix for Re and Im dofs',Level=10)
1107
1108
dofs = Solver % Variable % Dofs
1109
IF(MODULO(dofs,2) /= 0) THEN
1110
CALL Fatal('BlockPickReIm','Cannot pick from odd number of dofs: '//I2S(dofs))
1111
END IF
1112
1113
NoVar = 2
1114
BlockIndex(1::2) = 1
1115
BlockIndex(2::2) = 2
1116
1117
END SUBROUTINE BlockPickReIm
1118
1119
1120
!-------------------------------------------------------------------------------------
1121
!> Picks the components of a full matrix when blockindex table is given.
1122
!-------------------------------------------------------------------------------------
1123
SUBROUTINE BlockPickMatrixPerm( Solver, BlockIndex, NoVar, DoAddMatrix )
1124
1125
TYPE(Solver_t) :: Solver
1126
INTEGER, POINTER :: BlockIndex(:)
1127
INTEGER :: Novar
1128
LOGICAL :: DoAddMatrix
1129
1130
INTEGER :: bcol,brow,bi,bk,i,k,j,n,m,istat,NoBlock,dofs
1131
TYPE(Matrix_t), POINTER :: A, B, C
1132
INTEGER, ALLOCATABLE :: BlockNumbering(:), rowcount(:), offset(:)
1133
LOGICAL :: SplitComplex, SplitComplexHCurl, CreatePermPar, GotDiag, Found
1134
REAL(KIND=dp) :: Coeff, Coeff0
1135
1136
CALL Info('BlockPickMatrixPerm','Picking indexed block matrix from monolithic one',Level=10)
1137
1138
A => Solver % Matrix
1139
1140
n = A % NumberOfRows
1141
IF(DoAddMatrix) THEN
1142
NoBlock = NoVar + 1
1143
n = Solver % Matrix % AddMatrix % NumberOfRows
1144
ELSE
1145
NoBlock = NoVar
1146
n = Solver % Matrix % NumberOfRows
1147
END IF
1148
1149
ALLOCATE( BlockNumbering( n ), rowcount(NoVar), offset(NoBlock+1), STAT=istat )
1150
IF(istat /= 0) THEN
1151
CALL Fatal('BlockPickMatrixPerm','Allocation error for BlockNumbering etc.')
1152
END IF
1153
BlockNumbering = 0
1154
RowCount = 0
1155
offset = 0
1156
1157
IF(.NOT. ASSOCIATED(TotMatrix % BlockPerm) ) THEN
1158
ALLOCATE(TotMatrix % BlockPerm(n))
1159
END IF
1160
TotMatrix % BlockPerm = 0
1161
1162
n = Solver % Matrix % NumberOfRows
1163
DO i=1,n
1164
brow = BlockIndex(i)
1165
rowcount(brow) = rowcount(brow) + 1
1166
BlockNumbering(i) = rowcount(brow)
1167
END DO
1168
1169
CreatePermPar = ASSOCIATED(A % InvPerm) .AND. ( ParEnv % PEs > 1 )
1170
1171
DO i = 1, NoVar
1172
B => TotMatrix % SubMatrix(i,i) % Mat
1173
n = rowcount(i)
1174
1175
IF(ASSOCIATED(B % rhs)) THEN
1176
IF(SIZE(B % Rhs) /= n) DEALLOCATE( B % rhs)
1177
END IF
1178
IF(.NOT. ASSOCIATED(B % rhs)) THEN
1179
ALLOCATE(B % Rhs(n))
1180
END IF
1181
B % rhs = 0.0_dp
1182
1183
! Create Perm only in parallel
1184
IF( CreatePermPar ) THEN
1185
m = SIZE( Solver % Variable % Perm ) * Solver % Variable % Dofs
1186
IF(ASSOCIATED(B % Perm)) THEN
1187
IF(SIZE(B % Perm) /= m) DEALLOCATE( B % Perm)
1188
END IF
1189
IF(.NOT. ASSOCIATED(B % Perm)) THEN
1190
ALLOCATE(B % Perm(m))
1191
END IF
1192
B % Perm = 0
1193
END IF
1194
1195
! Always generate InvPerm
1196
IF(ASSOCIATED(B % InvPerm)) THEN
1197
IF(SIZE(B % InvPerm) /= n) DEALLOCATE( B % InvPerm)
1198
END IF
1199
IF(.NOT. ASSOCIATED(B % InvPerm)) THEN
1200
ALLOCATE(B % InvPerm(n))
1201
END IF
1202
B % InvPerm = 0
1203
1204
! Add the (n,n) entry since this helps to create most efficiently the full ListMatrix
1205
! CALL AddToMatrixElement(B,n,n,0.0_dp)
1206
1207
offset(i+1) = offset(i) + n
1208
END DO
1209
1210
DO i=1,NoVar
1211
DO j=1,NoVar
1212
B => TotMatrix % SubMatrix(i,j) % Mat
1213
IF ( B % Format == MATRIX_CRS ) B % Values = 0
1214
END DO
1215
END DO
1216
1217
n = Solver % Matrix % NumberOfRows
1218
DO i=1, A % NumberOfRows
1219
1220
brow = BlockIndex(i)
1221
bi = BlockNumbering(i)
1222
1223
B => TotMatrix % SubMatrix(brow,brow) % Mat
1224
B % Rhs(bi) = A % Rhs(i)
1225
1226
IF( CreatePermPar ) THEN
1227
j = A % InvPerm(i)
1228
IF(j<0 .OR. j>SIZE(B % Perm)) THEN
1229
PRINT *,'Too big j:',j,SIZE(B % Perm),i,SIZE(A % Perm),SIZE(A % InvPerm)
1230
STOP
1231
END IF
1232
B % Perm(j) = bi
1233
B % InvPerm(bi) = j
1234
ELSE
1235
B % InvPerm(bi) = i
1236
END IF
1237
1238
TotMatrix % BlockPerm(offset(brow)+bi) = i
1239
1240
DO j=A % Rows(i+1)-1,A % Rows(i),-1
1241
1242
k = A % Cols(j)
1243
! IF ( k>n) CYCLE
1244
1245
bcol = BlockIndex(k)
1246
bk = BlockNumbering(k)
1247
1248
B => TotMatrix % SubMatrix(brow,bcol) % Mat
1249
CALL AddToMatrixElement(B,bi,bk,A % Values(j))
1250
END DO
1251
END DO
1252
1253
IF( DoAddMatrix ) THEN
1254
CALL Info('BlockPickMatrixPerm','Creating additional submatrices from AddMatrix block system!',Level=10)
1255
C => Solver % Matrix % AddMatrix
1256
1257
i = NoBlock
1258
B => TotMatrix % SubMatrix(i,i) % Mat
1259
n = C % NumberOfRows - A % NumberOfRows
1260
offset(i+1) = offset(i) + n
1261
1262
CALL Info('BlockPickMatrixPerm','Number of new rows from AddMatrix: '//I2S(n),Level=20)
1263
1264
TotMatrix % Subvector(i) % AddVector = .TRUE.
1265
1266
IF(ASSOCIATED(B % rhs)) THEN
1267
IF(SIZE(B % Rhs) /= n) DEALLOCATE( B % rhs)
1268
END IF
1269
IF(.NOT. ASSOCIATED(B % rhs)) THEN
1270
ALLOCATE(B % Rhs(n))
1271
END IF
1272
B % rhs = 0.0_dp
1273
1274
IF(ASSOCIATED(B % InvPerm)) THEN
1275
IF(SIZE(B % InvPerm) /= n) DEALLOCATE( B % InvPerm)
1276
END IF
1277
IF(.NOT. ASSOCIATED(B % InvPerm)) THEN
1278
ALLOCATE(B % InvPerm(n))
1279
END IF
1280
B % InvPerm = 0
1281
1282
DO i=1,C % NumberOfRows
1283
IF(i <= A % NumberOfRows ) THEN
1284
IF( A % ConstrainedDOF(i) ) CYCLE
1285
brow = BlockIndex(i)
1286
bi = BlockNumbering(i)
1287
GotDiag = .TRUE.
1288
ELSE
1289
brow = NoBlock
1290
bi = i-A % NumberOfRows
1291
GotDiag = .FALSE.
1292
END IF
1293
1294
B => TotMatrix % SubMatrix(brow,brow) % Mat
1295
B % Rhs(bi) = B % Rhs(bi) + C % Rhs(i)
1296
1297
! IF( CreatePermPar )
1298
IF(i> A % NumberOfRows ) THEN
1299
B % InvPerm(bi) = i
1300
TotMatrix % BlockPerm(offset(brow)+bi) = i
1301
END IF
1302
1303
1304
DO j=C % Rows(i+1)-1,C % Rows(i),-1
1305
k = C % Cols(j)
1306
IF(k <= A % NumberOfRows ) THEN
1307
bcol = BlockIndex(k)
1308
bk = BlockNumbering(k)
1309
ELSE
1310
bcol = NoBlock
1311
bk = k-A % NumberOfRows
1312
IF(brow == bcol .AND. bi == bk) GotDiag = .TRUE.
1313
END IF
1314
1315
B => TotMatrix % SubMatrix(brow,bcol) % Mat
1316
CALL AddToMatrixElement(B,bi,bk,C % Values(j))
1317
END DO
1318
1319
! The matrix should have diagonal entries.
1320
! If they are complex, they should be symmetric.
1321
IF(.NOT. GotDiag ) THEN
1322
B => TotMatrix % SubMatrix(brow,brow) % Mat
1323
CALL AddToMatrixElement( B,bi,bi,0._dp )
1324
IF( A % COMPLEX ) THEN
1325
IF(MOD(bi,2)==0) THEN
1326
CALL AddToMatrixElement( B,bi,bi-1,0._dp )
1327
ELSE
1328
CALL AddToMatrixElement( B,bi,bi+1,0._dp )
1329
END IF
1330
END IF
1331
END IF
1332
1333
END DO
1334
END IF
1335
1336
DO i = 1, NoBlock
1337
DO j = 1, NoBlock
1338
B => TotMatrix % SubMatrix(i,j) % Mat
1339
IF( B % FORMAT == MATRIX_LIST ) THEN
1340
CALL Info('BlockPickMatrixPerm','Transforming submatrix '//I2S(10*i+j)//' to CRS format',Level=12)
1341
CALL List_toCRSMatrix(B)
1342
END IF
1343
1344
IF( i==j .AND. ParEnv % PEs > 1 ) THEN
1345
CALL ParallelInitMatrix( Solver, B )
1346
END IF
1347
END DO
1348
END DO
1349
1350
IF( ASSOCIATED(A % PrecValues) ) THEN
1351
CALL Info('BlockPickMatrixPerm','Creating preconditioning matrix from monolithic one!')
1352
1353
! Note that only diagonal prec matrices are created since only they are used
1354
! to solve the actual block equations.
1355
DO i = 1, NoVar
1356
CALL CRS_CopyMatrixTopology( TotMatrix % Submatrix(i,i) % Mat, &
1357
TotMatrix % Submatrix(i,i) % PrecMat )
1358
END DO
1359
1360
! If we use ReIm splitting then we need to carry the off-diagonal prec values too,
1361
! since they will be later added to the diagonal.
1362
SplitComplex = ListGetLogical( Solver % Values,'Block Split Complex',Found )
1363
1364
IF( SplitComplex ) THEN
1365
SplitComplexHcurl = ListGetLogical( Solver % Values,'Block Split Complex Hcurl', Found )
1366
IF(.NOT. SplitComplexHCurl ) THEN
1367
IF( MODULO(NoVar,2) /= 0) THEN
1368
CALL Fatal('BlockPickMatrixPerm','Requiring even number of blocks for the complex preconditioner!')
1369
END IF
1370
END IF
1371
Coeff0 = ListGetCReal( Solver % Values,'Prec Matrix Complex Coeff',Found)
1372
IF(.NOT. Found) Coeff0 = 1.0_dp
1373
END IF
1374
1375
DO i=1,A % NumberOfRows
1376
brow = BlockIndex(i)
1377
bi = BlockNumbering(i)
1378
1379
DO j=A % Rows(i+1)-1,A % Rows(i),-1
1380
k = A % Cols(j)
1381
1382
bcol = BlockIndex(k)
1383
bk = BlockNumbering(k)
1384
1385
IF(bcol == brow ) THEN
1386
B => TotMatrix % SubMatrix(brow,brow) % PrecMat
1387
CALL AddToMatrixElement(B,bi,bk,A % PrecValues(j))
1388
ELSE IF( SplitComplex .AND. ABS(bcol-brow)==1) THEN
1389
IF(SplitComplexHcurl ) THEN
1390
IF(brow == 2 .AND. bcol == 3) THEN
1391
Coeff = Coeff0
1392
ELSE IF(brow == 3 .AND. bcol == 2 ) THEN
1393
Coeff = -Coeff0
1394
ELSE
1395
CYCLE
1396
END IF
1397
ELSE
1398
IF( MODULO(brow,2) == 1 .AND. bcol == brow+1) THEN
1399
Coeff = Coeff0
1400
ELSE IF( MODULO(brow,2) == 0 .AND. bcol == brow-1) THEN
1401
Coeff = -Coeff0
1402
ELSE
1403
CYCLE
1404
END IF
1405
END IF
1406
B => TotMatrix % SubMatrix(brow,brow) % PrecMat
1407
CALL AddToMatrixElement(B,bi,bk,Coeff*A % PrecValues(j))
1408
END IF
1409
END DO
1410
END DO
1411
END IF
1412
1413
1414
END SUBROUTINE BlockPickMatrixPerm
1415
1416
1417
1418
1419
1420
1421
#if 0
1422
!-------------------------------------------------------------------------------------
1423
!> Picks the components of a full matrix to the submatrices of a block matrix assuming AV solver.
1424
!-------------------------------------------------------------------------------------
1425
SUBROUTINE BlockPickMatrixAV( Solver, NoVar )
1426
1427
TYPE(Solver_t) :: Solver
1428
INTEGER :: Novar
1429
1430
INTEGER :: RowVar, ColVar
1431
TYPE(Matrix_t), POINTER :: SolverMatrix
1432
TYPE(Matrix_t), POINTER :: Amat
1433
INTEGER::i,j,k,i_aa,i_vv,i_av,i_va,n;
1434
TYPE(Matrix_t), POINTER :: B_aa,B_av,B_va,B_vv,C_aa,C_vv,A,CM
1435
REAL(KIND=DP) :: SumAbsMat
1436
1437
CALL Info('BlockPickMatrixAV','Picking block matrix from monolithic one',Level=8)
1438
1439
SolverMatrix => Solver % Matrix
1440
1441
A => SolverMatrix
1442
i_aa=0; i_vv=0; i_av=0; i_va=0;
1443
n = Solver % Mesh % NumberOfNodes
1444
1445
B_vv => TotMatrix % SubMatrix(1,1) % Mat
1446
B_va => TotMatrix % SubMatrix(1,2) % Mat
1447
B_av => TotMatrix % SubMatrix(2,1) % Mat
1448
B_aa => TotMatrix % SubMatrix(2,2) % Mat
1449
1450
IF(ASSOCIATED(B_aa % Values)) B_aa % Values=0._dp
1451
IF(ASSOCIATED(B_av % Values)) B_av % Values=0._dp
1452
IF(ASSOCIATED(B_va % Values)) B_va % Values=0._dp
1453
IF(ASSOCIATED(B_vv % Values)) B_vv % Values=0._dp
1454
1455
DO i=1,SIZE(Solver % Variable % Perm)
1456
j = Solver % Variable % Perm(i)
1457
IF(j<=0) CYCLE
1458
IF (i<=n) THEN
1459
i_vv=i_vv+1
1460
ELSE
1461
i_aa=i_aa+1
1462
END IF
1463
DO k=A % Rows(j+1)-1,A % Rows(j),-1
1464
! IF(A % Cols(k) /= j.AND.A % Values(k)==0) CYCLE
1465
1466
IF(i<=n.AND.A % Cols(k)<=n) THEN
1467
CALL AddToMatrixElement(B_vv,i_vv,A % Cols(k),A % Values(k))
1468
ELSE IF (i<=n.AND.A % Cols(k)>n) THEN
1469
CALL AddToMatrixElement(B_va,i_vv,A % Cols(k)-n,A % Values(k))
1470
ELSE IF (i>n.AND.A % Cols(k)<=n) THEN
1471
CALL AddToMatrixElement(B_av,i_aa,A % Cols(k),A % Values(k))
1472
ELSE
1473
CALL AddToMatrixElement(B_aa,i_aa,A % Cols(k)-n,A % Values(k))
1474
END IF
1475
END DO
1476
END DO
1477
1478
IF (B_aa % Format == MATRIX_LIST) THEN
1479
CALL List_toCRSMatrix(B_aa)
1480
CALL List_toCRSMatrix(B_av)
1481
CALL List_toCRSMatrix(B_va)
1482
CALL List_toCRSMatrix(B_vv)
1483
END IF
1484
1485
IF(ASSOCIATED(B_aa % Rhs)) THEN
1486
DEALLOCATE(B_aa % Rhs, B_vv % Rhs)
1487
END IF
1488
1489
ALLOCATE(B_aa % Rhs(B_aa % NumberOfRows))
1490
ALLOCATE(B_vv % Rhs(B_vv % NumberOfRows))
1491
1492
i_vv=0; i_aa=0
1493
DO i=1,SIZE(Solver % Variable % Perm)
1494
j = Solver % Variable % Perm(i)
1495
IF(j<=0) CYCLE
1496
IF (i<=n) THEN
1497
i_vv=i_vv+1
1498
B_vv % Rhs(i_vv) = A % Rhs(j)
1499
ELSE
1500
i_aa=i_aa+1
1501
B_aa % Rhs(i_aa) = A % Rhs(j)
1502
END IF
1503
END DO
1504
1505
1506
! Also inherit the constraints, if any
1507
! If the constraints are treated as block matrix also the
1508
! pointer should not be associated.
1509
CM => A % ConstraintMatrix
1510
IF( ASSOCIATED(CM) ) THEN
1511
CALL Info('BlockPickMatrixAV','Adding constraint matrices to block AV system!',Level=10)
1512
END IF
1513
1514
DO WHILE(ASSOCIATED(CM))
1515
C_aa=>AllocateMatrix(); C_aa % Format=MATRIX_LIST
1516
C_vv=>AllocateMatrix(); C_vv % Format=MATRIX_LIST
1517
i_aa=0; i_vv=0;
1518
DO i=1,CM % NumberOFRows
1519
IF(CM % Cols(CM % Rows(i))<=n) THEN
1520
i_vv=i_vv+1
1521
ELSE
1522
i_aa=i_aa+1
1523
END IF
1524
DO j=CM % Rows(i),CM % Rows(i+1)-1
1525
IF (CM % Values(j)==0._dp) CYCLE
1526
1527
IF (CM % Cols(j)<=n) THEN
1528
CALL AddToMatrixElement(C_vv,i_vv,CM % Cols(j),CM % Values(j))
1529
ELSE
1530
CALL AddToMatrixElement(C_aa,i_aa,CM % Cols(j)-n,CM % Values(j))
1531
END IF
1532
END DO
1533
END DO
1534
C_aa % ConstraintMatrix => Null()!B_aa % ConstraintMatrix XXXXXXX
1535
B_aa % ConstraintMatrix => C_aa
1536
1537
C_vv % ConstraintMatrix => Null()!B_vv % ConstraintMatrix YYYYYYY
1538
B_vv % ConstraintMatrix => C_vv
1539
1540
CALL List_toCRSMatrix(C_vv)
1541
CALL List_toCRSMatrix(C_aa)
1542
ALLOCATE(C_aa % Rhs(C_aa % NumberOfRows)); C_aa % Rhs=0._dp
1543
ALLOCATE(C_vv % Rhs(C_vv % NumberOfRows)); C_vv % Rhs=0._dp
1544
CM => CM % ConstraintMatrix
1545
IF(c_vv%numberofrows<=0) b_vv%constraintmatrix=>null()
1546
END DO
1547
1548
CALL Info('BlockPickMatrixAV','Finished picking block martrix!',Level=20)
1549
1550
1551
END SUBROUTINE BlockPickMatrixAV
1552
#endif
1553
1554
1555
!-------------------------------------------------------------------------------------
1556
!> Picks vertical and horizontal components of a full matrix.
1557
!-------------------------------------------------------------------------------------
1558
SUBROUTINE BlockPickMatrixHorVer( Solver, NoVar, Cart, DTag)
1559
1560
TYPE(Solver_t) :: Solver
1561
INTEGER :: Novar
1562
LOGICAL :: Cart
1563
INTEGER :: DTag(:)
1564
1565
INTEGER::i,j,k,n,t,ne,dofs,nd,ni,nn,ndir(3),ic,kc
1566
TYPE(Matrix_t), POINTER :: A,B
1567
TYPE(Nodes_t), SAVE :: Nodes, EdgeNodes
1568
INTEGER :: ActiveCoordinate
1569
INTEGER, ALLOCATABLE :: DPerm(:)
1570
INTEGER, POINTER :: Indexes(:)
1571
TYPE(Mesh_t), POINTER :: Mesh
1572
REAL(KIND=dp) :: Wlen, Wproj, Wtol, u, v, w, DetJ, Normal(3), MaxCoord, MinCoord
1573
TYPE(GaussIntegrationPoints_t) :: IP
1574
LOGICAL :: PiolaVersion, Found, Stat
1575
TYPE(Element_t), POINTER :: Element, Edge
1576
REAL(KIND=dp), POINTER :: Coord(:)
1577
1578
REAL(KIND=dp), ALLOCATABLE :: WBasis(:,:), RotWBasis(:,:)
1579
REAL(KIND=dp), ALLOCATABLE :: Basis(:), dBasisdx(:,:)
1580
1581
n = 28 ! currently just large enough
1582
ALLOCATE( WBasis(n,3), RotWBasis(n,3), Basis(n), dBasisDx(n,3), Indexes(n) )
1583
1584
1585
CALL Info('BlockPickMatrixHorVer','Dividing matrix into vertical and horizontal dofs',Level=10)
1586
1587
IF (Cart) THEN
1588
NoVar = 3
1589
ELSE
1590
NoVar = 2
1591
END IF
1592
n = MAXVAL(Solver % Variable % Perm)
1593
Mesh => Solver % Mesh
1594
1595
A => Solver % Matrix
1596
dofs = Solver % Variable % Dofs
1597
1598
n = A % NumberOfRows / dofs
1599
DTag = 0
1600
1601
PiolaVersion = ListGetLogical( Solver % Values,'Use Piola Transform', Found )
1602
ActiveCoordinate = ListGetInteger( Solver % Values,'Active Coordinate',Found )
1603
IF(.NOT. Found ) ActiveCoordinate = 3
1604
Normal = 0.0_dp
1605
Normal(ActiveCoordinate) = 1.0_dp
1606
1607
Wtol = 1.0e-3
1608
1609
1610
DO t=1,Solver % NumberOfActiveElements
1611
Element => Mesh % Elements( Solver % ActiveElements(t) )
1612
nn = Element % TYPE % NumberOfNodes
1613
1614
nd = GetElementDOFs( Indexes, Element, Solver)
1615
CALL GetElementNodes( Nodes, Element )
1616
1617
1618
! Both strategies give exactly the same set of vertical and horizontal dofs!
1619
IF( Cart ) THEN
1620
DO ActiveCoordinate = 1, 3
1621
IF( ActiveCoordinate == 1 ) THEN
1622
Coord => Nodes % x
1623
ELSE IF( ActiveCoordinate == 2 ) THEN
1624
Coord => Nodes % y
1625
ELSE
1626
Coord => Nodes % z
1627
END IF
1628
1629
MinCoord = MINVAL( Coord(1:nn) )
1630
MaxCoord = MAXVAL( Coord(1:nn) )
1631
Wlen = MaxCoord - MinCoord
1632
1633
DO i=1,nd
1634
j = Solver % Variable % Perm(Indexes(i))
1635
1636
IF( i <= Element % TYPE % NumberOfEdges ) THEN
1637
Edge => Mesh % Edges( Element % EdgeIndexes(i) )
1638
CALL GetElementNodes( EdgeNodes, Edge )
1639
ne = Edge % TYPE % NumberOfNodes
1640
1641
IF( ActiveCoordinate == 1 ) THEN
1642
Coord => EdgeNodes % x
1643
ELSE IF( ActiveCoordinate == 2 ) THEN
1644
Coord => EdgeNodes % y
1645
ELSE
1646
Coord => EdgeNodes % z
1647
END IF
1648
1649
MinCoord = MINVAL( Coord(1:ne) )
1650
MaxCoord = MAXVAL( Coord(1:ne) )
1651
ELSE
1652
CALL Fatal('BlockPickMatrixHorVer','Cannot do faces yet!')
1653
END IF
1654
1655
Wproj = ( MaxCoord - MinCoord ) / Wlen
1656
1657
IF( WProj > 1.0_dp - Wtol ) DTag(j) = ActiveCoordinate
1658
END DO
1659
END DO
1660
1661
ELSE IF(.TRUE.) THEN
1662
IF( ActiveCoordinate == 1 ) THEN
1663
Coord => Nodes % x
1664
ELSE IF( ActiveCoordinate == 2 ) THEN
1665
Coord => Nodes % y
1666
ELSE
1667
Coord => Nodes % z
1668
END IF
1669
1670
MinCoord = MINVAL( Coord(1:nn) )
1671
MaxCoord = MAXVAL( Coord(1:nn) )
1672
Wlen = MaxCoord - MinCoord
1673
1674
DO i=1,nd
1675
j = Solver % Variable % Perm(Indexes(i))
1676
1677
IF( i <= Element % Type % NumberOfEdges ) THEN
1678
Edge => Mesh % Edges( Element % EdgeIndexes(i) )
1679
CALL GetElementNodes( EdgeNodes, Edge )
1680
ne = Edge % Type % NumberOfNodes
1681
1682
IF( Indexes(i) /= Mesh % NumberOfNodes + Element % EdgeIndexes(i) ) THEN
1683
PRINT *,'ind com:',Indexes(i), Mesh % NumberOfNodes + Element % EdgeIndexes(i), &
1684
Mesh % NumberOfNodes
1685
END IF
1686
1687
IF( ActiveCoordinate == 1 ) THEN
1688
Coord => EdgeNodes % x
1689
ELSE IF( ActiveCoordinate == 2 ) THEN
1690
Coord => EdgeNodes % y
1691
ELSE
1692
Coord => EdgeNodes % z
1693
END IF
1694
1695
MinCoord = MINVAL( Coord(1:ne) )
1696
MaxCoord = MAXVAL( Coord(1:ne) )
1697
ELSE
1698
! jj = 2 * ( Element % ElementIndex - 1) + ( i - noedges )
1699
CALL Fatal('BlockPickMatrixHorVer','Cannot do faces yet!')
1700
END IF
1701
1702
Wproj = ( MaxCoord - MinCoord ) / Wlen
1703
1704
IF( WProj > 1.0_dp - Wtol ) THEN
1705
IF( dofs == 1 ) THEN
1706
DTag(j) = 1
1707
ELSE
1708
DTag(2*j-1) = 1
1709
DTag(2*j) = 1
1710
END IF
1711
ELSE IF( Wproj < Wtol ) THEN
1712
IF( dofs == 1 ) THEN
1713
DTag(j) = 2
1714
ELSE
1715
DTag(2*j-1) = 2
1716
DTag(2*j) = 2
1717
END IF
1718
END IF
1719
END DO
1720
1721
ELSE
1722
IP = GaussPoints(Element, EdgeBasis=.TRUE., PReferenceElement=PiolaVersion)
1723
1724
u = SUM( IP % u ) / IP % n
1725
v = SUM( IP % v ) / IP % n
1726
w = IP % w(k)
1727
1728
IF (PiolaVersion) THEN
1729
stat = EdgeElementInfo( Element, Nodes, u, v, w, &
1730
DetF = DetJ, Basis = Basis, EdgeBasis = WBasis, &
1731
RotBasis = RotWBasis, dBasisdx = dBasisdx, &
1732
ApplyPiolaTransform = .TRUE.)
1733
ELSE
1734
stat = ElementInfo( Element, Nodes, u, v, w, &
1735
detJ, Basis, dBasisdx )
1736
CALL GetEdgeBasis(Element, WBasis, RotWBasis, Basis, dBasisdx)
1737
END IF
1738
1739
DO i=1,nd
1740
j = Solver % Variable % Perm(Indexes(i))
1741
Wlen = SQRT( SUM( WBasis(i,:)**2 ) )
1742
IF( Wlen < EPSILON( Wlen ) ) CYCLE
1743
1744
Wproj = ABS( SUM( WBasis(i,:) * Normal ) ) / Wlen
1745
1746
IF( WProj > 1.0_dp - Wtol ) THEN
1747
!IF( DTag(j) == 2 ) PRINT *,'Vertical edge '//I2S(j)//' is also horizontal?'
1748
IF( dofs == 1 ) THEN
1749
DTag(j) = 1 ! set to be vertical
1750
ELSE
1751
DTag(2*j-1) = 1 ! set to be vertical
1752
DTag(2*j) = 1 ! set to be vertical
1753
END IF
1754
ELSE IF( Wproj < Wtol ) THEN
1755
!IF( DTag(j) == 1 ) PRINT *,'Horizontal edge '//I2S(j)//' is also vertical?'
1756
IF( dofs == 1 ) THEN
1757
DTag(j) = 2 ! set to be horizontal
1758
ELSE
1759
DTag(2*j-1) = 2 ! set to be horizontal
1760
DTag(2*j) = 2 ! set to be horizontal
1761
END IF
1762
ELSE
1763
PRINT *,'Edge '//I2S(j)//' direction undefined: ',Wproj
1764
END IF
1765
END DO
1766
1767
END IF
1768
END DO
1769
1770
IF( InfoActive(20) ) THEN
1771
DO i=1,NoVar
1772
j = COUNT(DTag==i)
1773
CALL Info('BlockPickMatrixHorVer','There are '//I2S(j)//' dofs group '//I2S(i))
1774
END DO
1775
END IF
1776
1777
END SUBROUTINE BlockPickMatrixHorVer
1778
1779
1780
!-------------------------------------------------------------------------------------
1781
!> Makes a quadratic H(curl) approximation to have a block structure
1782
!-------------------------------------------------------------------------------------
1783
SUBROUTINE BlockPickMatrixHcurl( Solver, NoVar, DoCmplx, BlockTag )
1784
1785
TYPE(Solver_t) :: Solver
1786
INTEGER :: Novar
1787
LOGICAL :: DoCmplx
1788
INTEGER :: BlockTag(:)
1789
1790
INTEGER :: i,j,k,n,m,n0,dofs,ic,kc
1791
TYPE(Matrix_t), POINTER :: A,B
1792
TYPE(Mesh_t), POINTER :: Mesh
1793
TYPE(Element_t), POINTER :: Element, Edge
1794
LOGICAL :: Found
1795
1796
Mesh => Solver % Mesh
1797
1798
IF(.NOT. ASSOCIATED( Mesh % Edges ) ) THEN
1799
CALL Fatal('BlockPickMatrixHcurl','This subroutine needs Edges!')
1800
END IF
1801
IF(.NOT. ASSOCIATED( Mesh % Faces ) ) THEN
1802
CALL Fatal('BlockPickMatrixHcurl','This subroutine needs Faces!')
1803
END IF
1804
CALL Info('BlockPickMatrixHcurl','Arranging a quadratic H(curl) approximation into blocks',Level=10)
1805
1806
NoVar = 2
1807
IF( ListGetLogical( Solver % Values,'Block Quadratic Hcurl Faces',Found ) ) NoVar = 3
1808
IF(DoCmplx) THEN
1809
NoVar = 2 * NoVar
1810
IF( ListGetLogical( Solver % Values,'Block Quadratic Hcurl semicomplex',Found ) ) NoVar = 3
1811
END IF
1812
1813
1814
A => Solver % Matrix
1815
dofs = Solver % Variable % Dofs
1816
1817
m = A % NumberOfRows
1818
n = m
1819
1820
! Set the default blocks
1821
IF( DoCmplx ) THEN
1822
! Synopsis: the tags of (4x4) block structure
1823
! - Re, lowest-order = 1
1824
! - Im, lowest-order = 2
1825
! - Re, higher-order = 3
1826
! - Im, higher-order = 4
1827
! while (3x3) structure corresponds to
1828
! - Re and Im, lowest-order = 1
1829
! - Re, higher-order = 2
1830
! - Im, higher-order = 3
1831
BlockTag(1::2) = 3
1832
BlockTag(2::2) = 4
1833
ELSE
1834
! Synopsis:
1835
! - lowest-order = 1
1836
! - higher-order = 2
1837
! - higher-order DOFs which are not associated with edges = 3 (optional)
1838
BlockTag = 2
1839
END IF
1840
1841
n0 = Mesh % NumberOfNodes
1842
DO i=1, Mesh % NumberOfEdges
1843
! This corresponds to the lowest-order DOF over an edge
1844
j = n0 + 2*i-1
1845
k = Solver % Variable % Perm(j)
1846
IF(k==0) CYCLE
1847
1848
! If BlockTag array were created for all DOFs with DOFs>1,
1849
! it would have a repeated entries occuring in clusters of
1850
! size DOFs. Therefore a smaller array can be used to tag DOFs.
1851
IF( dofs == 1 ) THEN
1852
BlockTag(k) = 1
1853
ELSE IF(dofs == 2 ) THEN
1854
BlockTag(2*k-1) = 1
1855
IF( DoCmplx ) THEN
1856
BlockTag(2*k) = 2
1857
ELSE
1858
BlockTag(2*k) = 1
1859
END IF
1860
END IF
1861
END DO
1862
1863
IF(NoVar == 3) THEN
1864
IF( DoCmplx ) THEN
1865
WHERE( BlockTag > 1 )
1866
BlockTag = BlockTag - 1
1867
END WHERE
1868
ELSE
1869
DO j = n0 + 2*Mesh % NumberOfEdges + 1, SIZE(Solver % Variable % Perm)
1870
k = Solver % Variable % Perm(j)
1871
IF(k==0) CYCLE
1872
1873
IF(dofs == 1 ) THEN
1874
BlockTag(k) = 3
1875
ELSE IF( dofs == 2 ) THEN
1876
BlockTag(2*k-1) = 3
1877
BlockTag(2*k) = 3
1878
END IF
1879
END DO
1880
END IF
1881
END IF
1882
1883
IF( InfoActive(20) ) THEN
1884
DO i=1,NoVar
1885
j = COUNT(BlockTag==i)
1886
CALL Info('BlockMatrixHCurl','There are '//I2S(j)//' dofs group '//I2S(i))
1887
END DO
1888
END IF
1889
1890
END SUBROUTINE BlockPickMatrixHcurl
1891
1892
1893
1894
!-------------------------------------------------------------------------------------
1895
!> Picks apart nodal and non-nodal dofs.
1896
!-------------------------------------------------------------------------------------
1897
SUBROUTINE BlockPickMatrixNodal( Solver, NoVar, DoCmplx, BlockTag )
1898
1899
TYPE(Solver_t) :: Solver
1900
INTEGER :: Novar
1901
LOGICAL :: DoCmplx
1902
INTEGER :: BlockTag(:)
1903
1904
INTEGER :: i,j,k,n,dofs
1905
TYPE(Matrix_t), POINTER :: A
1906
TYPE(Mesh_t), POINTER :: Mesh
1907
LOGICAL :: Found
1908
1909
Mesh => Solver % Mesh
1910
1911
CALL Info('BlockPickMatrixNodal','Separates nodal and non-nodal dofs from each other',Level=10)
1912
1913
NoVar = 2
1914
IF(DoCmplx) NoVar = 2 * NoVar
1915
1916
A => Solver % Matrix
1917
dofs = Solver % Variable % Dofs
1918
1919
IF( DoCmplx ) THEN
1920
BlockTag(1::2) = 3
1921
BlockTag(2::2) = 4
1922
ELSE
1923
BlockTag = 2
1924
END IF
1925
1926
DO i=1, Mesh % NumberOfNodes
1927
k = Solver % Variable % Perm(j)
1928
IF(k==0) CYCLE
1929
1930
IF( dofs == 1 ) THEN
1931
BlockTag(k) = 1
1932
ELSE IF(dofs == 2 ) THEN
1933
BlockTag(2*k-1) = 1
1934
IF( DoCmplx ) THEN
1935
BlockTag(2*k) = 2
1936
ELSE
1937
BlockTag(2*k) = 1
1938
END IF
1939
END IF
1940
END DO
1941
1942
IF( InfoActive(20) ) THEN
1943
DO i=1,NoVar
1944
j = COUNT(BlockTag==i)
1945
CALL Info('BlockMatrixNodal','There are '//I2S(j)//' dofs group '//I2S(i))
1946
END DO
1947
END IF
1948
1949
END SUBROUTINE BlockPickMatrixNodal
1950
1951
1952
1953
!-------------------------------------------------------------------------------------
1954
!> Picks the components of the constraint matrix.
1955
!-------------------------------------------------------------------------------------
1956
SUBROUTINE BlockPickConstraint( Solver, NoVar, SkipPrec )
1957
1958
TYPE(Solver_t), TARGET :: Solver
1959
INTEGER :: Novar
1960
LOGICAL :: SkipPrec
1961
1962
INTEGER :: RowVar, ColVar
1963
TYPE(Matrix_t), POINTER :: SolverMatrix
1964
TYPE(Matrix_t), POINTER :: Amat
1965
TYPE(ValueList_t), POINTER :: Params
1966
LOGICAL :: Found
1967
1968
LOGICAL :: BlockAV
1969
INTEGER::i,j,k,l,n,i1,i2,i3,rowi,colj,NoCon,rb,cb
1970
TYPE(Matrix_t), POINTER :: A,CM,C1,C2,C3,C1prec,C2prec,C3prec,Tmat
1971
REAL(KIND=dp) :: PrecCoeff,val
1972
INTEGER, POINTER :: ConsPerm(:), ConsPerm2(:)
1973
INTEGER :: DoPrec
1974
CHARACTER(:), ALLOCATABLE :: VarName
1975
TYPE(Variable_t), POINTER :: Var
1976
TYPE(Solver_t), POINTER :: PSolver
1977
LOGICAL :: InheritCM, PrecTrue
1978
1979
LOGICAL, ALLOCATABLE :: vflag(:)
1980
1981
INTEGER, ALLOCATABLE :: REdgePerm(:), RNodePerm(:), BlockNumbering(:), InvPerm(:)
1982
1983
CALL Info('BlockPickConstraint','Picking constraints to block matrix',Level=10)
1984
1985
1986
SolverMatrix => Solver % Matrix
1987
Params => Solver % Values
1988
BlockAV = ListGetLogical( Params,'Block A-V System', Found)
1989
BlockAV = BlockAV .OR. ListGetLogical( Params,'Block A-V System Old', Found)
1990
1991
A => SolverMatrix
1992
n = Solver % Mesh % NumberOfNodes
1993
1994
PrecCoeff = ListGetConstReal( Params,'Block Diag Coeff',Found)
1995
1996
IF(.NOT. Found ) PrecCoeff = 1.0_dp
1997
1998
PrecTrue = ListGetLogical( Params,'Block Diag True',Found )
1999
2000
2001
! temporarily be generic
2002
NoCon = 0
2003
CM => A % ConstraintMatrix
2004
DO WHILE(ASSOCIATED(CM))
2005
NoCon = NoCon + 1
2006
CM => CM % ConstraintMatrix
2007
END DO
2008
2009
CALL Info('BlockPickConstraint','Number of constraint matrices: '//I2S(NoCon),Level=10)
2010
2011
InheritCM = (NoVar == 1 ) .AND. (NoCon == 1 )
2012
IF( InheritCM ) THEN
2013
CALL info('BlockPickConstraint','Inheriting constraint matrix',Level=20)
2014
END IF
2015
2016
2017
IF( NoVar == 1 ) THEN
2018
IF( InheritCM ) THEN
2019
C1 => A % ConstraintMatrix
2020
TotMatrix % Submatrix(NoVar+1,1) % Mat => A % ConstraintMatrix
2021
CALL Info('BlockPickConstraint',&
2022
'Using constraint matrix ('//I2S(NoVar+1)//',1) as is!',Level=10)
2023
i = A % ConstraintMatrix % NumberOfRows
2024
CALL Info('BlockPickConstraint','Number of rows in matrix: '//I2S(i),Level=20)
2025
IF( PrecTrue ) THEN
2026
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % Mat
2027
ELSE
2028
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % PrecMat
2029
END IF
2030
ELSE
2031
C1 => TotMatrix % Submatrix(NoVar+1,1) % Mat
2032
IF( PrecTrue ) THEN
2033
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % Mat
2034
ELSE
2035
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % PrecMat
2036
END IF
2037
END IF
2038
2039
ELSE IF(BlockAV) THEN
2040
IF( PrecTrue ) THEN
2041
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % Mat
2042
C2prec => TotMatrix % Submatrix(NoVar+2,NoVar+2) % Mat
2043
ELSE
2044
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % PrecMat
2045
C2prec => TotMatrix % Submatrix(NoVar+2,NoVar+2) % PrecMat
2046
END IF
2047
C1 => TotMatrix % SubMatrix(NoVar+1,1) % Mat
2048
C2 => TotMatrix % SubMatrix(NoVar+2,2) % Mat
2049
ELSE
2050
CALL Fatal('BlockPickConstraint','Not done for vectors!')
2051
END IF
2052
2053
CM => A % ConstraintMatrix
2054
n = Solver % Mesh % NumberOfNodes
2055
DO WHILE(ASSOCIATED(CM))
2056
IF(.NOT.BlockAV ) n = MAX( n, MAXVAL(MOD(CM % InvPerm-1,A % NumberOfRows)+1) )
2057
CM => CM % ConstraintMatrix
2058
END DO
2059
CM => A % ConstraintMatrix
2060
2061
ALLOCATE( ConsPerm( A % NumberOfRows) )
2062
ConsPerm = 0;
2063
IF ( BlockAV ) THEN
2064
ALLOCATE( ConsPerm2(A % NumberofRows) )
2065
ConsPerm2 = 0
2066
END IF
2067
2068
IF ( BlockAV ) THEN
2069
ALLOCATE( InvPerm(MAXVAL(Solver % Variable % Perm)))
2070
InvPerm = 0
2071
DO i=1,SIZE(Solver % Variable % Perm)
2072
j = Solver % Variable % Perm(i)
2073
IF ( j>0 ) InvPerm(j) = i
2074
END DO
2075
2076
j = CM % NumberOfRows
2077
ALLOCATE( rEdgePerm(j), rNodePerm(j) )
2078
rEdgePerm = 0
2079
rNodePerm = 0
2080
i1 = 0
2081
i2 = 0
2082
DO i=1,CM % NumberOFRows
2083
j = CM % InvPerm(i)
2084
j = MOD(j-1,A % NumberOfRows)+1
2085
j = InvPerm(j)
2086
IF ( j > n ) THEN
2087
i2 = i2+1
2088
rEdgePerm(i) = i2
2089
ELSE IF ( j>0 .AND. j <= n ) THEN
2090
i1 = i1 +1
2091
rNodePerm(i) = i1
2092
ELSE
2093
stop 'cm invperm'
2094
END IF
2095
END DO
2096
! print*, 'edges: ', i2, 'nodes: ', i1, cm % numberofrows
2097
END IF
2098
2099
j = Solver % Matrix % NumberOfRows
2100
ALLOCATE( vFlag(j), BlockNumbering(j) )
2101
IF (BlockAV) THEN
2102
i1 = 0; i2 = 0
2103
k = SIZE(Solver % Variable % Perm)
2104
DO i=1,k
2105
j = Solver % variable % Perm(i)
2106
IF ( j<= 0 ) CYCLE
2107
vFlag(j) = i <= n
2108
END DO
2109
ELSE
2110
vFlag = .TRUE.
2111
END IF
2112
! print*, 'edges: ', COUNT(.NOT. vFlag), 'nodes: ', COUNT(vFlag), solver % matrix % numberofrows
2113
2114
2115
k = Solver % Matrix % NumberOfRows
2116
i1 = 0; i2=0
2117
BlockNumbering = 0
2118
DO i=1,k
2119
IF ( vFlag(i) ) THEN
2120
i1 = i1 + 1
2121
BlockNumbering(i) = i1
2122
ELSE
2123
i2 = i2 + 1
2124
BlockNumbering(i) = i2
2125
END IF
2126
END DO
2127
2128
IF ( .NOT. InheritCM ) THEN
2129
IF ( C1 % Format == MATRIX_CRS ) THEN
2130
C1 % Values = 0
2131
IF ( ASSOCIATED(C1prec) ) THEN
2132
IF ( ASSOCIATED(C1prec % Values) ) C1prec % Values = 0
2133
END IF
2134
END IF
2135
2136
IF ( BlockAV ) THEN
2137
IF ( C2 % Format == MATRIX_CRS ) THEN
2138
C2 % Values = 0
2139
IF ( ASSOCIATED(C2prec) ) THEN
2140
IF ( ASSOCIATED(C2prec % Values) ) C2prec % Values = 0
2141
END IF
2142
END IF
2143
END IF
2144
END IF
2145
2146
DO DoPrec = 0, 1
2147
IF( DoPrec == 1 .AND. SkipPrec ) CYCLE
2148
2149
i1 = 0
2150
i2 = 0
2151
2152
CM => A % ConstraintMatrix
2153
DO WHILE(ASSOCIATED(CM))
2154
2155
DO i=1,CM % NumberOFRows
2156
2157
rowi = MOD(CM % InvPerm(i)-1, A % NumberOfRows)+1
2158
2159
rb = 1
2160
i1 = i1 + 1
2161
IF( BlockAV ) THEN
2162
IF( rEdgePerm(i)>0 ) rb = 2
2163
IF( rb == 1 ) THEN
2164
i1 = rNodePerm(i)
2165
ELSE
2166
i2 = rEdgePerm(i)
2167
END IF
2168
END IF
2169
2170
! First round initialize the ConsPerm
2171
IF( DoPrec == 0 ) THEN
2172
IF ( rb == 1 ) THEN
2173
ConsPerm(rowi) = i1
2174
ELSE
2175
ConsPerm2(rowi) = i2
2176
END IF
2177
END IF
2178
2179
DO j=CM % Rows(i),CM % Rows(i+1)-1
2180
IF (CM % Values(j)==0._dp) CYCLE
2181
2182
colj = CM % Cols(j)
2183
cb = 1
2184
IF( BlockAV ) THEN
2185
IF( .NOT. vFlag(colj) ) cb = 2
2186
END IF
2187
colj = BlockNumbering(colj)
2188
2189
val = CM % Values(j)
2190
2191
IF( DoPrec == 1 ) THEN
2192
IF( ConsPerm( colj ) > 0 ) THEN
2193
! The sign -1 is needed for consistency
2194
val = -PrecCoeff * val
2195
IF ( cb == 1 ) THEN
2196
CALL AddToMatrixElement(C1prec,i1,ConsPerm(colj),val)
2197
ELSE
2198
CALL AddToMatrixElement(C2prec,i2,ConsPerm2(colj),val)
2199
END IF
2200
END IF
2201
ELSE IF( .NOT. InheritCM ) THEN
2202
IF ( cb == 1 ) THEN
2203
CALL AddToMatrixElement(C1,i1,colj,val)
2204
ELSE
2205
CALL AddToMatrixElement(C2,i2,colj,val)
2206
END IF
2207
END IF
2208
END DO
2209
END DO
2210
2211
CM => CM % ConstraintMatrix
2212
END DO
2213
2214
! It is more efficient to set the last entry of the list matrix first
2215
#if 0
2216
IF( DoPrec == 0 .AND. .NOT. SkipPrec ) THEN
2217
CALL AddToMatrixElement(C1prec,i1,i1,0.0_dp)
2218
END IF
2219
#endif
2220
END DO
2221
2222
CALL Info('BlockPickConstraint','Setting format of constraint blocks to CRS',Level=20)
2223
IF(.NOT. InheritCM ) THEN
2224
CALL List_toCRSMatrix(C1)
2225
END IF
2226
IF(.NOT. SkipPrec ) CALL List_toCRSMatrix(C1prec)
2227
2228
IF( BlockAV ) THEN
2229
CALL List_toCRSMatrix(C2)
2230
IF(.NOT. SkipPrec) CALL List_toCRSMatrix(C2prec)
2231
END IF
2232
2233
IF( ListGetLogical( Solver % Values,'Save Prec Matrix', Found ) ) THEN
2234
CALL SaveProjector(C1prec,.TRUE.,"CM")
2235
END IF
2236
2237
VarName = "lambda_n"
2238
Var => VariableGet( Solver % Mesh % Variables, VarName )
2239
IF(ASSOCIATED( Var ) ) THEN
2240
n = SIZE( Var % Values )
2241
DEALLOCATE(ConsPerm)
2242
CALL Info('BlockPickConstraint','Using existing variable > '//VarName//' <')
2243
ELSE
2244
CALL Info('BlockPickConstraint','Variable > '//VarName//' < does not exist, creating')
2245
n = MAXVAL(ConsPerm)
2246
PSolver => Solver
2247
Var => CreateBlockVariable(PSolver, NoVar+1, VarName, 1, ConsPerm )
2248
END IF
2249
2250
TotMatrix % SubVector(NoVar+1) % Var => Var
2251
TotMatrix % Offset(NoVar+2) = TotMatrix % Offset(NoVar+1) + n
2252
TotMatrix % MaxSize = MAX( TotMatrix % MaxSize, n )
2253
TotMatrix % TotSize = TotMatrix % TotSize + n
2254
2255
TotMatrix % SubMatrix(NoVar+1,1) % Mat => C1
2256
2257
Tmat => TotMatrix % SubMatrix(1,NoVar+1) % Mat
2258
IF ( ASSOCIATED(Tmat) ) CALL FreeMatrix(Tmat)
2259
TotMatrix % SubMatrix(1,NoVar+1) % Mat => CRS_Transpose(C1)
2260
2261
TotMatrix % SubMatrix(1,NoVar+1) % ParallelIsolatedMatrix = &
2262
TotMatrix % SubMatrix(NoVar+1,1) % ParallelIsolatedMatrix
2263
2264
IF ( BlockAV ) THEN
2265
VarName = "lambda_a"
2266
Var => VariableGet( Solver % Mesh % Variables, VarName )
2267
IF(ASSOCIATED( Var ) ) THEN
2268
n = SIZE( Var % Values )
2269
DEALLOCATE(ConsPerm2)
2270
CALL Info('BlockPickConstraint','Using existing variable > '//VarName//' <')
2271
ELSE
2272
CALL Info('BlockPickConstraint','Variable > '//VarName//' < does not exist, creating')
2273
n = MAXVAL(ConsPerm2)
2274
Var => CreateBlockVariable(PSolver, NoVar+2, VarName, 1, ConsPerm2 )
2275
END IF
2276
2277
TotMatrix % SubVector(NoVar+2) % Var => Var
2278
TotMatrix % Offset(NoVar+3) = TotMatrix % Offset(NoVar+2) + n
2279
TotMatrix % MaxSize = MAX( TotMatrix % MaxSize, n )
2280
TotMatrix % TotSize = TotMatrix % TotSize + n
2281
2282
TotMatrix % SubMatrix(NoVar+2,2) % Mat => C2
2283
2284
Tmat => TotMatrix % SubMatrix(2,NoVar+2) % Mat
2285
IF ( ASSOCIATED(Tmat) ) CALL FreeMatrix(Tmat)
2286
TotMatrix % SubMatrix(2,NoVar+2) % Mat => CRS_Transpose(C2)
2287
2288
TotMatrix % SubMatrixActive(2,NoVar+2) = .TRUE.
2289
TotMatrix % SubMatrixActive(NoVar+2,2) = .TRUE.
2290
2291
TotMatrix % SubMatrix(2,NoVar+2) % ParallelIsolatedMatrix = &
2292
TotMatrix % SubMatrix(NoVar+2,2) % ParallelIsolatedMatrix
2293
END IF
2294
2295
END SUBROUTINE BlockPickConstraint
2296
2297
2298
2299
!-------------------------------------------------------------------------------------
2300
!> The block preconditioning matrix need not be directly derived from the full
2301
!> matrix. Some or all the components may also be derived from a basic operator
2302
!> such as the Laplacian.
2303
!-------------------------------------------------------------------------------------
2304
SUBROUTINE BlockPrecMatrix( Solver, NoVar )
2305
2306
TYPE(Solver_t) :: Solver
2307
INTEGER :: Novar
2308
2309
INTEGER :: i, RowVar, ColVar, CopyVar
2310
CHARACTER(:), ALLOCATABLE :: str
2311
REAL(KIND=dp) :: Coeff, Coeff0
2312
LOGICAL :: GotIt, GotIt2, DoIt
2313
INTEGER, POINTER :: VarPerm(:)
2314
TYPE(ValueList_t), POINTER :: Params
2315
TYPE(Matrix_t), POINTER :: Amat, PMat
2316
TYPE(Variable_t), POINTER :: AVar
2317
LOGICAL :: SplitComplexHcurl
2318
2319
CALL Info('BlockPrecMatrix','Checking for tailored preconditioning matrices',Level=6)
2320
2321
Params => Solver % Values
2322
SplitComplexHcurl = ListGetLogical( Params,'Block Split Complex Hcurl', GotIt )
2323
2324
! The user may give a user defined preconditioner matrix
2325
!-----------------------------------------------------------
2326
DO RowVar=1,NoVar
2327
i = TotMatrix % Submatrix(RowVar,RowVar) % PrecMat % NumberOfRows
2328
2329
IF( i > 0 ) CYCLE
2330
2331
str = 'Prec Matrix Diffusion '//I2S(RowVar)
2332
Coeff = ListGetCReal( Params, str, GotIt)
2333
2334
str = 'Prec Matrix Density '//I2S(RowVar)
2335
Coeff = ListGetCReal( Params, str, GotIt2)
2336
2337
IF( GotIt .OR. GotIt2 ) THEN
2338
CALL CRS_CopyMatrixTopology( TotMatrix % Submatrix(RowVar,RowVar) % Mat, &
2339
TotMatrix % Submatrix(RowVar,RowVar) % PrecMat )
2340
2341
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
2342
VarPerm => TotMatrix % Subvector(RowVar) % Var % Perm
2343
IF( GotIt ) THEN
2344
CALL Info('BlockPrecMatrix','Creating simple preconditioning Laplace matrix',Level=8)
2345
CALL LaplaceMatrixAssembly( Solver, VarPerm, Amat )
2346
Amat % Values = Coeff * Amat % Values
2347
ELSE
2348
CALL Info('BlockPrecMatrix','Creating simple preconditioning mass matrix',Level=8)
2349
CALL MassMatrixAssembly( Solver, VarPerm, Amat )
2350
Amat % Values = Coeff * Amat % Values
2351
END IF
2352
Amat % ParallelInfo => TotMatrix % Submatrix(RowVar,RowVar) % Mat % ParallelInfo
2353
END IF
2354
2355
str = 'Prec Matrix Complex Coeff '//I2S(RowVar)
2356
Coeff = ListGetCReal( Params, str, GotIt )
2357
2358
IF(.NOT. GotIt) THEN
2359
str = 'Prec Matrix Complex Coeff'
2360
Coeff = ListGetCReal( Params, str, GotIt )
2361
END IF
2362
2363
IF(.NOT. GotIt) THEN
2364
GotIt = ListGetLogical( Params,'Block Split Complex', GotIt )
2365
Coeff = 1.0_dp
2366
END IF
2367
Coeff0 = Coeff
2368
2369
IF( GotIt ) THEN
2370
IF(ASSOCIATED(Solver % Matrix % PrecValues) ) THEN
2371
CALL Info('BlockPermMatrix','Skipping adding off-diagonal prec values!')
2372
GotIt = .FALSE.
2373
END IF
2374
END IF
2375
2376
IF(GotIt) THEN
2377
CALL Info('BlockPrecMatrix','Creating preconditioning matrix from block sums',Level=8)
2378
2379
IF( SplitComplexHcurl ) THEN
2380
! This is a special case where only the A matrix is split to [Re,Im] parts.
2381
IF( RowVar == 2 ) THEN
2382
ColVar = RowVar + 1
2383
Coeff = Coeff0
2384
ELSE IF( RowVar == 3 ) THEN
2385
ColVar = RowVar - 1
2386
Coeff = -Coeff0
2387
ELSE
2388
CYCLE
2389
END IF
2390
ELSE
2391
! Here all the block matrices are split.
2392
IF( MODULO(NoVar,2) /= 0) THEN
2393
CALL Fatal('BlockPrecMatrix','Assuming even number of blocks for the complex preconditioner!')
2394
END IF
2395
IF( MODULO(RowVar,2) == 1 ) THEN
2396
ColVar = RowVar + 1
2397
Coeff = Coeff0
2398
ELSE
2399
ColVar = RowVar - 1
2400
Coeff = -Coeff0
2401
END IF
2402
END IF
2403
2404
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
2405
IF(Amat % NumberOfRows == 0 ) THEN
2406
CALL CRS_CopyMatrixTopology( TotMatrix % Submatrix(RowVar,RowVar) % Mat, &
2407
TotMatrix % Submatrix(RowVar,RowVar) % PrecMat )
2408
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
2409
END IF
2410
IF( ASSOCIATED( TotMatrix % Submatrix(RowVar,RowVar) % Mat % PrecValues ) ) THEN
2411
AMat % Values = TotMatrix % Submatrix(RowVar,RowVar) % Mat % PrecValues
2412
DEALLOCATE( TotMatrix % Submatrix(RowVar,RowVar) % Mat % PrecValues )
2413
ELSE
2414
AMat % Values = TotMatrix % Submatrix(RowVar,RowVar) % Mat % Values
2415
END IF
2416
2417
IF( SIZE( Amat % Values ) /= SIZE( TotMatrix % Submatrix(RowVar,ColVar) % Mat % Values ) ) THEN
2418
CALL Fatal('BlockPrecMatrix','Mismatch in matrix size for block: '//I2S(10*RowVar+ColVar))
2419
END IF
2420
2421
AMat % Values = Amat % Values + &
2422
Coeff * TotMatrix % Submatrix(RowVar,ColVar) % Mat % Values
2423
END IF
2424
2425
str = 'Prec Matrix Diagonal '//I2S(RowVar)
2426
Coeff = ListGetCReal( Params, str, GotIt)
2427
IF( GotIt ) THEN
2428
CopyVar = NoVar+1 - RowVar
2429
PMat => TotMatrix % Submatrix(RowVar,CopyVar) % Mat
2430
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
2431
CALL Info('BlockPrecMatrix','Creating preconditioner from matrix ('&
2432
//I2S(RowVar)//','//I2S(CopyVar)//')',Level=6)
2433
2434
CALL DiagonalMatrixSumming( Solver, PMat, Amat )
2435
Amat % Values = Coeff * Amat % Values
2436
END IF
2437
END DO
2438
2439
IF( ListGetLogical( Params,'Create Schur Matrix Approximation',GotIt ) ) THEN
2440
CALL Info('BlockPrecMatrix','Generating block '//I2S(11*NoVar),Level=7)
2441
IF(NoVar == 1) THEN
2442
CALL Fatal('BlockPrecMatrix','We should have more than one block')
2443
END IF
2444
IF ( NoVar == 4 ) THEN
2445
Pmat => TotMatrix % Submatrix(3,3) % PrecMat
2446
IF ( ASSOCIATED(Pmat) ) CALL FreeMatrix(Pmat)
2447
2448
Pmat => TotMatrix % Submatrix(4,4) % PrecMat
2449
IF ( ASSOCIATED(Pmat) ) CALL FreeMatrix(Pmat)
2450
2451
Pmat => CreateSchurApproximation( &
2452
TotMatrix % Submatrix(1,1) % Mat, &
2453
TotMatrix % Submatrix(3,1) % Mat, &
2454
TotMatrix % Submatrix(1,3) % Mat )
2455
TotMatrix % Submatrix(3,3) % PrecMat => Pmat
2456
2457
Pmat => CreateSchurApproximation( &
2458
TotMatrix % Submatrix(2,2) % Mat, &
2459
TotMatrix % Submatrix(4,2) % Mat, &
2460
TotMatrix % Submatrix(2,4) % Mat )
2461
TotMatrix % Submatrix(4,4) % PrecMat => Pmat
2462
ELSE
2463
Pmat => TotMatrix % Submatrix(2,2) % PrecMat
2464
IF ( ASSOCIATED(Pmat) ) CALL FreeMatrix(Pmat)
2465
2466
Pmat => CreateSchurApproximation( &
2467
TotMatrix % Submatrix(1,1) % Mat, &
2468
TotMatrix % Submatrix(2,1) % Mat, &
2469
TotMatrix % Submatrix(1,2) % Mat )
2470
TotMatrix % Submatrix(2,2) % PrecMat => Pmat
2471
END IF
2472
NULLIFY(Pmat)
2473
END IF
2474
2475
2476
str = ListGetString( Params,'Block Matrix Schur Variable', GotIt)
2477
IF( GotIt ) THEN
2478
AVAr => VariableGet( Solver % Mesh % Variables, str )
2479
IF( .NOT. ASSOCIATED( AVar ) ) THEN
2480
CALL Fatal('BlockPrecMatrix','Schur variable does not exist: '//str)
2481
END IF
2482
IF( .NOT. ASSOCIATED( AVar % Solver ) ) THEN
2483
CALL Fatal('BlockPrecMatrix','Schur solver does not exist for: '//str)
2484
END IF
2485
IF( .NOT. ASSOCIATED( AVar % Solver % Matrix ) ) THEN
2486
CALL Fatal('BlockPrecMatrix','Schur matrix does not exist for: '//str)
2487
END IF
2488
CALL Info('BlockPrecMatrix','Using Schur matrix to precondition block '//I2S(NoVar))
2489
TotMatrix % Submatrix(NoVar,NoVar) % PrecMat => AVar % Solver % Matrix
2490
END IF
2491
2492
2493
! When we have an inner-outer iteration, we could well have a different matrix
2494
! assembled for the purpose of preconditioning. Use it here, if available.
2495
IF(ListGetLogical( Params,'Block Nested System',GotIt ) ) THEN
2496
Amat => TotMatrix % Submatrix(1,1) % Mat
2497
IF( ASSOCIATED( Amat % PrecValues ) ) THEN
2498
PMat => TotMatrix % Submatrix(1,1) % PrecMat
2499
IF (.NOT. ASSOCIATED(PMat % Values)) THEN
2500
CALL Info('BlockPrecMatrix','Moving PrecValues to PrecMat!')
2501
CALL CRS_CopyMatrixTopology( AMat, PMat )
2502
ELSE
2503
! Make a partial check that PrecMat has been derived from the right template:
2504
IF (.NOT. ASSOCIATED(AMat % Rows, PMat % Rows)) &
2505
CALL Fatal('BlockPrecMatrix', 'Inconsistent matrix structures')
2506
END IF
2507
PMat % Values => Amat % PrecValues
2508
NULLIFY(Amat % PrecValues)
2509
END IF
2510
END IF
2511
2512
END SUBROUTINE BlockPrecMatrix
2513
2514
2515
! Check if matrix C that is a coupling block in the block matrix system
2516
! couples dofs at parallel interfaces. Assume that C := C_ab where a is
2517
! associated to A and b to B.
2518
!------------------------------------------------------------------------
2519
FUNCTION CheckParallelCoupling( A, B, C ) RESULT ( Coupled )
2520
TYPE(Matrix_t), POINTER :: A, B, C
2521
LOGICAL :: Coupled
2522
2523
LOGICAL :: Acoupled, Bcoupled
2524
INTEGER :: i,j,k
2525
REAL(KIND=dp) :: Eps
2526
2527
Coupled = .FALSE.
2528
IF(.NOT. ASSOCIATED( A % ParallelInfo ) ) THEN
2529
CALL Fatal('CheckParallelCoupling','Matrix A does not have ParallelInfo!')
2530
END IF
2531
IF(.NOT. ASSOCIATED( B % ParallelInfo ) ) THEN
2532
CALL Fatal('CheckParallelCoupling','Matrix B does not have ParallelInfo!')
2533
END IF
2534
2535
DO i=1,C % NumberOfRows
2536
DO j=C % Rows(i), C % Rows(i+1)-1
2537
k = C % Cols(j)
2538
IF( ABS( C % Values(j) ) < EPSILON( Eps ) ) CYCLE
2539
IF ( ASSOCIATED(A % ParallelInfo % NeighbourList(i) % Neighbours) ) THEN
2540
IF ( SIZE(A % ParallelInfo % NeighbourList(i) % Neighbours) > 1 ) Coupled = .TRUE.
2541
END IF
2542
IF ( ASSOCIATED(B % ParallelInfo % NeighbourList(k) % Neighbours) ) THEN
2543
IF ( SIZE(B % ParallelInfo % NeighbourList(k) % Neighbours) > 1 ) Coupled = .TRUE.
2544
END IF
2545
IF( Coupled ) EXIT
2546
END DO
2547
END DO
2548
2549
IF( Coupled ) THEN
2550
CALL Info('CheckParallelCoupling','Coupling matrix has parallel connections!',Level=10)
2551
ELSE
2552
CALL Info('CheckParallelCoupling','Coupling matrix does not have parallel connections!',Level=10)
2553
END IF
2554
2555
END FUNCTION CheckParallelCoupling
2556
2557
2558
!> Create the coupling blocks for a linear FSI coupling among various types of
2559
!> elasticity and fluid solvers.
2560
!--------------------------------------------------------------------------------
2561
SUBROUTINE FsiCouplingBlocks( Solver )
2562
2563
TYPE(Solver_t) :: Solver
2564
INTEGER :: i, j, k, Novar
2565
2566
TYPE(ValueList_t), POINTER :: Params
2567
TYPE(Matrix_t), POINTER :: A_fs, A_sf, A_s, A_f
2568
TYPE(Variable_t), POINTER :: FVar, SVar
2569
INTEGER, POINTER :: ConstituentSolvers(:)
2570
LOGICAL :: Found
2571
LOGICAL :: IsPlate, IsShell, IsNs, IsPres
2572
CHARACTER(*), PARAMETER :: Caller = 'FsiCouplingBlocks'
2573
2574
Params => Solver % Values
2575
ConstituentSolvers => ListGetIntegerArray(Params, 'Block Solvers', Found)
2576
2577
IsPlate = .FALSE.
2578
IsShell = .FALSE.
2579
IsNS = .FALSE.
2580
IsPres = .FALSE.
2581
2582
i = ListGetInteger( Params,'Structure Solver Index',Found)
2583
2584
IF ( Found ) THEN
2585
IsPlate = ListGetLogical( CurrentModel % Solvers(i) % Values,&
2586
'Plate Solver', Found )
2587
IsShell = ListGetLogical( CurrentModel % Solvers(i) % Values,&
2588
'Shell Solver', Found )
2589
ELSE
2590
i = ListGetInteger( Params,'Plate Solver Index',IsPlate)
2591
IF(.NOT. IsPlate ) THEN
2592
i = ListGetInteger( Params,'Shell Solver Index',IsShell)
2593
END IF
2594
END IF
2595
2596
! The first and second entries in the "Block Solvers" list define
2597
! the solver sections to assemble the (1,1)-block and (2,2)-block,
2598
! respectively. The following check is needed as the solver section
2599
! numbers may not index TotMatrix % Submatrix(:,:) directly.
2600
!
2601
IF (i > 0) THEN
2602
Found = .FALSE.
2603
DO k=1,SIZE(ConstituentSolvers)
2604
IF (i == ConstituentSolvers(k)) THEN
2605
Found = .TRUE.
2606
EXIT
2607
END IF
2608
END DO
2609
IF (.NOT. Found) THEN
2610
CALL Fatal(Caller, &
2611
'Structure/Plate/Shell Solver Index is not an entry in the Block Solvers array')
2612
ELSE
2613
i = k
2614
END IF
2615
END IF
2616
IF (i > 2) CALL Fatal(Caller, &
2617
'Use the first two entries of Block Solvers to define FSI coupling')
2618
2619
j = ListGetInteger( Params,'Fluid Solver Index',Found)
2620
IF(.NOT. Found ) THEN
2621
j = ListGetInteger( Params,'NS Solver Index', IsNs )
2622
IF( .NOT. IsNs ) THEN
2623
j = ListGetInteger( Params,'Pressure Solver Index',IsPres)
2624
END IF
2625
END IF
2626
2627
IF (j > 0) THEN
2628
Found = .FALSE.
2629
DO k=1,SIZE(ConstituentSolvers)
2630
IF (j == ConstituentSolvers(k)) THEN
2631
Found = .TRUE.
2632
EXIT
2633
END IF
2634
END DO
2635
IF (.NOT. Found) THEN
2636
CALL Fatal(Caller, &
2637
'Fluid/NS/Pressure Solver Index is not an entry in the Block Solvers array')
2638
ELSE
2639
j = k
2640
END IF
2641
END IF
2642
IF (j > 2) CALL Fatal(Caller, &
2643
'Use the first two entries of Block Solvers to define FSI coupling')
2644
2645
IF( j == 0 ) THEN
2646
IF( i > 1 .AND. TotMatrix % NoVar == 2 ) j = 3 - i
2647
END IF
2648
IF( i == 0 ) THEN
2649
IF( j > 1 .AND. TotMatrix % NoVar == 2 ) i = 3 - j
2650
END IF
2651
2652
IF(i<=0 .OR. j<=0) THEN
2653
IF( i > 0 ) CALL Warn(Caller,'Structure solver given but not fluid!')
2654
IF( j > 0 ) CALL Warn(Caller,'Fluid solver given but not structure!')
2655
RETURN
2656
END IF
2657
2658
! IF (i > TotMatrix % NoVar .OR. j > TotMatrix % NoVar) &
2659
! CALL Fatal(Caller,'Use solver sections 1 and 2 to define FSI coupling')
2660
2661
A_fs => TotMatrix % Submatrix(j,i) % Mat
2662
A_sf => TotMatrix % Submatrix(i,j) % Mat
2663
2664
IF(.NOT. ASSOCIATED( A_fs ) ) THEN
2665
CALL Fatal(Caller,'Fluid-structure coupling matrix not allocated!')
2666
END IF
2667
IF(.NOT. ASSOCIATED( A_sf ) ) THEN
2668
CALL Fatal(Caller,'Structure-fluid coupling matrix not allocated!')
2669
END IF
2670
2671
SVar => TotMatrix % Subvector(i) % Var
2672
FVar => TotMatrix % Subvector(j) % Var
2673
2674
A_s => TotMatrix % Submatrix(i,i) % Mat
2675
A_f => TotMatrix % Submatrix(j,j) % Mat
2676
2677
IF(.NOT. ASSOCIATED( FVar ) ) THEN
2678
CALL Fatal(Caller,'Fluid variable not present!')
2679
END IF
2680
IF(.NOT. ASSOCIATED( FVar ) ) THEN
2681
CALL Fatal(Caller,'Structure variable not present!')
2682
END IF
2683
2684
IF(.NOT. (IsNs .OR. IsPres ) ) THEN
2685
IsPres = ( FVar % Dofs <= 2 )
2686
IsNs = .NOT. IsPres
2687
END IF
2688
2689
CALL FsiCouplingAssembly( Solver, FVar, SVar, A_f, A_s, A_fs, A_sf, &
2690
IsPlate, IsShell, IsNS )
2691
2692
IF( ParEnv % PEs > 1 ) THEN
2693
TotMatrix % Submatrix(i,j) % ParallelSquareMatrix = .FALSE.
2694
TotMatrix % Submatrix(j,i) % ParallelSquareMatrix = .FALSE.
2695
2696
TotMatrix % Submatrix(i,j) % ParallelIsolatedMatrix = &
2697
.NOT. CheckParallelCoupling(A_s, A_f, A_sf )
2698
TotMatrix % Submatrix(j,i) % ParallelIsolatedMatrix = &
2699
.NOT. CheckParallelCoupling(A_f, A_s, A_fs )
2700
END IF
2701
2702
2703
END SUBROUTINE FsiCouplingBlocks
2704
2705
2706
!> Create the coupling between elasticity solvers of various types.
2707
!--------------------------------------------------------------------------------
2708
SUBROUTINE StructureCouplingBlocks( Solver )
2709
2710
TYPE(Solver_t) :: Solver
2711
2712
INTEGER :: i,j,k,ind1,ind2,Novar,Nsol
2713
INTEGER, POINTER :: ConstituentSolvers(:)
2714
LOGICAL :: Found
2715
TYPE(ValueList_t), POINTER :: Params, ShellParams
2716
TYPE(Matrix_t), POINTER :: A_fs, A_sf, A_s, A_f
2717
TYPE(Variable_t), POINTER :: FVar, SVar
2718
LOGICAL :: IsPlate, IsShell, IsBeam, IsSolid, GotBlockSolvers
2719
LOGICAL :: DrillingDOFs
2720
TYPE(Solver_t), POINTER :: PSol
2721
CHARACTER(*), PARAMETER :: Caller = 'StructureCouplingBlocks'
2722
2723
2724
Params => Solver % Values
2725
ConstituentSolvers => ListGetIntegerArray(Params, 'Block Solvers', GotBlockSolvers)
2726
IF(.NOT. GotBlockSolvers ) THEN
2727
CALL Fatal(Caller,'We need "Block Solvers" defined!')
2728
END IF
2729
2730
! Currently we simply assume the master solver to be listed as the first entry in
2731
! the 'Block Solvers' array.
2732
i = 1
2733
SVar => TotMatrix % Subvector(i) % Var
2734
IF(.NOT. ASSOCIATED( SVar ) ) THEN
2735
CALL Fatal(Caller,'Master structure variable not present!')
2736
END IF
2737
A_s => TotMatrix % Submatrix(i,i) % Mat
2738
2739
Nsol = SIZE( ConstituentSolvers )
2740
2741
2742
DO j = 1, Nsol
2743
! No need to couple to one self!
2744
IF(j==1) CYCLE
2745
IF (j > size(ConstituentSolvers)) CALL Fatal(Caller, &
2746
'Solid/Plate/Shell/Beam Solver Index larger than Block Solvers array')
2747
2748
k = ConstituentSolvers(j)
2749
PSol => CurrentModel % Solvers(k)
2750
2751
IsSolid = ListGetLogical( Psol % Values,'Solid Solver',IsSolid)
2752
IsPlate = ListGetLogical( Psol % Values,'Plate Solver',IsPlate)
2753
IsShell = ListGetLogical( Psol % Values,'Shell Solver',IsShell)
2754
IsBeam = ListGetLogical( Psol % Values,'Beam Solver',IsBeam)
2755
2756
ind1 = ConstituentSolvers(i)
2757
ind2 = ConstituentSolvers(j)
2758
CALL Info(Caller,'Generating coupling between solvers '&
2759
//I2S(ind1)//' and '//I2S(ind2))
2760
2761
2762
A_fs => TotMatrix % Submatrix(j,i) % Mat
2763
A_sf => TotMatrix % Submatrix(i,j) % Mat
2764
2765
!SVar => TotMatrix % Subvector(i) % Var
2766
FVar => TotMatrix % Subvector(j) % Var
2767
IF(.NOT. ASSOCIATED( FVar ) ) THEN
2768
CALL Fatal(Caller,'Slave structure variable not present!')
2769
END IF
2770
2771
!A_s => TotMatrix % Submatrix(i,i) % Mat
2772
A_f => TotMatrix % Submatrix(j,j) % Mat
2773
2774
IF (IsShell) THEN
2775
ShellParams => Fvar % Solver % Values
2776
DrillingDOFs = GetLogical(ShellParams, 'Drilling DOFs', Found)
2777
ELSE
2778
DrillingDOFs = .FALSE.
2779
END IF
2780
2781
CALL StructureCouplingAssembly( Solver, FVar, SVar, A_f, A_s, A_fs, A_sf, &
2782
IsSolid, IsPlate, IsShell, IsBeam, DrillingDOFs)
2783
2784
IF( ParEnv % PEs > 1 ) THEN
2785
TotMatrix % Submatrix(i,j) % ParallelSquareMatrix = .FALSE.
2786
TotMatrix % Submatrix(j,i) % ParallelSquareMatrix = .FALSE.
2787
2788
TotMatrix % Submatrix(i,j) % ParallelIsolatedMatrix = &
2789
.NOT. CheckParallelCoupling(A_s, A_f, A_sf )
2790
TotMatrix % Submatrix(j,i) % ParallelIsolatedMatrix = &
2791
.NOT. CheckParallelCoupling(A_f, A_s, A_fs )
2792
END IF
2793
2794
END DO
2795
2796
END SUBROUTINE StructureCouplingBlocks
2797
2798
2799
! This is tailored L2 norm for the many use types of the block solver.
2800
!---------------------------------------------------------------------
2801
FUNCTION CompNorm( x, n, npar, A) RESULT ( nrm )
2802
REAL(KIND=dp) :: x(:)
2803
INTEGER :: n
2804
INTEGER, OPTIONAL :: npar
2805
TYPE(Matrix_t), POINTER, OPTIONAL :: A
2806
REAL(KIND=dp) :: nrm
2807
2808
INTEGER :: i,m
2809
REAL(KIND=dp) :: s,stot,ntot
2810
2811
IF( ParEnv % PEs > 1 .AND. PRESENT( A ) ) THEN
2812
m = 0
2813
s = 0.0_dp
2814
DO i=1,A % NumberOfRows
2815
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(i) % Neighbours(1)) CYCLE
2816
m = m+1
2817
s = s + x(i)**2
2818
END DO
2819
ELSE
2820
IF( ParEnv % PEs > 1 .AND. PRESENT( npar ) ) THEN
2821
m = npar
2822
ELSE
2823
m = n
2824
END IF
2825
s = SUM(x(1:m)**2)
2826
END IF
2827
2828
stot = ParallelReduction(s)
2829
ntot = ParallelReduction(m)
2830
2831
nrm = SQRT( stot / ntot )
2832
2833
END FUNCTION CompNorm
2834
2835
2836
!------------------------------------------------------------------------------
2837
!> Compute the rhs for the block matrix system which is solved
2838
!> accounting only the diagonal entries i.e. subtract the non-diagonal
2839
!> matrix-vector results from the original r.h.s. vectors.
2840
!> After this the block diagonal problem Ax=b may be solved.
2841
!----------------------------------------------------------------------------------
2842
SUBROUTINE BlockUpdateRhs( BlockMatrix, ThisRow )
2843
2844
TYPE(BlockMatrix_t), TARGET :: BlockMatrix
2845
INTEGER, OPTIONAL :: ThisRow
2846
2847
TYPE(Matrix_t), POINTER :: A
2848
INTEGER :: n, NoRow,NoCol, NoVar
2849
REAL(KIND=dp), POINTER :: x(:),rtmp(:),rhs(:)
2850
REAL(KIND=dp) :: bnorm
2851
TYPE(Variable_t), POINTER :: Var
2852
2853
CALL Info('BlockUpdateRhs','Computing block r.h.s',Level=8)
2854
2855
NoVar = BlockMatrix % NoVar
2856
2857
! The residual is used only as a temporary vector
2858
ALLOCATE( rtmp(BlockMatrix % MaxSize) )
2859
2860
2861
DO NoRow = 1,NoVar
2862
2863
! Optionally only one diagonal block may be updated for
2864
IF( PRESENT( ThisRow ) ) THEN
2865
IF( NoRow /= ThisRow ) CYCLE
2866
END IF
2867
2868
Var => BlockMatrix % SubVector(NoRow) % Var
2869
x => Var % Values
2870
n = SIZE( x )
2871
2872
! The r.h.s. of the initial system is stored in the Matrix
2873
!-----------------------------------------------------------
2874
IF(.NOT. ALLOCATED( BlockMatrix % SubVector(NoRow) % rhs )) THEN
2875
ALLOCATE( BlockMatrix % SubVector(NoRow) % rhs(n) )
2876
CALL Info('BlockUpdateRhs','Creating rhs for component: '//I2S(NoRow),Level=12)
2877
END IF
2878
rhs => BlockMatrix % SubVector(NoRow) % rhs
2879
rhs = 0.0_dp
2880
2881
A => BlockMatrix % SubMatrix( NoRow, NoRow ) % Mat
2882
IF( ASSOCIATED( A ) ) THEN
2883
IF( ASSOCIATED( A % rhs ) ) rhs = A % rhs
2884
END IF
2885
2886
DO NoCol = 1,NoVar
2887
! This ensures that the diagonal itself is not subtracted
2888
! before computing the bnorm used to estimate the convergence.
2889
IF( NoCol == NoRow ) CYCLE
2890
2891
Var => BlockMatrix % SubVector(NoCol) % Var
2892
x => Var % Values
2893
2894
A => BlockMatrix % SubMatrix( NoRow, NoCol ) % Mat
2895
IF( A % NumberOfRows == 0 ) CYCLE
2896
2897
CALL CRS_MatrixVectorMultiply( A, x, rtmp)
2898
rhs(1:n) = rhs(1:n) - rtmp(1:n)
2899
END DO
2900
2901
2902
bnorm = CompNorm(rhs,n)
2903
BlockMatrix % SubVector(NoRow) % bnorm = bnorm
2904
2905
! Finally deduct the diagonal entry so that we can solve for the residual
2906
NoCol = NoRow
2907
Var => BlockMatrix % SubVector(NoCol) % Var
2908
x => Var % Values
2909
A => BlockMatrix % SubMatrix( NoRow, NoCol ) % Mat
2910
IF( A % NumberOfRows > 0 ) THEN
2911
CALL CRS_MatrixVectorMultiply( A, x, rtmp)
2912
rhs(1:n) = rhs(1:n) - rtmp(1:n)
2913
END IF
2914
2915
END DO
2916
2917
DEALLOCATE( rtmp )
2918
2919
END SUBROUTINE BlockUpdateRhs
2920
2921
2922
!------------------------------------------------------------------------------
2923
!> Perform matrix-vector product v=Au for block matrices.
2924
!> Has to be callable outside the module by Krylov methods.
2925
!------------------------------------------------------------------------------
2926
!------------------------------------------------------------------------------
2927
SUBROUTINE BlockMatrixVectorProd( u,v,ipar )
2928
!------------------------------------------------------------------------------
2929
REAL(KIND=dp), INTENT(in) :: u(*)
2930
REAL(KIND=dp), INTENT(out) :: v(*)
2931
INTEGER, INTENT(in) :: ipar(*)
2932
2933
INTEGER :: n,i,j,k,NoVar,i1,i2,j1,j2,ll,kk
2934
REAL(KIND=dp), ALLOCATABLE :: s(:)
2935
INTEGER :: maxsize,ndofs
2936
INTEGER, POINTER :: Offset(:)
2937
REAL(KIND=dp) :: nrm
2938
TYPE(Matrix_t), POINTER :: A
2939
REAL(KIND=dp), POINTER :: b(:)
2940
2941
LOGICAL :: Isolated
2942
LOGICAL :: DoSum , DoAMGXMV, Found
2943
2944
DoAMGXMV = ListGetLogical( SolverRef % Values, 'Block AMGX M-V', Found)
2945
2946
CALL Info('BlockMatrixVectorProd','Starting block matrix multiplication',Level=20)
2947
2948
NoVar = TotMatrix % NoVar
2949
MaxSize = TotMatrix % MaxSize
2950
ALLOCATE( s(MaxSize) )
2951
2952
IF( isParallel ) THEN
2953
Offset => TotMatrix % ParOffset
2954
ELSE
2955
Offset => TotMatrix % Offset
2956
END IF
2957
2958
v(1:offset(NoVar+1)) = 0
2959
2960
DO i=1,NoVar
2961
DO j=1,NoVar
2962
s = 0._dp
2963
2964
j1 = offset(j)+1
2965
j2 = offset(j+1)
2966
2967
IF ( ListGetLogical(SolverRef % Values, 'Dummy block'//I2S(i), Found) ) CYCLE
2968
A => TotMatrix % SubMatrix(i,j) % Mat
2969
IF ( .NOT. ASSOCIATED(A) ) CYCLE
2970
IF ( A % NumberOfRows == 0) CYCLE
2971
Isolated = TotMatrix % SubMatrix(i,j) % ParallelIsolatedMatrix
2972
2973
CALL Info('BlockMatrixVectorProd','Multiplying with submatrix ('&
2974
//I2S(i)//','//I2S(j)//')',Level=15)
2975
2976
IF (isParallel) THEN
2977
IF( ASSOCIATED( A % ParMatrix ) ) THEN
2978
CALL ParallelMatrixVector( A, u(j1:j2), s )
2979
ELSE IF( Isolated ) THEN
2980
CALL CRS_MatrixVectorMultiply( A, u(j1:j2), s )
2981
ELSE
2982
CALL Fatal('BlockMatrixVectorProd','Cannot make the matric-vector product in parallel!')
2983
END IF
2984
ELSE
2985
IF ( DoAMGXMV ) THEN
2986
CALL AMGXMatrixVectorMultiply(A, u(j1:j2), s, SolverRef )
2987
ELSE
2988
CALL CRS_MatrixVectorMultiply( A, u(j1:j2), s )
2989
END IF
2990
END IF
2991
2992
IF( InfoActive( 25 ) ) THEN
2993
PRINT *,'MatVecProdNorm u:',i,j,&
2994
SQRT(SUM(u(j1:j2)**2)),SUM( u(j1:j2) ), MINVAL( u(j1:j2) ), MAXVAL( u(j1:j2) )
2995
PRINT *,'MatVecProdNorm s:',i,j,&
2996
SQRT(SUM(s**2)), SUM( s ), MINVAL( s ), MAXVAL( s )
2997
END IF
2998
2999
v(offset(i)+1:offset(i+1)) = v(offset(i)+1:offset(i+1)) + s(1:offset(i+1)-offset(i))
3000
END DO
3001
3002
IF( InfoActive( 25 ) ) THEN
3003
i1 = offset(i)+1
3004
i2 = offset(i+1)
3005
b => TotMatrix % Submatrix(i,i) % Mat % Rhs
3006
IF( ASSOCIATED( b ) ) THEN
3007
PRINT *,'MatVecProdNorm b:',i,&
3008
SQRT(SUM(b**2)),SUM( b ), MINVAL( b ), MAXVAL( b )
3009
END IF
3010
PRINT *,'MatVecProdNorm v:',i,&
3011
SQRT(SUM(v(i1:i2)**2)), SUM( v(i1:i2) ), MINVAL( v(i1:i2) ), MAXVAL( v(i1:i2) )
3012
END IF
3013
END DO
3014
3015
IF( InfoActive( 25 ) ) THEN
3016
n = offset(NoVar+1)
3017
nrm = CompNorm(v(1:n),n)
3018
WRITE( Message,'(A,ES12.5)') 'Mv result norm: ',nrm
3019
CALL Info('BlockMatrixVectorProd',Message )
3020
END IF
3021
3022
CALL Info('BlockMatrixVectorProd','Finished block matrix multiplication',Level=20)
3023
!------------------------------------------------------------------------------
3024
END SUBROUTINE BlockMatrixVectorProd
3025
!------------------------------------------------------------------------------
3026
3027
3028
!------------------------------------------------------------------------------
3029
!> Given a permutation between monolithic and block matrix solutions
3030
!> create a map between the owned dofs for the same in parallel.
3031
!------------------------------------------------------------------------------
3032
SUBROUTINE ParallelShrinkPerm()
3033
TYPE(Matrix_t), POINTER :: A, Adiag
3034
INTEGER, POINTER :: BlockPerm(:), ParBlockPerm(:), ParPerm(:)
3035
INTEGER :: i,j,k,l,n,m
3036
INTEGER, ALLOCATABLE :: ShrinkPerm(:),RenumPerm(:)
3037
LOGICAL :: Halt
3038
3039
n = TotMatrix % TotSize
3040
Halt = .FALSE.
3041
3042
! Example of blockperm: block solution u to monolithic solution v
3043
! v(1:n) = u(BlockPerm(1:n))
3044
3045
! Dense numbering the monolithic dofs
3046
A => TotMatrix % ParentMatrix
3047
IF(.NOt. ASSOCIATED(A) ) A => SolverMatrix
3048
3049
IF( ASSOCIATED( A ) ) THEN
3050
CALL Info('ParallelShrinkPerm','Using the monolithic matrix to deduce permutation',Level=6)
3051
ELSE
3052
CALL Info('ParallelShrinkPerm','Using the block matrix to deduce permutation',Level=6)
3053
END IF
3054
3055
ALLOCATE(ShrinkPerm(n))
3056
3057
DO j=1,TotMatrix % Novar
3058
Adiag => TotMatrix % Submatrix(j,j) % Mat
3059
IF(.NOT. ASSOCIATED( Adiag % ParallelInfo ) ) CYCLE
3060
k = 0
3061
l = 0
3062
m = 0
3063
ShrinkPerm(1:Adiag % NumberOfRows) = 0
3064
DO i=1,Adiag % NumberOfRows
3065
k = k + 1
3066
IF (Parenv % MyPE /= Adiag % ParallelInfo % NeighbourList(i) % Neighbours(1)) THEN
3067
m = m+1
3068
CYCLE
3069
END IF
3070
l = l+1
3071
ShrinkPerm(k) = l
3072
END DO
3073
3074
IF(ASSOCIATED(TotMatrix % Submatrix(j,j) % ParPerm )) THEN
3075
k = SIZE(TotMatrix % SubMatrix(j,j) % ParPerm)
3076
IF(k /= l) THEN
3077
CALL Warn('ParallelShrinkPerm','Different size for ParPerm '&
3078
//I2S(l)//': '//I2S(k)//' vs. '//I2S(l))
3079
PRINT *,'ParBlockPerm skipped1',ParEnv % MyPe, m, j
3080
DEALLOCATE(TotMatrix % SubMatrix(j,j) % ParPerm )
3081
Halt = .TRUE.
3082
END IF
3083
END IF
3084
3085
IF(.NOT. ASSOCIATED(TotMatrix % Submatrix(j,j) % ParPerm ) ) THEN
3086
ALLOCATE( TotMatrix % Submatrix(j,j) % ParPerm(l) )
3087
END IF
3088
ParPerm => TotMatrix % Submatrix(j,j) % ParPerm
3089
ParPerm = 0
3090
DO i=1,Adiag % NumberOfRows
3091
k = ShrinkPerm(i)
3092
IF(k==0) CYCLE
3093
ParPerm(k) = i
3094
END DO
3095
END DO
3096
3097
m = 0
3098
3099
ShrinkPerm = 0
3100
IF( ASSOCIATED( A ) ) THEN
3101
l = 0
3102
DO i=1,A % NumberOfRows
3103
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(i) % Neighbours(1)) THEN
3104
m = m+1
3105
CYCLE
3106
END IF
3107
l = l+1
3108
ShrinkPerm(i) = l
3109
END DO
3110
END IF
3111
3112
IF(.NOT. ASSOCIATED(TotMatrix % ParPerm) ) THEN
3113
ALLOCATE( TotMatrix % ParPerm(l) )
3114
END IF
3115
ParPerm => TotMatrix % ParPerm
3116
ParPerm = 0
3117
DO i=1,n
3118
j = ShrinkPerm(i)
3119
IF(j==0) CYCLE
3120
ParPerm(j) = i
3121
END DO
3122
3123
3124
IF(.NOT. ASSOCIATED(TotMatrix % ParOffset) ) THEN
3125
ALLOCATE( TotMatrix % ParOffset(TotMatrix % NoVar+1))
3126
END IF
3127
TotMatrix % ParOffset = 0
3128
k = 0
3129
l = 0
3130
DO j=1,TotMatrix % Novar
3131
m = 0
3132
A => TotMatrix % Submatrix(j,j) % Mat
3133
DO i=1,A % NumberOfRows
3134
k = k + 1
3135
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(i) % Neighbours(1)) THEN
3136
m = m+1
3137
CYCLE
3138
END IF
3139
l = l+1
3140
END DO
3141
TotMatrix % ParOffset(j+1) = l
3142
END DO
3143
3144
3145
CALL Info('ParallelShrinkPerm','Number of parallel dofs in this partition: '// &
3146
I2S(l)//' / '//I2S(n), Level=6)
3147
3148
! We can only make the ParBlockPerm if also BlockPerm exists!
3149
BlockPerm => TotMatrix % BlockPerm
3150
IF(.NOT. ASSOCIATED(BlockPerm) ) THEN
3151
IF(Halt) STOP
3152
RETURN
3153
END IF
3154
3155
! Dense numbering for the block system dofs
3156
ALLOCATE(RenumPerm(n))
3157
RenumPerm = 1
3158
DO i=1,n
3159
j = BlockPerm(i)
3160
IF( ShrinkPerm(j) == 0 ) RenumPerm(i) = 0
3161
END DO
3162
l = 0
3163
DO i=1,n
3164
IF(RenumPerm(i) > 0) THEN
3165
l=l+1
3166
RenumPerm(i) = l
3167
END IF
3168
END DO
3169
3170
! Allocate the parallel permutation, if not already done
3171
IF(ASSOCIATED(TotMatrix % ParBlockPerm)) THEN
3172
k = SIZE(TotMatrix % ParBlockPerm)
3173
IF(k /= l) THEN
3174
CALL Warn('ParallelShrinkPerm','Different size for ParBlockPerm: '//I2S(k)//' vs. '//I2S(l))
3175
PRINT *,'ParBlockPerm skipped2',ParEnv % MyPe, m
3176
DEALLOCATE(TotMatrix % ParBlockPerm)
3177
Halt = .TRUE.
3178
END IF
3179
END IF
3180
IF(.NOT. ASSOCIATED(TotMatrix % ParBlockPerm) ) THEN
3181
ALLOCATE(TotMatrix % ParBlockPerm(l))
3182
END IF
3183
ParBlockPerm => TotMatrix % ParBlockPerm
3184
ParBlockPerm = 0
3185
3186
! And finally create the renumbering scheme.
3187
! This was tough to settle. Don't doubt it!
3188
DO i=1,n
3189
IF(RenumPerm(i)==0) CYCLE
3190
ParBlockPerm(RenumPerm(i)) = ShrinkPerm(BlockPerm(i))
3191
END DO
3192
3193
IF(Halt) STOP
3194
3195
END SUBROUTINE ParallelShrinkPerm
3196
3197
3198
!------------------------------------------------------------------------------
3199
! If the block matrix is just a remake of the monolithic one we may actually
3200
! use the monolithic version when we make the necessary permutations.
3201
! The advantage may be that we have an alternative (more simple) routine for
3202
! debugging and it may also be faster...
3203
! Note that here u and v only include the owned dofs for each partition.
3204
! Hence if we want to make a standard matrix-vector product we need to expand
3205
! these to include all dofs.
3206
!------------------------------------------------------------------------------
3207
SUBROUTINE BlockMatrixVectorProdMono( u,v,ipar )
3208
!------------------------------------------------------------------------------
3209
REAL(KIND=dp), INTENT(in) :: u(*)
3210
REAL(KIND=dp), INTENT(out) :: v(*)
3211
INTEGER, INTENT(in) :: ipar(*)
3212
3213
INTEGER :: n,m,i,j,k,NoVar,i1,i2,j1,j2
3214
REAL(KIND=dp), ALLOCATABLE :: s(:)
3215
INTEGER :: maxsize,ndofs
3216
INTEGER, POINTER :: Offset(:)
3217
REAL(KIND=dp) :: nrm
3218
TYPE(Matrix_t), POINTER :: A
3219
REAL(KIND=dp), POINTER :: b(:)
3220
LOGICAL :: DoSum, GotBlockStruct
3221
REAL(KIND=dp), POINTER :: utmp(:),vtmp(:)
3222
INTEGER, POINTER :: BlockPerm(:)
3223
3224
CALL Info('BlockMatrixVectorProdMono','Starting monolithic matrix multiplication',Level=20)
3225
3226
IF(.NOT.ASSOCIATED(SolverMatrix)) THEN
3227
CALL Fatal('BlockMatrixVectorProdMono','No matrix to apply.')
3228
END IF
3229
3230
NoVar = TotMatrix % NoVar
3231
MaxSize = TotMatrix % MaxSize
3232
GotBlockStruct = TotMatrix % GotBlockStruct
3233
3234
n = ipar(3)
3235
3236
IF(isParallel) THEN
3237
BlockPerm => TotMatrix % ParBlockPerm
3238
IF(.NOT. ASSOCIATED( BlockPerm ) ) THEN
3239
BlockPerm => TotMatrix % ParPerm
3240
END IF
3241
IF(.NOT. ASSOCIATED(BlockPerm) ) THEN
3242
CALL Fatal('BlockMatrixVectorProdMono','How come there is no permutation in parallel?')
3243
END IF
3244
Offset => TotMatrix % ParOffset
3245
ELSE
3246
BlockPerm => TotMatrix % BlockPerm
3247
Offset => TotMatrix % Offset
3248
END IF
3249
3250
IF( ASSOCIATED( BlockPerm ) ) THEN
3251
IF(InfoActive(20)) THEN
3252
i = MAXVAL( BlockPerm )
3253
j = MINVAL( BlockPerm )
3254
IF( j <= 0 .OR. i > n ) THEN
3255
CALL Fatal('BlockMatrixVectorProdMono','Invalid sizes: '&
3256
//I2S(i)//' '//I2S(j)//' '//I2S(n)//' '//I2S(SIZE(BlockPerm)))
3257
END IF
3258
CALL Info('BlockMatrixVectorProdMono','BlockPermSizes: '//I2S(i)//' '//I2S(j)//' '//I2S(n))
3259
END IF
3260
END IF
3261
3262
3263
IF(isParallel) THEN
3264
! Reorder & copy block variable to monolithic variable
3265
m = SolverMatrix % NumberOfRows
3266
ALLOCATE(utmp(m),vtmp(m))
3267
utmp(1:m) = 0.0_dp
3268
utmp(BlockPerm(1:n)) = u(1:n)
3269
CALL ParallelMatrixVector(SolverMatrix, utmp(1:m), vtmp(1:m) )
3270
v(1:n) = vtmp(BlockPerm(1:n))
3271
DEALLOCATE(utmp,vtmp)
3272
ELSE
3273
IF( ASSOCIATED( BlockPerm ) ) THEN
3274
! Only reorder between block and monolithic ordering
3275
ALLOCATE(utmp(n))
3276
utmp(BlockPerm(1:n)) = u(1:n)
3277
CALL CRS_MatrixVectorMultiply( SolverMatrix, utmp, v )
3278
v(1:n) = v(BlockPerm(1:n))
3279
ELSE
3280
CALL CRS_MatrixVectorMultiply( SolverMatrix, u(1:n), v(1:n) )
3281
END IF
3282
END IF
3283
3284
IF( InfoActive( 25 ) ) THEN
3285
nrm = CompNorm(v(1:n),n)
3286
WRITE( Message,'(A,ES12.5)') 'Mv result norm: ',nrm
3287
CALL Info('BlockMatrixVectorProdMono',Message )
3288
END IF
3289
3290
CALL Info('BlockMatrixVectorProdMono','Finished block matrix multiplication',Level=20)
3291
!------------------------------------------------------------------------------
3292
END SUBROUTINE BlockMatrixVectorProdMono
3293
!------------------------------------------------------------------------------
3294
3295
3296
3297
!> Create the vectors needed for block matrix scaling. Currently only
3298
!> real and complex valued row equilibration is supported. Does not perform
3299
!> the actual scaling.
3300
!------------------------------------------------------------------------------
3301
SUBROUTINE CreateBlockMatrixScaling( )
3302
!------------------------------------------------------------------------------
3303
IMPLICIT NONE
3304
3305
INTEGER :: i,j,k,l,n,m,NoVar,istat
3306
REAL(KIND=dp) :: nrm, tmp, blocknrm
3307
TYPE(Matrix_t), POINTER :: A
3308
REAL(KIND=dp), POINTER :: b(:), Diag(:), Values(:)
3309
LOGICAL :: ComplexMatrix, GotIt, DiagOnly, PrecScale
3310
INTEGER, POINTER :: Rows(:), Cols(:)
3311
LOGICAL :: Found
3312
TYPE(ValueList_t), POINTER :: Params
3313
TYPE(Variable_t), POINTER :: SolverVar
3314
CHARACTER(*), PARAMETER :: Caller = 'CreateBlockMatrixScaling'
3315
3316
CALL Info(Caller,'Starting block matrix row equilibration',Level=20)
3317
3318
NoVar = TotMatrix % NoVar
3319
3320
Params => CurrentModel % Solver % Values
3321
DiagOnly = ListGetLogical( Params,'Block Scaling Diagonal',Found )
3322
IF( DiagOnly ) THEN
3323
CALL Info(Caller,'Considering only diagonal matrices in scaling',Level=20)
3324
END IF
3325
3326
PrecScale = ListGetLogical( Params,'Block Scaling PrecMatrix',Found )
3327
3328
m = 0
3329
DO k=1,NoVar
3330
A => TotMatrix % SubMatrix(k,k) % Mat
3331
n = A % NumberOfRows
3332
IF(.NOT. ASSOCIATED(TotMatrix % Subvector )) THEN
3333
CALL Fatal(Caller,'Subvector not associated!')
3334
END IF
3335
IF( ASSOCIATED(TotMatrix % Subvector(k) % Var) ) THEN
3336
! We might have a constraint and then the block diagonal matrix may not exist.
3337
n = MAX(n, SIZE(TotMatrix % SubVector(k) % Var % Values) )
3338
END IF
3339
3340
IF( .NOT. ALLOCATED( Totmatrix % SubVector(k) % DiagScaling ) ) THEN
3341
m = m + 1
3342
ALLOCATE( TotMatrix % SubVector(k) % DiagScaling(n), STAT=istat )
3343
IF( istat /= 0 ) THEN
3344
CALL Fatal(Caller,'Cannot allocate scaling vectors '//I2S(k)//' of size: '//I2S(n))
3345
END IF
3346
CALL Info(Caller,'Allocated scaling vector of size '//I2S(n)//' to block '//I2S(k),Level=20)
3347
END IF
3348
END DO
3349
IF( m > 0 ) THEN
3350
CALL Info(Caller,'Allocated '//I2S(m)//' scaling vectors for rhs!',Level=8)
3351
END IF
3352
3353
3354
GotIt = .FALSE.
3355
blocknrm = 0.0_dp
3356
ComplexMatrix = .FALSE.
3357
DO k=1,NoVar
3358
A => TotMatrix % SubMatrix(k,k) % Mat
3359
IF( ASSOCIATED( A ) ) THEN
3360
IF( A % NumberOfRows > 0 .AND. .NOT. GotIt) THEN
3361
GotIt = .TRUE.
3362
! We assume that if complex flag is not found for k>1 it is inherited from previous ones.
3363
ComplexMatrix = A % COMPLEX
3364
IF( ComplexMatrix ) THEN
3365
m = 2
3366
CALL Info(Caller,'Assuming complex block matrix in scaling!',Level=20)
3367
ELSE
3368
m = 1
3369
CALL Info(Caller,'Assuming real valued block matrix in scaling!',Level=20)
3370
END IF
3371
END IF
3372
END IF
3373
IF(.NOT. GotIt) CALL Warn(Caller,'Improve complex matrix detection!')
3374
3375
Diag => TotMatrix % SubVector(k) % DiagScaling
3376
Diag = 0.0_dp
3377
3378
3379
DO l=1,NoVar
3380
IF( DiagOnly ) THEN
3381
IF( k /= l ) CYCLE
3382
END IF
3383
3384
Found = .FALSE.
3385
IF(k==l .AND. PrecScale ) THEN
3386
A => TotMatrix % Submatrix(k,k) % PrecMat
3387
Found = ( A % NumberOfRows > 0 )
3388
IF(Found) THEN
3389
CALL Info(Caller,'Using PrecMat to define the scaling of block row '//I2S(k),Level=20)
3390
END IF
3391
END IF
3392
3393
IF(.NOT.Found) THEN
3394
A => TotMatrix % Submatrix(k,l) % Mat
3395
END IF
3396
IF(.NOT. ASSOCIATED( A ) ) CYCLE
3397
3398
n = A % NumberOfRows
3399
IF( n == 0 ) CYCLE
3400
3401
Rows => A % Rows
3402
Cols => A % Cols
3403
Values => A % Values
3404
3405
!---------------------------------------------
3406
! Compute 1-norm of each row
3407
!---------------------------------------------
3408
DO i=1,n,m
3409
tmp = 0.0_dp
3410
3411
IF( ComplexMatrix ) THEN
3412
DO j=Rows(i),Rows(i+1)-1,2
3413
tmp = tmp + SQRT( Values(j)**2 + Values(j+1)**2 )
3414
END DO
3415
ELSE
3416
DO j=Rows(i),Rows(i+1)-1
3417
tmp = tmp + ABS(Values(j))
3418
END DO
3419
END IF
3420
3421
! Compute the sum to the real component, scaling for imaginary will be the same
3422
Diag(i) = Diag(i) + tmp
3423
END DO
3424
END DO
3425
3426
IF (ParEnv % PEs > 1) THEN
3427
A => TotMatrix % SubMatrix(k,k) % Mat
3428
IF( A % NumberOfRows > 0 ) THEN
3429
! We need the parallel info that is only available in the matrix.
3430
CALL ParallelSumVector(A, Diag)
3431
END IF
3432
END IF
3433
3434
n = SIZE(Diag)
3435
nrm = MAXVAL(Diag(1:n))
3436
IF( ParEnv % PEs > 1 ) THEN
3437
nrm = ParallelReduction(nrm,2)
3438
END IF
3439
blocknrm = MAX(blocknrm,nrm)
3440
3441
! Define the actual scaling vector (for real component)
3442
DO i=1,n,m
3443
IF (Diag(i) > EPSILON( nrm ) ) THEN
3444
Diag(i) = 1.0_dp / Diag(i)
3445
ELSE
3446
Diag(i) = 1.0_dp
3447
END IF
3448
END DO
3449
3450
! Scaling of complex component
3451
IF( ComplexMatrix ) Diag(2::2) = Diag(1::2)
3452
3453
WRITE( Message,'(A,ES12.5)') 'Unscaled matrix norm for block '//I2S(k)//': ', nrm
3454
CALL Info(Caller, Message, Level=10 )
3455
END DO
3456
3457
WRITE( Message,'(A,ES12.5)') 'Unscaled matrix norm: ', blocknrm
3458
CALL Info(Caller, Message, Level=7 )
3459
3460
END SUBROUTINE CreateBlockMatrixScaling
3461
!------------------------------------------------------------------------------
3462
3463
3464
!------------------------------------------------------------------------------
3465
SUBROUTINE BlockMatrixInfo()
3466
!------------------------------------------------------------------------------
3467
IMPLICIT NONE
3468
INTEGER :: i,j,k,l,n,m,NoVar
3469
INTEGER(KIND=8) :: ll
3470
REAL(KIND=dp) :: nrm, tmp, blocknrm
3471
TYPE(Matrix_t), POINTER :: A
3472
REAL(KIND=dp), POINTER :: b(:), Diag(:), Values(:)
3473
LOGICAL :: ComplexMatrix, GotIt, DiagOnly
3474
INTEGER, POINTER :: Rows(:), Cols(:)
3475
LOGICAL :: Found
3476
CHARACTER(:), ALLOCATABLE :: pre
3477
3478
3479
CALL Info('BlockMatrixInfo','')
3480
CALL Info('BlockMatrixInfo','Showing some ranges of block matrix stuff',Level=10)
3481
3482
NoVar = TotMatrix % NoVar
3483
m = 0
3484
3485
pre = 'BlockInfo'//I2S(ParEnv % MyPe)//': '
3486
3487
PRINT *,pre,NoVar, ParEnv % Mype
3488
DO k=1,NoVar
3489
DO l=1,NoVar
3490
3491
A => TotMatrix % SubMatrix(k,l) % Mat
3492
IF( .NOT. ASSOCIATED( A ) ) CYCLE
3493
IF( A % NumberOfRows == 0 ) CYCLE
3494
3495
n = 0
3496
m = 0
3497
3498
IF( ASSOCIATED( TotMatrix % Offset ) ) THEN
3499
n = TotMatrix % offset(k+1) - TotMatrix % offset(k)
3500
END IF
3501
IF(isParallel ) THEN
3502
IF( ASSOCIATED( TotMatrix % ParOffset ) ) THEN
3503
m = TotMatrix % ParOffset(k+1) -TotMatrix % ParOffset(k)
3504
END IF
3505
END IF
3506
3507
PRINT *,TRIM(pre)//' size',k,l,A % NumberOfRows, n, m, A % COMPLEX
3508
3509
Rows => A % Rows
3510
Cols => A % Cols
3511
Values => A % Values
3512
3513
PRINT *,pre,'A'//I2S(10*k+l)//' range',SUM( Values ), SUM( ABS( Values ) ), &
3514
MINVAL( Values ), MAXVAL( Values )
3515
3516
A => TotMatrix % SubMatrix(k,k) % PrecMat
3517
IF( .NOT. ASSOCIATED( A ) ) CYCLE
3518
IF( A % NumberOfRows == 0 ) CYCLE
3519
3520
Values => A % Values
3521
PRINT *,TRIM(pre),'B'//I2S(11*k)//' range',SUM( Values ), SUM( ABS( Values ) ), &
3522
MINVAL( Values ), MAXVAL( Values )
3523
END DO
3524
END DO
3525
3526
3527
DO k=1,NoVar
3528
PRINT *,'BlockInfo rhs:',k
3529
3530
A => TotMatrix % SubMatrix(k,k) % Mat
3531
IF( ASSOCIATED( A ) ) THEN
3532
b => A % rhs
3533
IF(ASSOCIATED(b)) THEN
3534
PRINT *,pre, 'A rhs range',k,SUM( b ), SUM( ABS( b ) ), &
3535
MINVAL( b ), MAXVAL( b )
3536
END IF
3537
END IF
3538
3539
b => TotMatrix % SubVector(k) % rhs
3540
IF(ASSOCIATED(b)) THEN
3541
PRINT *,pre,'b range',k,SUM( b ), SUM( ABS( b ) ), &
3542
MINVAL( b ), MAXVAL( b )
3543
END IF
3544
END DO
3545
3546
IF(isParallel) THEN
3547
DO k=1,NoVar
3548
PRINT *,'BlockInfo ParallelInfo'//I2S(k)
3549
3550
A => TotMatrix % SubMatrix(k,k) % Mat
3551
IF(.NOT. ASSOCIATED(A % ParallelInfo) ) THEN
3552
PRINT *,pre,'No ParallelInfo associated', k
3553
CYCLE
3554
END IF
3555
3556
n = A % NumberOfRows
3557
j = 0
3558
ll = 0
3559
IF( ASSOCIATED(A % ParallelInfo % NeighbourList ) ) THEN
3560
i = SIZE( A % ParallelInfo % NeighbourList)
3561
DO l=1,i
3562
j = j+SIZE(A % ParallelInfo % NeighbourList(l) % Neighbours)
3563
ll = ll+SUM(A % ParallelInfo % NeighbourList(l) % Neighbours)
3564
END DO
3565
PRINT *,pre,'BlockInfo NeighbourList:',n,i,j,ll
3566
END IF
3567
IF( ASSOCIATED(A % ParallelInfo % GInterface) ) THEN
3568
i = SIZE( A % ParallelInfo % Ginterface)
3569
j = COUNT(A % ParallelInfo % GInterface)
3570
PRINT *,pre,'BlockInfo GInterface', n,i,j
3571
END IF
3572
IF( ASSOCIATED(A % ParallelInfo % GlobalDOFs) ) THEN
3573
i = SIZE( A % ParallelInfo % GlobalDOFs)
3574
ll = SUM(A % ParallelInfo % GlobalDOFs)
3575
PRINT *,pre,'BlockInfo GlobalDofs', n,i,ll
3576
END IF
3577
3578
END DO
3579
END IF
3580
3581
END SUBROUTINE BlockMatrixInfo
3582
!------------------------------------------------------------------------------
3583
3584
3585
3586
3587
!> Performs the actual forward or reverse scaling. Optionally the scaling may be
3588
!> applied to only one matrix with an optional r.h.s. The idea is that for
3589
!> block preconditioning we may revert to the original symmetric matrix but
3590
!> still use the optimal row equilibration scaling for the block system.
3591
!------------------------------------------------------------------------------
3592
SUBROUTINE DoBlockMatrixScaling( reverse, blockrow, blockcol, bext, SkipMatrixScale )
3593
!------------------------------------------------------------------------------
3594
IMPLICIT NONE
3595
LOGICAL, OPTIONAL :: reverse
3596
INTEGER, OPTIONAL :: blockrow, blockcol
3597
REAL(KIND=dp), POINTER, OPTIONAL :: bext(:)
3598
LOGICAL, OPTIONAL :: SkipMatrixScale
3599
3600
INTEGER :: i,j,k,l,n,m,NoVar
3601
REAL(KIND=dp) :: nrm, tmp
3602
TYPE(Matrix_t), POINTER :: A
3603
REAL(KIND=dp), POINTER :: b(:), Diag(:), Values(:)
3604
INTEGER, POINTER :: Rows(:), Cols(:)
3605
LOGICAL :: backscale
3606
CHARACTER(*), PARAMETER :: Caller = 'DoBlockMatrixScaling'
3607
3608
IF( PRESENT( Reverse ) ) THEN
3609
BackScale = Reverse
3610
ELSE
3611
BackScale = .FALSE.
3612
END IF
3613
IF( BackScale ) THEN
3614
Message = 'Performing block matrix reverse row equilibration'
3615
ELSE
3616
Message = 'Performing block matrix row equilibration'
3617
END IF
3618
IF(PRESENT(blockrow)) THEN
3619
Message = TRIM(Message)//' for block '//I2S(blockrow)
3620
END IF
3621
CALL Info(Caller,Message,Level=12)
3622
3623
NoVar = TotMatrix % NoVar
3624
DO k=1,NoVar
3625
3626
IF( PRESENT( blockrow ) ) THEN
3627
IF( blockrow /= k ) CYCLE
3628
END IF
3629
3630
Diag => TotMatrix % SubVector(k) % DiagScaling
3631
IF( .NOT. ASSOCIATED( Diag ) ) THEN
3632
CALL Fatal(Caller,'Diag for scaling not associated!')
3633
END IF
3634
3635
IF( BackScale ) Diag = 1.0_dp / Diag
3636
3637
DO l=1,NoVar
3638
3639
IF( PRESENT( blockcol ) ) THEN
3640
IF( blockcol /= l ) CYCLE
3641
END IF
3642
3643
! If we use unscaled special preconditioning matrix we don't need to scale it
3644
IF( PRESENT( SkipMatrixScale ) ) THEN
3645
IF( SkipMatrixScale ) THEN
3646
CALL Info(Caller,'Skipping preconditioning matrix for block '//I2S(l),Level=20)
3647
CYCLE
3648
END IF
3649
END IF
3650
3651
A => TotMatrix % SubMatrix(k,l) % Mat
3652
n = A % NumberOfRows
3653
IF( n == 0 ) CYCLE
3654
3655
Rows => A % Rows
3656
Cols => A % Cols
3657
Values => A % Values
3658
3659
DO i=1,n
3660
DO j=Rows(i),Rows(i+1)-1
3661
Values(j) = Values(j) * Diag(i)
3662
END DO
3663
END DO
3664
3665
#if 0
3666
! This does not seem to be necessary but actually harmfull.
3667
A => TotMatrix % SubMatrix(k,l) % PrecMat
3668
IF( A % NumberOfRows == 0 ) CYCLE
3669
DO i=1,n
3670
DO j=A % Rows(i),A % Rows(i+1)-1
3671
A % Values(j) = A % Values(j) * Diag(i)
3672
END DO
3673
END DO
3674
#endif
3675
END DO
3676
3677
IF( PRESENT( bext ) ) THEN
3678
b => bext
3679
ELSE
3680
b => TotMatrix % Submatrix(k,k) % Mat % Rhs
3681
END IF
3682
3683
IF( ASSOCIATED( b ) ) THEN
3684
n = SIZE(Diag)
3685
b(1:n) = Diag(1:n) * b(1:n)
3686
END IF
3687
3688
IF( BackScale ) Diag = 1.0_dp / Diag
3689
END DO
3690
3691
IF( BackScale ) THEN
3692
CALL Info(Caller,'Finished block matrix reverse row equilibration',Level=25)
3693
ELSE
3694
CALL Info(Caller,'Finished block matrix row equilibration',Level=25)
3695
END IF
3696
3697
END SUBROUTINE DoBlockMatrixScaling
3698
!------------------------------------------------------------------------------
3699
3700
3701
!> Deallocates the block matrix scaling vectors.
3702
!------------------------------------------------------------------------------
3703
SUBROUTINE DestroyBlockMatrixScaling()
3704
!------------------------------------------------------------------------------
3705
INTEGER :: k,NoVar
3706
3707
CALL Info('DestroyBlockMatrixScaling','Deallocating the vectors for block system scaling',Level=10)
3708
3709
NoVar = TotMatrix % NoVar
3710
DO k=1,NoVar
3711
IF( ALLOCATED( TotMatrix % SubVector(k) % DiagScaling ) ) THEN
3712
DEALLOCATE( TotMatrix % SubVector(k) % DiagScaling )
3713
END IF
3714
END DO
3715
3716
END SUBROUTINE DestroyBlockMatrixScaling
3717
!------------------------------------------------------------------------------
3718
3719
3720
3721
!------------------------------------------------------------------------------
3722
!> Perform block preconditioning for Au=v by solving all the individual diagonal problems.
3723
!> Has to be called outside the module by Krylov methods.
3724
!------------------------------------------------------------------------------
3725
SUBROUTINE BlockMatrixPrec( u,v,ipar )
3726
IMPLICIT NONE
3727
REAL(KIND=dp), TARGET, INTENT(out) :: u(*)
3728
REAL(KIND=dp), TARGET, INTENT(in) :: v(*)
3729
INTEGER :: ipar(*)
3730
!---------------------------------------------------------------------------------
3731
REAL(KIND=dp), POINTER :: rtmp(:),vtmp(:),xtmp(:),btmp(:),diagtmp(:),b(:),x(:), a_rhs_save(:)
3732
REAL(KIND=dp), POINTER CONTIG :: rhs_save(:)
3733
INTEGER :: i,j,k,l,n,m,NoVar,nc,kk,ll,istat
3734
TYPE(Solver_t), POINTER :: Solver, Solver_save, ASolver
3735
INTEGER, POINTER :: Offset(:), BlockPerm(:),ParPerm(:)
3736
TYPE(ValueList_t), POINTER :: Params
3737
INTEGER, POINTER :: BlockOrder(:)
3738
TYPE(Matrix_t), POINTER :: A, Aij, mat_save
3739
TYPE(Variable_t), POINTER :: Var, Var_save
3740
REAL(KIND=dp) :: nrm
3741
LOGICAL :: GotOrder, BlockGS, Found, NS, ScaleSystem, DoSum, &
3742
IsComplex, BlockScaling, DoDiagScaling, DoPrecScaling, UsePrecMat, &
3743
Isolated, NoNestedScaling, DoAMGXmv, CalcLoads, BlockSch
3744
CHARACTER(:), ALLOCATABLE :: str
3745
INTEGER(KIND=AddrInt) :: AddrFunc
3746
EXTERNAL :: AddrFunc
3747
3748
CALL Info('BlockMatrixPrec','Starting block matrix preconditioning',Level=8)
3749
3750
DoAMGXMV = ListGetLogical( SolverRef % Values, 'Block AMGX M-V', Found)
3751
3752
n = ipar(3)
3753
3754
IF( InfoActive(25) ) THEN
3755
nrm = CompNorm(v(1:n),n)
3756
WRITE( Message,'(A,ES12.5)') 'V start norm: ',nrm
3757
CALL Info('BlockMatrixPrec',Message,Level=10)
3758
END IF
3759
3760
Solver => CurrentModel % Solver
3761
Params => Solver % Values
3762
3763
NoVar = TotMatrix % NoVar
3764
Solver => TotMatrix % Solver
3765
3766
TotMatrix % NoIters = TotMatrix % NoIters + 1
3767
3768
3769
! Enable user defined order for the solution of blocks
3770
!---------------------------------------------------------------
3771
BlockOrder => ListGetIntegerArray( Params,'Block Order',GotOrder)
3772
IF(GotOrder) THEN
3773
IF(SIZE(BlockOrder) /= NoVar) THEN
3774
CALL Fatal('BlockMatrixPrec','Block Order size should be '//I2S(NoVar))
3775
END IF
3776
END IF
3777
3778
BlockGS = ListGetLogical( Params,'Block Gauss-Seidel',Found)
3779
BlockSch = ListGetLogical( Params,'Block Schur',Found)
3780
3781
3782
3783
IF( isParallel ) THEN
3784
offset => TotMatrix % ParOffset
3785
ELSE
3786
offset => TotMatrix % Offset
3787
END IF
3788
3789
IF( n /= Offset(NoVar+1) ) THEN
3790
CALL Warn('BlockMatrixPrec','There is a mismatch between sizes: '&
3791
//I2S(n)//' vs. '//I2S(Offset(NoVar+1)))
3792
END IF
3793
3794
! Save the initial solver stuff
3795
solver_save => Solver
3796
var_save => Solver % Variable
3797
mat_save => Solver % Matrix
3798
rhs_save => Solver % Matrix % RHS
3799
3800
BlockScaling = ListGetLogical( Params,'Block Scaling',Found )
3801
3802
DoDiagScaling = .FALSE.
3803
IF( ASSOCIATED( Solver % Matrix ) ) THEN
3804
DoDiagScaling = ASSOCIATED( Solver % Matrix % diagscaling )
3805
END IF
3806
IF( DoDiagScaling ) THEN
3807
CALL Info('BlockMatrixPrec','External diagonal scaling is active!',Level=20)
3808
ELSE
3809
CALL Info('BlockMatrixPrec','External diagonal scaling is not active!',Level=30)
3810
END IF
3811
IF( BlockScaling ) THEN
3812
CALL Info('BlockMatrixPrec','Block matrix scaling is active!',Level=20)
3813
ELSE
3814
CALL Info('BlockMatrixPrec','Block matrix scaling is not active!',Level=30)
3815
END IF
3816
3817
IF(DoDiagscaling) THEN
3818
NoNestedScaling = ListGetLogical( Params,'Eliminate Nested Scaling',Found )
3819
IF(.NOT. Found) NoNestedScaling = .TRUE.
3820
ELSE
3821
NoNestedScaling = .FALSE.
3822
END IF
3823
3824
! Always treat the inner iterations as truly complex if they are
3825
CALL ListAddLogical( Params,'Linear System Skip Complex',.FALSE.)
3826
CALL ListAddLogical( Params,'Linear System Skip Loads',.TRUE.)
3827
3828
IF (isParallel) THEN
3829
ALLOCATE( x(TotMatrix % MaxSize), b(TotMatrix % MaxSize) )
3830
END IF
3831
3832
! Initial guess:
3833
!-----------------------------------------
3834
u(1:n) = 0.0_dp
3835
3836
BlockSch = ListCheckPrefix( Params,'Schur Operator' )
3837
3838
IF( BlockGS .OR. BlockSch ) THEN
3839
ALLOCATE( vtmp(n), rtmp(n), xtmp(n),STAT=istat)
3840
IF ( istat /= 0 ) CALL Fatal('BlockMatrixPrec','Memory allocation error for wrk space!')
3841
vtmp(1:n) = v(1:n)
3842
END IF
3843
3844
CALL ListPushNameSpace('block:')
3845
3846
DO j=1,NoVar
3847
IF( GotOrder ) THEN
3848
i = BlockOrder(j)
3849
ELSE
3850
i = j
3851
END IF
3852
3853
WRITE(Message,'(A,I0)') 'Solving block: ',i
3854
CALL Info('BlockMatrixPrec',Message,Level=8)
3855
3856
IF ( ListGetLogical( Solver % Values, 'Dymmy block '//I2S(i), Found) ) THEN
3857
u(offset(i)+1:offset(i+1)) = v(offset(i)+1:offset(i+1)); cycle
3858
end if
3859
3860
! We do probably not want to compute the change within each iteration
3861
CALL ListAddLogical( Params,'Skip Advance Nonlinear iter',.TRUE.)
3862
CALL ListAddLogical( Params,'Skip Compute Nonlinear Change',.TRUE.)
3863
3864
3865
! Set pointers to the new linear system
3866
!-------------------------------------------------------------------
3867
Var => TotMatrix % SubVector(i) % Var
3868
3869
UsePrecMat = .FALSE.
3870
IF( ASSOCIATED( TotMatrix % Subvector(i) % Solver ) ) THEN
3871
ASolver => TotMatrix % SubVector(i) % Solver
3872
A => ASolver % Matrix
3873
ELSE
3874
A => TotMatrix % Submatrix(i,i) % PrecMat
3875
IF( A % NumberOfRows == 0 ) THEN
3876
A => TotMatrix % Submatrix(i,i) % Mat
3877
ELSE
3878
UsePrecMat = .TRUE.
3879
CALL Info('BlockMatrixPrec','Using specialized (Schur) preconditioning block',Level=9)
3880
END IF
3881
ASolver => Solver
3882
END IF
3883
3884
IF ( A % NumberOfRows == 0 ) CYCLE
3885
3886
IF (isParallel) THEN
3887
! copy part of full solution to block solution
3888
x = 0.0_dp
3889
b = 0.0_dp
3890
ParPerm => TotMatrix % Submatrix(i,i) % ParPerm
3891
x(ParPerm) = u(offset(i)+1:offset(i+1))
3892
IF( BlockGS ) THEN
3893
b(ParPerm) = vtmp(offset(i)+1:offset(i+1))
3894
ELSE
3895
b(ParPerm) = v(offset(i)+1:offset(i+1))
3896
END IF
3897
ELSE
3898
x => u(offset(i)+1:offset(i+1))
3899
IF( BlockGS ) THEN
3900
b => vtmp(offset(i)+1:offset(i+1))
3901
ELSE
3902
b => v(offset(i)+1:offset(i+1))
3903
END IF
3904
END IF
3905
3906
IF( InfoActive(25) ) THEN
3907
! l is uninitialized!
3908
!nrm = CompNorm(b,offset(i+1)-offset(i),npar=l)
3909
nrm = CompNorm(b,offset(i+1)-offset(i))
3910
WRITE( Message,'(A,ES12.5)') 'Rhs '//I2S(i)//' norm: ',nrm
3911
CALL Info('BlockMatrixPrec',Message,Level=10)
3912
END IF
3913
3914
! Reuse block preconditioner from the first block to other components
3915
!--------------------------------------------------------------------
3916
IF( ListGetLogical( Params,'Block Prec Reuse',Found) ) THEN
3917
DO k = 1, NoVar
3918
IF( k == i ) CYCLE
3919
IF( CRS_CopyMatrixPrec( TotMatrix % Submatrix(k,k) % Mat, A ) ) EXIT
3920
END DO
3921
END IF
3922
3923
IF( BlockScaling ) CALL DoBlockMatrixScaling(.TRUE.,i,i,b,UsePrecMat)
3924
3925
! The special preconditioning matrices have not been scaled with the monolithic system.
3926
! So we need to transfer the (x,b) of this block to the unscaled system before going
3927
! to solve it. It is probably desirable to use separate scaling for this system.
3928
DoPrecScaling = DoDiagScaling .AND. UsePrecMat
3929
IF( DoPrecScaling ) THEN
3930
n = A % NumberOfRows
3931
ALLOCATE( btmp(n), diagtmp(n), STAT=istat)
3932
IF ( istat /= 0 ) CALL Fatal('BlockMatrixPrec',&
3933
'Memory allocation error for scaling wrk space!')
3934
3935
IF( TotMatrix % GotBlockStruct ) THEN
3936
k = TotMatrix % InvBlockStruct(i)
3937
IF( k <= 0 ) THEN
3938
CALL Fatal('BlockMatrixPrec','Cannot define the originating block '&
3939
//I2S(i)//' for scaling!')
3940
ELSE
3941
CALL Info('BlockMatrixPrec','Using initial block '//I2S(k)//&
3942
' in scaling of prec matrix '//I2S(i),Level=12)
3943
END IF
3944
ELSE
3945
k = i
3946
END IF
3947
3948
l = Solver % Variable % DOFs
3949
diagtmp(1:n) = Solver % Matrix % DiagScaling(k::l)
3950
3951
! Scale x & b to the unscaled system of the tailored preconditioning matrix for given block.
3952
x(1:n) = x(1:n) * diagtmp(1:n) * Solver % Matrix % RhsScaling
3953
btmp(1:n) = b(1:n) / diagtmp(1:n) * Solver % Matrix % RhsScaling
3954
ELSE
3955
btmp => b
3956
IF( NoNestedScaling ) THEN
3957
CALL Info('BlockMatrixPrec','Eliminating scaling for block as outer scaling already done!',Level=25)
3958
CALL ListAddLogical( Params,'Linear System Skip Scaling',.TRUE.)
3959
END IF
3960
END IF
3961
3962
IF( InfoActive( 25 ) ) THEN
3963
CALL BlockMatrixInfo()
3964
END IF
3965
3966
IF( A % COMPLEX ) THEN
3967
nc = 2
3968
ELSE
3969
nc = 1
3970
END IF
3971
3972
k = ListGetInteger( Params,'Schur Operator '//I2S(i),Found )
3973
IF( k > 0 ) THEN
3974
CALL Info('BlockMatrixPrec','Perform Schur complement operation for block '//I2S(i), Level=7 )
3975
3976
! The residual is used only as a temporary vector
3977
!-------------------------------------------------------------
3978
Aij => TotMatrix % SubMatrix(i,k) % Mat
3979
IF( Aij % NumberOfRows == 0) CYCLE
3980
3981
! r = P^T b
3982
Aij => TotMatrix % Submatrix(k,i) % Mat
3983
IF( BlockGS ) THEN
3984
b => vtmp(offset(i)+1:offset(i+1))
3985
ELSE
3986
b => v(offset(i)+1:offset(i+1))
3987
END IF
3988
IF(DoAMGXMV) THEN
3989
CALL AMGXMatrixVectorMultiply(Aij,b,rtmp,SolverRef )
3990
ELSE
3991
CALL CRS_MatrixVectorMultiply(Aij,b,rtmp )
3992
END IF
3993
3994
! u = A^-1 r
3995
CALL ListPushNameSpace('block '//i2s(11*k)//':')
3996
3997
Aij => TotMatrix % Submatrix(k,k) % Mat
3998
Isolated = TotMatrix % SubMatrix(k,k) % ParallelIsolatedMatrix
3999
IF(DoAMGXMv) THEN
4000
ScaleSystem = ListGetLogical( Params,'Linear System Scaling', Found )
4001
IF(.NOT. Found) ScaleSystem = .TRUE.
4002
IF ( ScaleSystem ) CALL ScaleLinearSystem(ASolver, Aij,btmp,xtmp )
4003
CALL AMGXSolver( Aij, xtmp, btmp, ASolver )
4004
IF( ScaleSystem ) CALL BackScaleLinearSystem(ASolver,Aij,btmp,xtmp)
4005
ELSE
4006
CALL SolveLinearSystem( Aij, rtmp, xtmp, Var % Norm, Var % DOFs, ASolver )
4007
END IF
4008
4009
! x = -P u
4010
rtmp = 0.0_dp
4011
Aij => TotMatrix % Submatrix(i,k) % Mat
4012
IF(DoAMGXMV) THEN
4013
CALL AMGXMatrixVectorMultiply(Aij,xtmp,rtmp,SolverRef )
4014
ELSE
4015
CALL CRS_MatrixVectorMultiply(Aij,xtmp,rtmp )
4016
END IF
4017
4018
BLOCK
4019
REAL(KIND=dp) :: cmult
4020
cmult = ListGetCReal( Params,'Schur Multiplier '//I2S(i),Found, DefValue=1.0_dp )
4021
! Up-date the off-diagonal entries to the r.h.s.
4022
u(offset(i)+1:offset(i+1)) = u(offset(i)+1:offset(i+1)) &
4023
- cmult * rtmp(1:offset(i+1)-offset(i))
4024
END BLOCK
4025
CALL ListPopNameSpace() ! block ij:
4026
4027
CYCLE
4028
ELSE
4029
CALL ListPushNameSpace('block '//i2s(11*i)//':')
4030
4031
IF(DoAMGXMv) THEN
4032
ScaleSystem = ListGetLogical( Params,'Linear System Scaling', Found )
4033
IF(.NOT. Found) ScaleSystem = .TRUE.
4034
4035
IF ( ScaleSystem ) CALL ScaleLinearSystem(ASolver, A,btmp,x )
4036
CALL AMGXSolver( A, x, btmp, ASolver )
4037
IF( ScaleSystem ) CALL BackScaleLinearSystem(ASolver,A,btmp,x)
4038
ELSE
4039
CALL SolveLinearSystem( A, btmp, x, Var % Norm, Var % DOFs, ASolver )
4040
END IF
4041
END IF
4042
4043
! If this was a special preconditioning matrix then update the solution in the scaled system.
4044
IF( DoPrecScaling ) THEN
4045
x(1:n) = x(1:n) / diagtmp(1:n)
4046
DEALLOCATE( btmp, diagtmp )
4047
ELSE IF( NoNestedScaling ) THEN
4048
CALL ListAddLogical( Params,'Linear System Skip Scaling',.FALSE.)
4049
END IF
4050
4051
IF( InfoActive(20) ) THEN
4052
nrm = CompNorm(x,offset(i+1)-offset(i),A=A)
4053
WRITE( Message,'(A,ES12.5)') 'Linear system '//I2S(i)//' norm: ',nrm
4054
CALL Info('BlockMatrixPrec',Message)
4055
END IF
4056
4057
IF( BlockScaling ) CALL DoBlockMatrixScaling(.FALSE.,i,i,b,UsePrecMat)
4058
4059
IF (isParallel) THEN
4060
x(1:offset(i+1)-offset(i)) = x(ParPerm)
4061
u(offset(i)+1:offset(i+1)) = x(1:offset(i+1)-offset(i))
4062
END IF
4063
4064
!---------------------------------------------------------------------
4065
IF( BlockGS ) THEN
4066
CALL Info('BlockMatrixPrec','Updating block r.h.s',Level=9)
4067
4068
DO l=j+1,NoVar
4069
IF( GotOrder ) THEN
4070
k = BlockOrder(l)
4071
ELSE
4072
k = l
4073
END IF
4074
4075
str = 'Block Gauss-Seidel Passive '//I2S(k)//I2S(i)
4076
IF( ListGetLogical( Params, str, Found ) ) CYCLE
4077
4078
CALL Info('BlockMatrixPrec','Updating r.h.s for component '//I2S(k),Level=15)
4079
4080
! The residual is used only as a temporary vector
4081
!-------------------------------------------------------------
4082
Aij => TotMatrix % SubMatrix(k,i) % Mat
4083
4084
IF( Aij % NumberOfRows == 0) CYCLE
4085
Isolated = TotMatrix % SubMatrix(k,i) % ParallelIsolatedMatrix
4086
4087
IF (isParallel) THEN
4088
IF(ASSOCIATED(Aij % ParMatrix)) THEN
4089
! x is packed, r is full
4090
CALL ParallelMatrixVector(Aij,x,rtmp )
4091
4092
ELSE IF( Isolated ) THEN
4093
! If our matrix is not active on shared nodes we may apply serial Mv
4094
! and pack the results to include only the dofs owned by the partition.
4095
CALL CRS_MatrixVectorMultiply(Aij,x,rtmp)
4096
ParPerm => TotMatrix % Submatrix(i,i) % ParPerm
4097
4098
#if 0
4099
rtmp(1:offset(i+1)-offset(i)) = rtmp(ParPerm)
4100
#else
4101
ll = 0
4102
DO kk=1,A % NumberofRows
4103
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(kk) % Neighbours(1)) CYCLE
4104
ll = ll+1
4105
rtmp(ll) = rtmp(kk)
4106
IF(parperm(ll) /= kk) PRINT *,'Problem:',ll,kk,parperm(ll)
4107
END DO
4108
#endif
4109
4110
ELSE IF (ASSOCIATED(SolverMatrix)) THEN
4111
! Here we don't have the luxury that the block matrix would either have parallel
4112
! communication initiated, or not have interface dofs. The last resort is to use
4113
! the initial monolithic matrix to perform Mv also for a given block by setting
4114
! other dofs to zero.
4115
xtmp = 0.0_dp
4116
xtmp(offset(i)+1:offset(i+1)) = x(offset(i)+1:offset(i+1))
4117
4118
BlockPerm => TotMatrix % ParBlockPerm
4119
4120
xtmp(BlockPerm(1:n)) = xtmp(1:n)
4121
CALL ParallelMatrixVector(SolverMatrix,xtmp,rtmp)
4122
rtmp(1:n) = rtmp(BlockPerm(1:n))
4123
4124
rtmp(1:offset(k+1)-offset(k)) = rtmp(offset(k)+1:offset(k+1))
4125
4126
ELSE
4127
CALL Fatal('BlockMatrixPrec','Do not know how to apply parallel matrix!')
4128
END IF
4129
ELSE
4130
Aij => TotMatrix % Submatrix(k,i) % Mat
4131
IF(DoAMGXMV) THEN
4132
CALL AMGXMatrixVectorMultiply(Aij, x, rtmp, SolverRef )
4133
ELSE
4134
CALL CRS_MatrixVectorMultiply(Aij,x,rtmp )
4135
END IF
4136
END IF
4137
4138
! Up-date the off-diagonal entries to the r.h.s.
4139
vtmp(offset(k)+1:offset(k+1)) = vtmp(offset(k)+1:offset(k+1)) &
4140
- rtmp(1:offset(k+1)-offset(k))
4141
4142
END DO ! l=j+1,NoVar
4143
4144
END IF ! Gauss-Seidel
4145
4146
CALL ListPopNameSpace() ! block ij:
4147
4148
END DO ! j=1,NoVar
4149
4150
IF (isParallel) DEALLOCATE(x,b)
4151
4152
CALL ListPopNameSpace('block:') ! block:
4153
4154
CALL ListAddLogical( Params,'Linear System Refactorize',.FALSE. )
4155
CALL ListAddLogical( Params,'Skip Advance Nonlinear iter',.FALSE.)
4156
CALL ListAddLogical( Params,'Skip Compute Nonlinear Change',.FALSE.)
4157
CALL ListAddLogical( Params,'Linear System Skip Loads',.FALSE.)
4158
4159
Solver => Solver_save
4160
Solver % Matrix => mat_save
4161
Solver % Matrix % RHS => rhs_save
4162
Solver % Variable => Var_save
4163
4164
IF( BlockGS .OR. BlockSch ) THEN
4165
DEALLOCATE( vtmp, rtmp, xtmp )
4166
END IF
4167
4168
IF( InfoActive(20) ) THEN
4169
nrm = CompNorm(v(1:n),n)
4170
WRITE( Message,'(A,ES12.5)') 'V fin norm: ',nrm
4171
CALL Info('BlockMatrixPrec',Message,Level=10)
4172
4173
nrm = CompNorm(u(1:n),n)
4174
WRITE( Message,'(A,ES12.5)') 'U fin norm: ',nrm
4175
CALL Info('BlockMatrixPrec',Message,Level=10)
4176
END IF
4177
4178
CALL Info('BlockMatrixPrec','Finished block matrix preconditioning',Level=8)
4179
4180
END SUBROUTINE BlockMatrixPrec
4181
4182
4183
4184
!> This call takes care of Jacobi & Gauss Seidel block methods.
4185
!-----------------------------------------------------------------
4186
SUBROUTINE BlockStandardIter( Solver, MaxChange )
4187
4188
TYPE(Solver_t) :: Solver
4189
REAL(KIND=dp) :: MaxChange
4190
4191
INTEGER :: i,j,NoVar,RowVar,iter,LinIter,MinIter
4192
INTEGER, POINTER :: BlockOrder(:)
4193
LOGICAL :: GotIt, GotBlockOrder, BlockGS
4194
REAL(KIND=dp), POINTER CONTIG :: rhs_save(:), b(:)
4195
REAL(KIND=dp), POINTER :: dx(:)
4196
TYPE(Matrix_t), POINTER :: A, mat_save
4197
TYPE(Variable_t), POINTER :: Var, SolverVar
4198
REAL(KIND=dp) :: LinTol, TotNorm, dxnorm, xnorm, Relax
4199
TYPE(ValueList_t), POINTER :: Params
4200
LOGICAL :: ScaleSystem, BlockScaling, Found
4201
4202
NoVar = TotMatrix % NoVar
4203
Params => Solver % Values
4204
SolverVar => Solver % Variable
4205
4206
BlockGS = ListGetLogical( Params,'Block Gauss-Seidel',Found)
4207
BlockOrder => ListGetIntegerArray( Params,'Block Order',GotBlockOrder)
4208
LinIter = ListGetInteger( Params,'Linear System Max Iterations',GotIt)
4209
MinIter = ListGetInteger( Params,'Linear System Min Iterations',GotIt)
4210
LinTol = ListGetConstReal( Params,'Linear System Convergence Tolerance',GotIt)
4211
BlockScaling = ListGetLogical( Params,'Block Scaling',GotIt)
4212
4213
CALL ListPushNamespace('block:')
4214
4215
! We don't want compute change externally
4216
CALL ListAddNewLogical( Params,'Skip compute nonlinear change',.TRUE.)
4217
4218
Relax = 1.0_dp
4219
4220
DO iter = 1, LinIter
4221
4222
! Store the iteration count
4223
TotMatrix % NoIters = iter
4224
4225
! In block Jacobi the r.h.s. is not updated during the iteration cycle
4226
!----------------------------------------------------------------------
4227
IF( BlockGS ) THEN
4228
WRITE( Message,'(A,I0)') 'Block Gauss-Seidel iteration: ',iter
4229
ELSE
4230
WRITE( Message,'(A,I0)') 'Block Jacobi iteration: ',iter
4231
CALL BlockUpdateRhs(TotMatrix)
4232
END IF
4233
CALL Info('BlockStandardIter',Message,Level=5)
4234
MaxChange = 0.0_dp
4235
TotNorm = 0.0_dp
4236
4237
IF( iter == 2 ) THEN
4238
CALL ListAddLogical( Params,'No Precondition Recompute',.TRUE.)
4239
END IF
4240
4241
DO i=1,NoVar
4242
IF( GotBlockOrder ) THEN
4243
RowVar = BlockOrder(i)
4244
ELSE
4245
RowVar = i
4246
END IF
4247
4248
! In gauss-seidel the partial update is immediately taken into account
4249
!---------------------------------------------------------------------
4250
IF( BlockGS ) THEN
4251
CALL BlockUpdateRhs(TotMatrix,RowVar)
4252
END IF
4253
4254
IF( ListGetLogical( Params,'Block Prec Reuse',GotIt) ) THEN
4255
DO j = 1, NoVar
4256
IF( j == RowVar ) CYCLE
4257
IF( CRS_CopyMatrixPrec( TotMatrix % Submatrix(j,j) % Mat, A ) ) EXIT
4258
END DO
4259
END IF
4260
4261
b => TotMatrix % SubVector(RowVar) % rhs
4262
4263
IF( InfoActive( 15 ) ) THEN
4264
PRINT *,'rhs'//I2S(i)//':',SQRT( SUM(b**2) ), MINVAL( b ), MAXVAL( b ), SUM( b )
4265
END IF
4266
4267
Var => TotMatrix % SubVector(RowVar) % Var
4268
Solver % Variable => Var
4269
4270
A => TotMatrix % Submatrix(i,i) % PrecMat
4271
IF( A % NumberOfRows == 0 ) THEN
4272
A => TotMatrix % Submatrix(i,i) % Mat
4273
ELSE
4274
CALL Info('BlockStandardIter','Using preconditioning block: '//I2S(i),Level=8)
4275
END IF
4276
4277
!Solver % Matrix => A
4278
4279
! Use the newly computed residual rather than original r.h.s. to solve the equation!!
4280
rhs_save => A % rhs ! Solver % Matrix % RHS
4281
A % RHS => b
4282
4283
! Solving the subsystem
4284
!-----------------------------------
4285
ALLOCATE( dx( SIZE( Var % Values ) ) )
4286
dx = 0.0_dp
4287
4288
CALL ListPushNamespace('block '//i2s(11*RowVar)//':')
4289
4290
IF( BlockScaling ) CALL DoBlockMatrixScaling(.TRUE.,i,i,b)
4291
4292
!IF( ListGetLogical( Solver % Values,'Linear System Complex', Found ) ) A % Complex = .TRUE.
4293
4294
!ScaleSystem = ListGetLogical( Solver % Values,'block: Linear System Scaling', Found )
4295
!IF(.NOT. Found) ScaleSystem = .TRUE.
4296
4297
4298
CALL SolveLinearSystem( A, b, dx, Var % Norm, Var % DOFs, Solver )
4299
4300
IF( BlockScaling ) CALL DoBlockMatrixScaling(.FALSE.,i,i,b)
4301
4302
CALL ListPopNamespace()
4303
4304
! Revert back to original r.h.s.
4305
A % RHS => rhs_save
4306
!Solver % Matrix => mat_save
4307
4308
IF( iter > 1 ) THEN
4309
Var % Values = Var % Values + Relax * dx
4310
ELSE
4311
Var % Values = Var % Values + dx
4312
END IF
4313
4314
dxnorm = CompNorm(dx,A % NumberOfRows, A=A)
4315
xnorm = CompNorm(Var % Values, A % NumberOfRows, A=A)
4316
4317
Var % Norm = xnorm
4318
Var % NonlinChange = dxnorm / xnorm
4319
4320
WRITE(Message,'(A,2ES12.3)') 'Block '//I2S(RowVar)//' norms: ',xnorm, dxnorm / xnorm
4321
CALL Info('BlockStandardIter',Message,Level=5)
4322
4323
IF( InfoActive( 20 ) ) THEN
4324
PRINT *,'dx'//I2S(i)//':',SQRT( SUM(dx**2) ), MINVAL( dx ), MAXVAL( dx ), SUM( dx ), SUM( ABS( dx ) )
4325
END IF
4326
4327
DEALLOCATE( dx )
4328
4329
TotNorm = TotNorm + Var % Norm
4330
MaxChange = MAX( MaxChange, Var % NonlinChange )
4331
END DO
4332
4333
WRITE(Message,'(A,2ES12.3)') 'Sum of norms: ',TotNorm, MaxChange
4334
CALL Info('BlockStandardIter',Message,Level=4)
4335
4336
IF( MaxChange < LinTol .AND. iter >= MinIter ) THEN
4337
CALL Info('BlockStandardIter','Converged after iterations: '//I2S(iter),Level=5)
4338
EXIT
4339
END IF
4340
4341
END DO
4342
CALL ListPopNamespace('block:')
4343
4344
CALL ListAddLogical( Params,'No Precondition Recompute',.FALSE.)
4345
4346
Solver % Variable => SolverVar
4347
4348
END SUBROUTINE BlockStandardIter
4349
4350
4351
!---------------------------------------------------------------------------
4352
!> This call takes care of the iterative Krylov methods for block systems
4353
!> which can still be preconditioned by block Jacobi or Gauss-Seidel methods
4354
!---------------------------------------------------------------------------
4355
SUBROUTINE BlockKrylovIter( Solver, MaxChange )
4356
4357
TYPE(Solver_t) :: Solver
4358
REAL(KIND=dp) :: MaxChange
4359
4360
INTEGER(KIND=AddrInt) :: AddrFunc
4361
EXTERNAL :: AddrFunc
4362
INTEGER(KIND=AddrInt) :: iterProc,precProc, mvProc,dotProc,nmrProc, zero=0
4363
REAL(KIND=dp) :: dpar(20), xnorm,prevxnorm
4364
REAL(KIND=dp), ALLOCATABLE :: x(:),b(:),r(:)
4365
4366
TYPE(Matrix_t), POINTER :: A
4367
TYPE(Variable_t), POINTER :: SVar
4368
TYPE(ValueList_t), POINTER :: Params
4369
INTEGER :: NoVar, ndim, maxsize
4370
LOGICAL :: Converged, Diverged
4371
INTEGER :: Rounds, OutputInterval, PolynomialDegree
4372
INTEGER, POINTER :: Offset(:),poffset(:),BlockStruct(:),ParPerm(:)
4373
INTEGER :: i,j,k,l,ia,ib,istat
4374
LOGICAL :: LS, BlockAV,Found, UseMono
4375
CHARACTER(:), ALLOCATABLE :: VarName
4376
CHARACTER(*), PARAMETER :: Caller = 'BlockKrylovIter'
4377
4378
4379
CALL Info(Caller,'Starting block system iteration',Level=8)
4380
4381
!CALL ListPushNameSpace('outer:')
4382
Params => Solver % Values
4383
4384
BlockAV = ListGetLogical(Params,'Block A-V System', Found)
4385
4386
ndim = TotMatrix % TotSize
4387
NoVar = TotMatrix % NoVar
4388
4389
TotMatrix % NoIters = 0
4390
4391
isParallel = (ParEnv % PEs > 1)
4392
offset => TotMatrix % Offset
4393
IF(isParallel) THEN
4394
poffset => TotMatrix % ParOffset
4395
ELSE
4396
poffset => offset
4397
END IF
4398
4399
! Just do some error checks
4400
DO i=1,NoVar
4401
IF( .NOT. ASSOCIATED( TotMatrix % Subvector(i) % Var ) ) THEN
4402
CALL Fatal(Caller,'Subvector '//I2S(i)//' not associated!')
4403
END IF
4404
A => TotMatrix % SubMatrix(i,i) % Mat
4405
IF( .NOT. ASSOCIATED( A ) ) THEN
4406
CALL Fatal(Caller,'Submatrix '//I2S(11*i)//' not associated!')
4407
END IF
4408
IF( .NOT. ASSOCIATED( A % Rhs ) ) THEN
4409
CALL Warn(Caller,'Submatrix rhs '//I2S(11*i)//' not associated!')
4410
END IF
4411
END DO
4412
4413
CALL Info(Caller,'Allocating temporal vectors for block system of size: '&
4414
//I2S(ndim),Level=15)
4415
4416
ALLOCATE(x(ndim), b(ndim),r(ndim),STAT=istat)
4417
IF( istat /= 0 ) THEN
4418
CALL Fatal(Caller,'Cannot allocate temporal vectors of size: '//I2S(ndim))
4419
END IF
4420
4421
x = 0.0_dp
4422
b = 0.0_dp
4423
r = 0.0_dp
4424
4425
IF (isParallel) THEN
4426
CALL Info(Caller,'Performing parallel initializations!',Level=18)
4427
DO i=1,NoVar
4428
A => TotMatrix % SubMatrix(i,i) % Mat
4429
! ParallelInitSolve expects full vectors
4430
CALL Info(Caller,'Initializing submatrix '//I2S(11*i),Level=20)
4431
IF (ASSOCIATED(A % ParMatrix % SplittedMatrix % InsideMatrix % PrecValues)) THEN
4432
IF (.NOT. ASSOCIATED(A % PrecValues)) &
4433
NULLIFY(A % ParMatrix % SplittedMatrix % InsideMatrix % PrecValues)
4434
END IF
4435
CALL ParallelInitSolve(A, TotMatrix % Subvector(i) % Var % Values, A % rhs, r )
4436
IF( ASSOCIATED(SolverMatrix)) THEN
4437
x(offset(i)+1:offset(i+1)) = TotMatrix % SubVector(i) % Var % Values
4438
IF(ASSOCIATED(A % rhs)) b(offset(i)+1:offset(i+1)) = A % rhs
4439
END IF
4440
CALL Info(Caller,'Done initializing submatrix '//I2S(11*i),Level=20)
4441
END DO
4442
DO i=1,NoVar
4443
DO j=1,NoVar
4444
A => TotMatrix % SubMatrix(i,j) % Mat
4445
IF(i==j) CYCLE
4446
CALL Info(Caller,'Initializing submatrix '//I2S(10*i+j),Level=20)
4447
IF(ASSOCIATED(A % ParMatrix)) CALL ParallelInitSolve(A,r,r,r)
4448
END DO
4449
END DO
4450
IF(ASSOCIATED(SolverMatrix)) THEN
4451
CALL Info(Caller,'Initializing SolverMatrix',Level=20)
4452
CALL ParallelInitSolve( SolverMatrix, x, b, r )
4453
x = 0.0_dp
4454
b = 0.0_dp
4455
END IF
4456
CALL Info(Caller,'Parallel initializations done!',Level=25)
4457
END IF
4458
4459
CALL Info(Caller,'Initializing monolithic system vectors',Level=18)
4460
4461
DO i=1,NoVar
4462
A => TotMatrix % SubMatrix(i,i) % Mat
4463
4464
IF (.NOT.isParallel) THEN
4465
x(offset(i)+1:offset(i+1)) = TotMatrix % SubVector(i) % Var % Values
4466
IF(ASSOCIATED(A % rhs)) b(offset(i)+1:offset(i+1)) = A % rhs
4467
4468
4469
4470
4471
4472
ELSE
4473
ParPerm => TotMatrix % SubMatrix(i,i) % ParPerm
4474
x(poffset(i)+1:poffset(i+1)) = TotMatrix % SubVector(i) % Var % Values(ParPerm)
4475
4476
! This is a little dirty as it uses internal stuff from the parallel structure directly.
4477
! However, only this r.h.s. vector seems to be up-to-date.
4478
IF(ASSOCIATED(A % rhs)) b(poffset(i)+1:poffset(i+1)) = A % rhs(ParPerm) !A % ParMatrix % SplittedMatrix % InsideMatrix % Rhs
4479
END IF
4480
END DO
4481
4482
! Parallel block system only solves for its own variables.
4483
IF (isParallel) THEN
4484
ndim = poffset(NoVar+1)
4485
END IF
4486
4487
!----------------------------------------------------------------------
4488
! Solve matrix equation solver with the redefined block matrix operations
4489
!----------------------------------------------------------------------
4490
CALL ListAddLogical(Params,'Linear System Free Factorization',.FALSE.)
4491
4492
precProc = AddrFunc(BlockMatrixPrec)
4493
4494
UseMono = ListGetLogical(Params,'Block MV Monolithic',Found )
4495
IF(isParallel .AND. .NOT. Found ) THEN
4496
! This is a little dangerous logic since it separates serial and parallel operation!
4497
UseMono = .NOT. ( ASSOCIATED(TotMatrix % SubMatrix(1,NoVar) % Mat % ParMatrix) .OR. &
4498
TotMatrix % SubMatrix(1,NoVar) % ParallelIsolatedMatrix )
4499
END IF
4500
4501
IF( UseMono ) THEN
4502
mvProc = AddrFunc(BlockMatrixVectorProdMono)
4503
ELSE
4504
mvProc = AddrFunc(BlockMatrixVectorProd)
4505
END IF
4506
4507
prevXnorm = CompNorm(b,ndim)
4508
WRITE( Message,'(A,ES12.5)') 'Rhs norm at start: ',PrevXnorm
4509
CALL Info(Caller,Message,Level=10)
4510
IF( PrevXNorm < EPSILON( PrevXNorm ) ) THEN
4511
CALL Warn(Caller,"With zero'ish r.h.s. it does not make sense to call the solver!")
4512
RETURN
4513
END IF
4514
4515
4516
prevXnorm = CompNorm(x,ndim)
4517
WRITE( Message,'(A,ES12.5)') 'Solution norm at start: ',PrevXnorm
4518
CALL Info(Caller,Message,Level=10)
4519
4520
CALL Info(Caller,'Start of blocks system iteration',Level=18)
4521
4522
! Always treat the block system as a real valued system and complex
4523
! arithmetics only at the inner level.
4524
CALL ListAddLogical( Params,'Linear System Skip Complex',.TRUE.)
4525
4526
IF(ASSOCIATED(SolverMatrix)) THEN
4527
A => SolverMatrix
4528
ELSE
4529
A => TotMatrix % SubMatrix(1,1) % Mat
4530
END IF
4531
4532
!IF( ListGetLogical( Solver % Values,'Linear System Complex', Found ) ) A % COMPLEX = .TRUE.
4533
4534
IF (isParallel) THEN
4535
! Note that at this stage we work with the packed vectors x and b
4536
A => A % ParMatrix % SplittedMatrix % InsideMatrix
4537
CALL IterSolver( A,x,b,&
4538
Solver,ndim=ndim,MatvecF=mvProc,PrecF=precProc,&
4539
DotF=AddrFunc(SParDotProd), NormF=AddrFunc(SParNorm))
4540
4541
DO i=1,NoVar
4542
TotMatrix % SubMatrix(i,i) % Mat % ParMatrix % SplittedMatrix % &
4543
TmpXvec = x(poffset(i)+1:poffset(i+1))
4544
END DO
4545
4546
! Communicate blockwise information.
4547
! After this the packed x is again a full vector with redundant shared dofs
4548
DO i=1,NoVar
4549
CALL ParallelUpdateResult(TotMatrix % SubMatrix(i,i) % Mat, &
4550
x(offset(i)+1:offset(i+1)), r )
4551
END DO
4552
ELSE
4553
IF( ListGetLogical( Params,'Linear System test',Found ) ) THEN
4554
CALL IterSolver( A,x,b,&
4555
Solver,ndim=ndim,MatvecF=mvProc,PrecF=precProc,&
4556
DotF=AddrFunc(PseudoZDotProd) )
4557
ELSE
4558
CALL IterSolver( A,x,b,&
4559
Solver,ndim=ndim,MatvecF=mvProc,PrecF=precProc)
4560
END IF
4561
END IF
4562
CALL info(Caller,'Finished block system iteration',Level=18)
4563
4564
CALL ListAddLogical(Params,'Linear System Refactorize',.TRUE.)
4565
CALL ListAddLogical(Params,'Linear System Free Factorization',.TRUE.)
4566
4567
!CALL ListPopNamespace()
4568
4569
Xnorm = CompNorm(x,ndim)
4570
WRITE( Message,'(A,ES12.5)') 'Solution norm: ',Xnorm
4571
CALL Info(Caller,Message,Level=8)
4572
4573
MaxChange = 2*ABS(Xnorm-PrevXnorm)/(Xnorm+PrevXnorm)
4574
PrevXNorm = Xnorm
4575
4576
WRITE( Message,'(A,ES12.5)') 'Relative change: ',MaxChange
4577
CALL Info(Caller,Message,Level=8)
4578
4579
DO i=1,NoVar
4580
TotMatrix % SubVector(i) % Var % Values(1:offset(i+1)-offset(i)) = &
4581
x(offset(i)+1:offset(i+1))
4582
END DO
4583
4584
! Copy values back since for nontrivial block-matrix structure the
4585
! components do not build the whole solution. If we have AddVector
4586
! then the last block will not be included.
4587
!-----------------------------------------------------------------
4588
IF( TotMatrix % GotBlockStruct ) THEN
4589
SVar => CurrentModel % Solver % Variable
4590
i = SIZE(SVar % Values)
4591
Svar % Values(TotMatrix % BlockPerm(1:i)) = x(1:i)
4592
ELSE IF (BlockAV ) THEN
4593
i = SIZE(SolverVar % Values)
4594
SolverVar % Values = x(1:i)
4595
END IF
4596
4597
j = SIZE(x)
4598
IF(j>i) THEN
4599
VarName = LagrangeMultiplierName( Solver )
4600
SVar => VariableGet( Solver % Mesh % Variables, VarName )
4601
IF(ASSOCIATED(SVar)) SVar % Values = x(i+1:j)
4602
END IF
4603
4604
CALL Info(Caller,'Finished block krylov iteration',Level=20)
4605
4606
END SUBROUTINE blockKrylovIter
4607
4608
4609
4610
!> This makes the system monolithic. If it was initially monolithic
4611
!> and then made block, it does not make any sense. However, for
4612
!> multiphysics coupled cases it may be a good strategy.
4613
!-----------------------------------------------------------------
4614
SUBROUTINE BlockMonolithicSolve( Solver, MaxChange )
4615
4616
TYPE(Solver_t) :: Solver
4617
REAL(KIND=dp) :: MaxChange
4618
4619
INTEGER :: i,j,k,m,n,nc,mc,c,NoVar,NoCol,NoRow,NoEigen,vdofs,comp
4620
INTEGER, POINTER :: BlockOrder(:)
4621
LOGICAL :: GotIt, DampedEigen
4622
REAL(KIND=dp), POINTER CONTIG :: rhs_save(:), b(:)
4623
REAL(KIND=dp), POINTER :: CollX(:), rhs(:)
4624
TYPE(Matrix_t), POINTER :: A, mat_save
4625
TYPE(Variable_t), POINTER :: Var, CompVar, SolverVar
4626
TYPE(Variable_t), TARGET :: MonolithicVar
4627
REAL(KIND=dp) :: TotNorm
4628
CHARACTER(:), ALLOCATABLE :: CompName
4629
TYPE(ValueList_t), POINTER :: Params
4630
TYPE(Matrix_t), POINTER :: CollMat
4631
LOGICAL :: Found, HaveMass, HaveDamp, SaveImag, Visited = .FALSE.
4632
CHARACTER(*), PARAMETER :: Caller = 'BlockMonolithicSolve'
4633
4634
SAVE Visited, CollMat, CollX, HaveMass, HaveDamp, SaveImag
4635
4636
CALL Info(Caller,'Solving block matrix as monolithic!',Level=6)
4637
4638
NoVar = TotMatrix % NoVar
4639
Params => Solver % Values
4640
SolverVar => Solver % Variable
4641
Solver % Variable => MonolithicVar
4642
4643
4644
IF(.NOT. Visited ) THEN
4645
n = 0
4646
m = 0
4647
4648
CollMat => AllocateMatrix()
4649
HaveMass = .FALSE.
4650
HaveDamp = .FALSE.
4651
4652
DO NoRow = 1,NoVar
4653
rhs => TotMatrix % SubVector(NoRow) % rhs
4654
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
4655
n = n + A % NumberOfRows
4656
4657
DO NoCol = 1,NoVar
4658
A => TotMatrix % SubMatrix( NoRow, NoCol ) % Mat
4659
IF(.NOT. ASSOCIATED(A) ) CYCLE
4660
IF(.NOT. ASSOCIATED(A % Values) ) CYCLE
4661
4662
IF(InfoActive(20)) THEN
4663
CALL VectorValuesRange(A % Values,SIZE(A % Values),&
4664
'A'//I2S(10*NoRow+NoCol),.TRUE.)
4665
IF( ASSOCIATED( A % MassValues ) ) THEN
4666
CALL VectorValuesRange(A % MassValues,SIZE(A % MassValues),&
4667
'M'//I2S(10*NoRow+NoCol),.TRUE.)
4668
END IF
4669
END IF
4670
4671
m = m + SIZE( A % Values )
4672
IF( ASSOCIATED( A % MassValues ) ) HaveMass = .TRUE.
4673
IF( ASSOCIATED( A % DampValues ) ) HaveDamp = .TRUE.
4674
END DO
4675
END DO
4676
4677
IF( HaveMass ) THEN
4678
DO NoRow = 1,NoVar
4679
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
4680
IF(.NOT. ASSOCIATED( A % MassValues ) ) THEN
4681
CALL Warn(Caller,'MassValues are missing for block: '//I2S(11*NoRow))
4682
END IF
4683
END DO
4684
CALL Info(Caller,'Treating MassValues of block matrix too!',Level=20)
4685
END IF
4686
4687
IF( HaveDamp ) THEN
4688
CALL Info(Caller,'Treating DampValues of block matrix too!',Level=20)
4689
END IF
4690
4691
NoEigen = Solver % NOFEigenValues
4692
4693
DampedEigen = ListGetLogical(Solver % Values,'Eigen System Complex',Found )
4694
IF( DampedEigen ) THEN
4695
CALL Info(Caller,'Creating complex system for eigen values!',Level=6)
4696
ELSE
4697
CALL Info(Caller,'Creating real valued system for eigen values!',Level=8)
4698
END IF
4699
4700
SaveImag = ListGetLogical(Solver % Values,'Pick Im Component',Found )
4701
4702
! The matrix sizes depend on whether we create a complex or real valued system.
4703
IF(DampedEigen) THEN
4704
nc = 2*n
4705
mc = 4*m
4706
ELSE
4707
nc = n
4708
mc = m
4709
END IF
4710
4711
4712
CollMat % NumberOfRows = nc
4713
CALL Info(Caller,'Size of monolithic matrix: '//I2S(nc),Level=7)
4714
CALL Info(Caller,'Estimated number of nonzeros in monolithic matrix: '//I2S(mc),Level=7)
4715
4716
ALLOCATE( CollMat % rhs(nc), CollMat % Diag(nc), CollMat % Rows(nc+1), CollX(nc) )
4717
CollMat % rhs = 0.0_dp
4718
CollMat % Diag = 0
4719
CollMat % Rows = 0
4720
CollX = 0.0_dp
4721
4722
CollMat % Complex = DampedEigen
4723
4724
ALLOCATE( CollMat % Values(mc), CollMat % Cols(mc+1) )
4725
CollMat % Values = 0.0_dp
4726
CollMat % Cols = 0
4727
4728
IF( HaveMass ) THEN
4729
ALLOCATE( CollMat % MassValues(mc) )
4730
CollMat % MassValues = 0.0_dp
4731
END IF
4732
IF( HaveDamp .AND. .NOT. DampedEigen ) THEN
4733
ALLOCATE( CollMat % DampValues(mc) )
4734
CollMat % DampValues = 0.0_dp
4735
END IF
4736
END IF
4737
4738
k = 0
4739
CollMat % Rows(1) = 1
4740
4741
4742
IF(DampedEigen) THEN
4743
DO NoRow = 1,NoVar
4744
n = TotMatrix % Offset(NoRow)
4745
4746
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
4747
m = A % NumberOfRows
4748
4749
DO i=1,m
4750
4751
! Loop over real and imaginary rows
4752
DO c=1,2
4753
4754
DO NoCol = 1,NoVar
4755
A => TotMatrix % SubMatrix( NoRow, NoCol ) % Mat
4756
IF( .NOT. ASSOCIATED( A ) ) CYCLE
4757
IF( .NOT. ASSOCIATED( A % Rows ) ) CYCLE
4758
4759
DO j=A % Rows(i),A % Rows(i+1)-1
4760
! If we have the imaginary row add the multiplier of imaginary value first
4761
IF( c == 2 ) THEN
4762
k = k + 1
4763
CollMat % Cols(k) = 2*TotMatrix % Offset(NoCol) + 2*A % Cols(j)-1
4764
IF( ASSOCIATED( A % DampValues) ) THEN
4765
CollMat % Values(k) = A % DampValues(j)
4766
END IF
4767
END IF
4768
4769
k = k + 1
4770
CollMat % Values(k) = A % Values(j)
4771
CollMat % Cols(k) = 2*TotMatrix % Offset(NoCol) + 2*(A % Cols(j)-1)+c
4772
IF( ASSOCIATED( A % MassValues ) ) THEN
4773
CollMat % MassValues(k) = A % MassValues(j)
4774
END IF
4775
4776
! If we have the real row add the multiplier of imaginary value last
4777
IF( c == 1 ) THEN
4778
k = k + 1
4779
CollMat % Cols(k) = 2*TotMatrix % Offset(NoCol) + 2*A % Cols(j)
4780
IF( ASSOCIATED( A % DampValues) ) THEN
4781
CollMat % Values(k) = -A % DampValues(j)
4782
END IF
4783
END IF
4784
END DO
4785
END DO
4786
IF(.NOT. Visited ) THEN
4787
CollMat % Rows(2*((n+i)-1)+c+1) = k+1
4788
END IF
4789
END DO
4790
END DO
4791
END DO
4792
4793
ELSE
4794
DO NoRow = 1,NoVar
4795
n = TotMatrix % Offset(NoRow)
4796
4797
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
4798
m = A % NumberOfRows
4799
4800
DO i=1,m
4801
DO NoCol = 1,NoVar
4802
A => TotMatrix % SubMatrix( NoRow, NoCol ) % Mat
4803
IF( .NOT. ASSOCIATED( A ) ) CYCLE
4804
IF( .NOT. ASSOCIATED( A % Rows ) ) CYCLE
4805
IF( SIZE(A % Rows) < i+1 ) CYCLE
4806
4807
DO j=A % Rows(i),A % Rows(i+1)-1
4808
k = k + 1
4809
CollMat % Values(k) = A % Values(j)
4810
IF(.NOT. Visited ) THEN
4811
CollMat % Cols(k) = TotMatrix % Offset(NoCol) + A % Cols(j)
4812
END IF
4813
IF( HaveMass ) THEN
4814
IF( ASSOCIATED( A % MassValues ) ) THEN
4815
CollMat % MassValues(k) = A % MassValues(j)
4816
END IF
4817
END IF
4818
IF( HaveDamp ) THEN
4819
IF( ASSOCIATED( A % DampValues ) ) THEN
4820
CollMat % DampValues(k) = A % DampValues(j)
4821
END IF
4822
END IF
4823
END DO
4824
IF( ASSOCIATED( A % rhs ) ) THEN
4825
CollMat % rhs(n+i) = A % rhs(i)
4826
END IF
4827
END DO
4828
IF(.NOT. Visited ) THEN
4829
CollMat % Rows(n+i+1) = k+1
4830
END IF
4831
END DO
4832
END DO
4833
END IF
4834
4835
4836
IF( ParEnv % PEs > 1 ) THEN
4837
IF( NoVar /= 2 ) THEN
4838
CALL Fatal(Caller,'Parallel operation currently assumes just 2x2 blocks!')
4839
END IF
4840
4841
CALL Info(Caller,'Merging parallel info of matrices')
4842
CALL ParallelMergeMatrix( Solver, CollMat, &
4843
TotMatrix % SubMatrix(1,1) % Mat, &
4844
TotMatrix % SubMatrix(2,2) % Mat )
4845
END IF
4846
4847
4848
IF(InfoActive(20)) THEN
4849
!CALL CRS_CheckSymmetricTopo(CollMat)
4850
!CALL CRS_CheckComplexTopo(CollMat)
4851
CALL VectorValuesRange(CollMat % Values,SIZE(CollMat % Values),'Atot',.TRUE.)
4852
IF( ASSOCIATED( CollMat % MassValues ) ) THEN
4853
CALL VectorValuesRange(CollMat % MassValues,SIZE(CollMat % MassValues),'Mtot',.TRUE.)
4854
END IF
4855
END IF
4856
4857
CALL Info(Caller,'True number of nonzeros in monolithic matrix: '//I2S(k),Level=7)
4858
4859
IF(.NOT. Visited ) THEN
4860
MonolithicVar % Name = '' ! Some name needed to avoid an uninitialised value error
4861
MonolithicVar % Values => CollX
4862
MonolithicVar % Dofs = 1
4863
MonolithicVar % Perm => NULL()
4864
4865
NoEigen = Solver % NOFEigenValues
4866
IF( NoEigen > 0 ) THEN
4867
n = CollMat % NumberOfRows
4868
ALLOCATE( MonolithicVar % EigenValues(NoEigen), MonolithicVar % EigenVectors(NoEigen,n) )
4869
MonolithicVar % EigenValues = 0.0_dp
4870
MonolithicVar % EigenVectors = 0.0_dp
4871
END IF
4872
Visited = .TRUE.
4873
END IF
4874
4875
IF(.NOT. DampedEigen) THEN
4876
CALL Info(Caller,'Copying block solution to monolithic vector',Level=12)
4877
DO i=1,NoVar
4878
Var => TotMatrix % SubVector(i) % Var
4879
n = SIZE( Var % Values )
4880
m = TotMatrix % Offset(i)
4881
CollX(m+1:m+n) = Var % Values(1:n)
4882
END DO
4883
END IF
4884
4885
4886
!IF( ListGetLogical( Solver % Values,'outer: Linear System Save',Found ) ) THEN
4887
! CALL SaveLinearSystem( Solver, CollMat,'CollMat')
4888
!END IF
4889
4890
! Solve monolithic matrix equation.
4891
CALL SolveLinearSystem( CollMat, CollMat % rhs, CollX, TotNorm, 1, Solver )
4892
4893
CALL Info(Caller,'Copying monolithic vector to block solutions',Level=12)
4894
4895
! Copy the 1st eigenmode because this will be used for norms etc.
4896
NoEigen = Solver % NOFEigenValues
4897
IF( NoEigen > 0 ) THEN
4898
MonolithicVar % Values = REAL( MonolithicVar % EigenVectors(1,:) )
4899
END IF
4900
4901
DO i=1,NoVar
4902
Var => TotMatrix % SubVector(i) % Var
4903
n = SIZE( Var % Values )
4904
m = TotMatrix % Offset(i)
4905
Var % Values(1:n) = CollX(m+1:m+n)
4906
4907
IF( NoEigen > 0 ) THEN
4908
IF(.NOT. ASSOCIATED( Var % EigenValues ) ) THEN
4909
IF( ASSOCIATED( Var % Solver ) ) THEN
4910
Var % Solver % NOFEigenValues = NoEigen
4911
END IF
4912
ALLOCATE( Var % EigenValues(NoEigen), Var % EigenVectors(NoEigen,n) )
4913
Var % EigenValues = 0.0_dp
4914
Var % EigenVectors = 0.0_dp
4915
4916
vdofs = Var % Dofs
4917
IF( vdofs > 1 ) THEN
4918
DO comp=1,vdofs
4919
CompName = ComponentName(Var % Name,comp)
4920
CompVar => VariableGet( Solver % Mesh % Variables, Compname )
4921
CompVar % EigenValues => Var % EigenValues
4922
CompVar % EigenVectors => Var % EigenVectors(:,comp::vdofs)
4923
END DO
4924
END IF
4925
END IF
4926
4927
DO k=1,NoEigen
4928
Var % EigenValues(k) = MonolithicVar % EigenValues(k)
4929
Var % EigenVectors(k,1:n) = MonolithicVar % EigenVectors(k,m+1:m+n)
4930
END DO
4931
4932
END IF
4933
END DO
4934
4935
Solver % Variable => SolverVar
4936
4937
END SUBROUTINE BlockMonolithicSolve
4938
4939
4940
!------------------------------------------------------------------------------
4941
!> An alternative handle for the block solvers to be used by the legacy matrix
4942
!> type.
4943
!------------------------------------------------------------------------------
4944
SUBROUTINE BlockSolveInt(A,x,b,Solver)
4945
!------------------------------------------------------------------------------
4946
TYPE(Matrix_t), POINTER :: A
4947
TYPE(Solver_t), TARGET :: Solver
4948
REAL(KIND=dp), TARGET :: x(:)
4949
REAL(KIND=dp), TARGET CONTIG :: b(:)
4950
!------------------------------------------------------------------------------
4951
TYPE(Solver_t), POINTER :: PSolver
4952
TYPE(Variable_t), POINTER :: Var
4953
INTEGER :: i,j,k,l,n
4954
LOGICAL :: GotIt, BlockPrec, BlockAV, &
4955
BlockHdiv, BlockReIm, BlockHcurl, BlockHorVer, BlockCart, BlockNodal, BlockDomain, &
4956
BlockDummy, BlockComplex, SkipPrec
4957
INTEGER :: ColVar, RowVar, NoVar, BlockDofs, VarDofs
4958
4959
REAL(KIND=dp) :: TotNorm, MaxChange
4960
REAL(KIND=dp), POINTER :: SaveValues(:)
4961
REAL(KIND=dp), POINTER CONTIG :: SaveRHS(:)
4962
LOGICAL :: BlockScaling, BlockMonolithic, Found
4963
INTEGER :: HaveConstraint, HaveAdd
4964
INTEGER, POINTER :: VarPerm(:)
4965
INTEGER, POINTER :: BlockPerm(:)
4966
INTEGER, POINTER :: SlaveSolvers(:)
4967
LOGICAL :: GotSlaveSolvers, DoMyOwnVars,OldMatrix
4968
4969
TYPE(Matrix_t), POINTER :: Amat, SaveCM
4970
TYPE(Mesh_t), POINTER :: Mesh
4971
TYPE(ValueList_t), POINTER :: Params
4972
4973
INTEGER, POINTER :: BlockIndex(:)
4974
4975
4976
CALL Info('BlockSolveInt','---------------------------------------',Level=5)
4977
4978
Params => Solver % Values
4979
Mesh => Solver % Mesh
4980
PSolver => Solver
4981
4982
SolverRef => Solver
4983
4984
isParallel = ParEnv % PEs > 1
4985
4986
OldMatrix = ASSOCIATED( Solver % BlockMatrix )
4987
IF( OldMatrix ) THEN
4988
CALL Info('BlockSolveInit','Using old block matrix structures!',Level=12)
4989
END IF
4990
4991
4992
! Determine some parameters related to the block strategy
4993
!------------------------------------------------------------------------------
4994
BlockPrec = ListGetLogical( Params,'Block Preconditioner',GotIt)
4995
IF(.NOT. GotIt) THEN
4996
CALL Info('BlockSolveInt','Using block preconditioning mode by default')
4997
BlockPrec = .TRUE.
4998
END IF
4999
5000
BlockMonolithic = ListGetLogical( Params,'Block Monolithic',GotIt)
5001
5002
BlockScaling = ListGetLogical( Params,'Block Scaling',GotIt)
5003
5004
! Different strategies on how to split the initial monolithic matrix into blocks
5005
BlockAV = ListGetLogical( Params,'Block A-V System', GotIt)
5006
BlockHcurl = ListGetLogical( Params,'Block Quadratic Hcurl System', GotIt)
5007
BlockHdiv = ListGetLogical( Params,'Block Hdiv system',GotIt)
5008
BlockReIm = ListGetLogical( Params,'Block Re-Im system',GotIt)
5009
BlockNodal = ListGetLogical( Params,'Block Nodal System', GotIt)
5010
BlockHorVer = ListGetLogical( Params,'Block Hor-Ver System', GotIt)
5011
BlockCart = ListGetLogical( Params,'Block Cartesian System', GotIt)
5012
BlockDomain = ListGetLogical( Params,'Block Domain System',GotIt)
5013
BlockDummy = ListGetLogical( Params,'Block Nested System',GotIt)
5014
BlockComplex = ListGetLogical( Params,'Block Complex System',GotIt)
5015
5016
5017
DoMyOwnVars = .FALSE.
5018
5019
IF( BlockDomain .OR. BlockHdiv .OR. BlockReIm .OR. BlockHcurl .OR. &
5020
BlockAV .OR. BlockHorVer .OR. BlockCart .OR. BlockNodal ) THEN
5021
! These take monolithic splitting and only return the "BlockIndex" which tells to which
5022
! block each dof belongs to. Then the same routine can split the matrices for all.
5023
!-----------------------------------------------------------------------------------------------
5024
n = SIZE( Solver % Variable % Values)
5025
ALLOCATE( BlockIndex(n) )
5026
BlockIndex = 0
5027
BlockDofs = 0
5028
DoMyOwnVars = .TRUE.
5029
5030
IF( BlockDomain ) THEN
5031
CALL BlockPickDofsPhysical( PSolver, BlockIndex, BlockDofs )
5032
ELSE IF( BlockHdiv ) THEN
5033
CALL BlockPickHdiv( PSolver, BlockIndex, BlockDofs )
5034
ELSE IF( BlockReIm ) THEN
5035
CALL BlockPickReIm( PSolver, BlockIndex, BlockDofs )
5036
ELSE IF( BlockHCurl ) THEN
5037
CALL BlockPickMatrixHcurl( PSolver, BlockDofs, BlockComplex, BlockIndex )
5038
ELSE IF( BlockAV ) THEN
5039
CALL BlockPickAV( PSolver, BlockIndex, BlockDofs )
5040
ELSE IF( BlockNodal ) THEN
5041
CALL BlockPickMatrixNodal( PSolver, BlockDofs, BlockComplex, BlockIndex )
5042
ELSE IF(BlockHorVer .OR. BlockCart) THEN
5043
CALL BlockPickMatrixHorVer( PSolver, BlockDofs, BlockCart, BlockIndex )
5044
END IF
5045
GotSlaveSolvers = .FALSE.
5046
ELSE
5047
SlaveSolvers => ListGetIntegerArray( Params, &
5048
'Block Solvers', GotSlaveSolvers )
5049
IF( GotSlaveSolvers ) THEN
5050
BlockDofs = SIZE( SlaveSolvers )
5051
ELSE IF( BlockDummy ) THEN
5052
BlockDofs = 1
5053
ELSE
5054
BlockDofs = Solver % Variable % Dofs
5055
END IF
5056
END IF
5057
5058
VarDofs = BlockDofs
5059
5060
5061
HaveConstraint = 0
5062
IF ( ASSOCIATED(A % ConstraintMatrix) ) HaveConstraint = 1
5063
HaveConstraint = ParallelReduction(HaveConstraint)
5064
5065
HaveAdd = 0
5066
IF ( ASSOCIATED(A % AddMatrix) ) THEN
5067
IF ( A % AddMatrix % NumberOFRows > 0 ) HaveAdd = 1
5068
END IF
5069
HaveAdd = ParallelReduction(HaveAdd)
5070
5071
IF( HaveConstraint > 0 .AND. HaveAdd > 0 ) THEN
5072
CALL Fatal('BlockSolveInt','Cannot yet do both Constraint and Add matrix!')
5073
END IF
5074
5075
IF( HaveConstraint > 0 ) THEN
5076
i = 0
5077
IF ( ASSOCIATED(A % ConstraintMatrix) ) THEN
5078
i = A % ConstraintMatrix % NumberOfRows
5079
END IF
5080
CALL Info('BlockSolveInt','Block system has ConstraintMatrix with '//I2S(i)//' rows!',Level=10)
5081
BlockDofs = BlockDofs + 1
5082
IF (BlockAV) BlockDofs = BlockDofs + 1
5083
END IF
5084
5085
IF( HaveAdd > 0 ) THEN
5086
i = A % AddMatrix % NumberOfRows - A % NumberOfRows
5087
CALL Info('BlockSolveInt','Block system has AddMatrix with '//I2S(i)//' own rows!',Level=10)
5088
BlockDofs = BlockDofs + 1
5089
END IF
5090
5091
5092
IF(.NOT. OldMatrix ) THEN
5093
CALL BlockInitMatrix( Solver, TotMatrix, BlockDofs, VarDofs, DoMyOwnVars )
5094
END IF
5095
5096
5097
NoVar = TotMatrix % NoVar
5098
TotMatrix % Solver => Solver
5099
5100
SaveMatrix => Solver % Matrix
5101
SolverMatrix => A
5102
Solver % Matrix => A
5103
5104
SolverVar => Solver % Variable
5105
SaveValues => SolverVar % Values
5106
SolverVar % Values => x
5107
5108
SaveRHS => SolverMatrix % RHS
5109
SolverMatrix % RHS => b
5110
5111
5112
IF( .NOT. GotSlaveSolvers ) THEN
5113
CALL Info('BlockSolveInt','Splitting monolithic matrix into pieces',Level=10)
5114
IF( DoMyOwnVars ) THEN
5115
CALL BlockPickMatrixPerm( Solver, BlockIndex, VarDofs, HaveAdd > 0 )
5116
IF(ASSOCIATED(BlockIndex)) THEN
5117
CALL BlockInitVar( Solver, TotMatrix, BlockIndex )
5118
DEALLOCATE(BlockIndex)
5119
ELSE
5120
CALL BlockInitVar( Solver, TotMatrix )
5121
END IF
5122
ELSE IF( BlockDummy .OR. VarDofs == 1 ) THEN
5123
CALL Info('BlockSolveInt','Using the original matrix as the (1,1) block!',Level=10)
5124
TotMatrix % SubMatrix(1,1) % Mat => SolverMatrix
5125
TotMatrix % SubMatrix(1,1) % Mat % Complex = ListGetLogical(Params,'Linear System Complex',Found)
5126
ELSE
5127
! Default splitting of matrices.
5128
CALL BlockPickMatrix( Solver, NoVar )
5129
VarDofs = NoVar
5130
END IF
5131
CALL Info('BlockSolveInt','Block matrix system created',Level=12)
5132
END IF
5133
5134
5135
! Currently we cannot have both structure-structure and fluid-structure couplings!
5136
IF( ListGetLogical( Params,'Structure-Structure Coupling',Found ) ) THEN
5137
CALL StructureCouplingBlocks( Solver )
5138
ELSE
5139
CALL FsiCouplingBlocks( Solver )
5140
END IF
5141
5142
IF( HaveConstraint > 0 ) THEN
5143
! Do not try to create preconditioner if we have Schur operator requested.
5144
SkipPrec = ListCheckPrefix( Params,'Schur Operator' )
5145
SkipPrec = SkipPrec .OR. ListGetLogical( Params,'Skip Constraint Prec', Found )
5146
CALL BlockPickConstraint( Solver, VarDofs, SkipPrec )
5147
! Storing pointer to CM so that the SolverMatrix won't be treated with the constraints
5148
SaveCM => Solver % Matrix % ConstraintMatrix
5149
Solver % Matrix % ConstraintMatrix => NULL()
5150
END IF
5151
5152
! Create preconditioners for block matrices.
5153
CALL BlockPrecMatrix( Solver, NoVar )
5154
5155
IF( ListCheckSuffix(Params,': Linear System Save') ) THEN
5156
DO RowVar=1,NoVar
5157
DO ColVar=1,NoVar
5158
IF( ListGetLogical( Params,'block '//I2S(10*ColVar+RowVar)//': Linear System Save',Found ) ) THEN
5159
Amat => TotMatrix % SubMatrix(RowVar,ColVar) % Mat
5160
CALL SaveLinearSystem( Solver, Amat,'block'//I2S(10*ColVar+RowVar) )
5161
END IF
5162
END DO
5163
IF( ListGetLogical( Params,'prec '//I2S(11*RowVar)//': Linear System Save',Found ) ) THEN
5164
Amat => TotMatrix % SubMatrix(RowVar,RowVar) % PrecMat
5165
CALL SaveLinearSystem( Solver, Amat,'prec'//I2S(11*RowVar) )
5166
END IF
5167
END DO
5168
END IF
5169
5170
5171
Found = .FALSE.
5172
DO RowVar=1,NoVar
5173
Amat => TotMatrix % SubMatrix(RowVar,RowVar) % Mat
5174
Var => TotMatrix % SubVector(RowVar) % Var
5175
IF( ASSOCIATED( Var ) ) THEN
5176
IF(.NOT. ASSOCIATED(Var % Perm)) THEN
5177
CALL Info('BlockSolveInt','Block variable '//I2S(RowVar)//' ('&
5178
//TRIM(Var % Name)//') exists but not Perm!',Level=3)
5179
Found = .TRUE.
5180
END IF
5181
END IF
5182
END DO
5183
IF(Found) THEN
5184
IF( isParallel ) THEN
5185
CALL Fatal('BlockSolveInt','Cannot continue without Perm in parallel!')
5186
ELSE
5187
CALL Warn('BlockSolveInt','Could not continue without Perm in parallel!!')
5188
END IF
5189
END IF
5190
5191
IF (isParallel .AND. .NOT. OldMatrix ) THEN
5192
CALL Info('BlockSolveInt','Initializing parallel block matrices',Level=12)
5193
DO RowVar=1,NoVar
5194
DO ColVar=1,NoVar
5195
5196
Amat => TotMatrix % SubMatrix(RowVar,ColVar) % Mat
5197
5198
! It is reasonable that there is no parallel communication for parallel
5199
! matrix if some partition is not participating in the process.
5200
IF(Amat % NumberOfRows == 0) CYCLE
5201
5202
Amat % Comm = Solver % Matrix % Comm
5203
Parenv % ActiveComm = Amat % Comm
5204
Solver % Variable => TotMatrix % SubVector(ColVar) % Var
5205
5206
! This is a coupling matrix that should by construction not lie at the interface
5207
IF(TotMatrix % Submatrix(RowVar,ColVar) % ParallelIsolatedMatrix ) CYCLE
5208
5209
! The parallel solution and hence also initialization works only for
5210
! standard square matrices.
5211
GotIt = (Amat % NumberOfRows == MAXVAL(Amat % Cols))
5212
TotMatrix % Submatrix(RowVar,ColVar) % ParallelSquareMatrix = GotIt
5213
5214
IF(GotIt) THEN
5215
CALL Info('BlockSolverInt','Block matrix is square matrix',Level=20)
5216
IF (.NOT.ASSOCIATED(Amat % ParMatrix)) THEN
5217
CALL Info('BlockSolveInt','Initializing parallel matrix: '//I2S(10*RowVar+ColVar),Level=6)
5218
CALL ParallelInitMatrix(Solver,Amat)
5219
END IF
5220
IF(ASSOCIATED(Amat % ParMatrix )) THEN
5221
Amat % ParMatrix % ParEnv % ActiveComm = Amat % Comm
5222
ParEnv => Amat % ParMatrix % ParEnv
5223
END IF
5224
!CALL SParIterActiveBarrier()
5225
ELSE
5226
CALL Info('BlockSolverInt','Block matrix '//I2S(10*RowVar+ColVar)//&
5227
' is not square matrix - cannot initialize parallel structures!',Level=20)
5228
END IF
5229
END DO
5230
END DO
5231
5232
CALL ParallelShrinkPerm()
5233
5234
Solver % Variable => SolverVar
5235
CALL Info('BlockSolveInt','Initialization of block matrix finished',Level=20)
5236
END IF
5237
5238
5239
IF(InfoActive(25)) THEN
5240
CALL Info('BlockSolveInt','Initial Block matrix system information:')
5241
CALL BlockMatrixInfo()
5242
END IF
5243
5244
5245
5246
!------------------------------------------------------------------------------
5247
! Finally solve the system using 'outer: ' as the optional namespace
5248
! for the linear system setting.
5249
!------------------------------------------------------------------------------
5250
5251
TotNorm = 0.0_dp
5252
MaxChange = 0.0_dp
5253
5254
IF( BlockScaling ) THEN
5255
CALL CreateBlockMatrixScaling()
5256
CALL DoBlockMatrixScaling(.FALSE.)
5257
END IF
5258
5259
CALL ListPushNamespace('outer:')
5260
5261
IF (BlockScaling) THEN
5262
! This simplifies writing a consistent sif file:
5263
!CALL ListAddLogical(Solver % Values, 'Linear System Row Equilibration', .TRUE.)
5264
END IF
5265
5266
! The case with one block is mainly for testing and developing features
5267
! related to nonlinearity and assembly.
5268
!----------------------------------------------------------------------
5269
IF( NoVar == 1 .AND. .NOT. BlockDummy ) THEN
5270
CALL Info('BlockSolveInt','Solving in standard manner',Level=6)
5271
5272
Solver % Variable => TotMatrix % SubVector(1) % Var
5273
Solver % Matrix => TotMatrix % Submatrix(1,1) % Mat
5274
5275
IF (BlockScaling) THEN
5276
! This simplifies writing a consistent sif file:
5277
CALL ListAddLogical(Solver % Values, 'Linear System Row Equilibration', .TRUE.)
5278
END IF
5279
5280
TotNorm = DefaultSolve()
5281
MaxChange = Solver % Variable % NonlinChange
5282
ELSE IF( BlockMonolithic ) THEN
5283
CALL Info('BlockSolveInt','Using monolithic strategy for the block',Level=6)
5284
CALL BlockMonolithicSolve( Solver, MaxChange )
5285
ELSE IF( BlockPrec ) THEN
5286
CALL Info('BlockSolveInt','Using block preconditioning strategy',Level=6)
5287
CALL BlockKrylovIter( Solver, MaxChange )
5288
ELSE
5289
Solver % Variable => TotMatrix % SubVector(1) % Var
5290
Solver % Matrix => TotMatrix % Submatrix(1,1) % Mat
5291
5292
CALL Info('BlockSolveInt','Using block solution strategy',Level=6)
5293
CALL BlockStandardIter( Solver, MaxChange )
5294
END IF
5295
5296
CALL ListPopNamespace('outer:')
5297
5298
IF( BlockScaling ) THEN
5299
CALL DoBlockMatrixScaling(.TRUE.)
5300
CALL DestroyBlockMatrixScaling()
5301
END IF
5302
5303
! For legacy matrices do the backmapping
5304
!------------------------------------------
5305
SolverMatrix % RHS => SaveRHS
5306
Solver % Matrix => SaveMatrix
5307
Solver % Variable => SolverVar
5308
Solver % Variable % Values => SaveValues
5309
5310
IF( HaveConstraint > 0 ) THEN
5311
! Restore the pointer to the SolverMatrix
5312
Solver % Matrix % ConstraintMatrix => SaveCM
5313
END IF
5314
5315
IF( DoMyOwnVars ) THEN
5316
CALL BlockBackCopyVar( Solver, TotMatrix )
5317
END IF
5318
5319
IF( ListGetLogical( Solver % Values,'Block Save Iterations',Found ) ) THEN
5320
CALL ListAddInteger(CurrentModel % Simulation,'res: block iterations',TotMatrix % NoIters)
5321
END IF
5322
5323
CALL Info('BlockSolveInt','All done')
5324
CALL Info('BlockSolveInt','-------------------------------------------------',Level=5)
5325
5326
END SUBROUTINE BlockSolveInt
5327
5328
END MODULE BlockSolve
5329
5330
5331
!------------------------------------------------------------------------------
5332
!> Just a handle for SolveLinearSystem():
5333
!------------------------------------------------------------------------------
5334
SUBROUTINE BlockSolveExt(A,x,b,Solver)
5335
!------------------------------------------------------------------------------
5336
USE Types
5337
USE BlockSolve, ONLY: BlockSolveInt
5338
USE Lists, ONLY : ListGetLogical, ListAddLogical
5339
IMPLICIT NONE
5340
5341
TYPE(Matrix_t), POINTER :: A
5342
TYPE(Solver_t) :: Solver
5343
REAL(KIND=dp) :: x(:),b(:)
5344
!------------------------------------------------------------------------------
5345
LOGICAL :: Found, bm
5346
!------------------------------------------------------------------------------
5347
! Eliminate recursion for block solvers.
5348
bm = ListGetLogical( Solver % Values, 'Linear System Block Mode', Found)
5349
IF(Found) &
5350
CALL ListAddLogical(Solver % Values,'Linear System Block Mode',.FALSE.)
5351
5352
CALL BlockSolveInt(A,x,b,Solver)
5353
5354
IF(Found) &
5355
CALL ListAddLogical(Solver % Values,'Linear System Block Mode',bm )
5356
!------------------------------------------------------------------------------
5357
END SUBROUTINE BlockSolveExt
5358
!------------------------------------------------------------------------------
5359
5360
!> \}
5361
5362