Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/BlockSolve.F90
5213 views
1
!/*****************************************************************************/
2
! *
3
! * Elmer, A Finite Element Software for Multiphysical Problems
4
! *
5
! * Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland
6
! *
7
! * This library is free software; you can redistribute it and/or
8
! * modify it under the terms of the GNU Lesser General Public
9
! * License as published by the Free Software Foundation; either
10
! * version 2.1 of the License, or (at your option) any later version.
11
! *
12
! * This library is distributed in the hope that it will be useful,
13
! * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
! * Lesser General Public License for more details.
16
! *
17
! * You should have received a copy of the GNU Lesser General Public
18
! * License along with this library (in file ../LGPL-2.1); if not, write
19
! * to the Free Software Foundation, Inc., 51 Franklin Street,
20
! * Fifth Floor, Boston, MA 02110-1301 USA
21
! *
22
! *****************************************************************************/
23
24
25
!> \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 MortarUtils, 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 associated 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 definition 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 matrix!',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 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,l,n,m,n0,dofs,EDOFs,EDOFs_Order1
1791
TYPE(Matrix_t), POINTER :: A,B
1792
TYPE(Mesh_t), POINTER :: Mesh
1793
TYPE(Element_t), POINTER :: Element, Edge
1794
LOGICAL :: Found, SecondFamily, SecondOrder, PickSimplest
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 H(curl) approximation into blocks',Level=10)
1805
1806
SecondFamily = ListGetLogical( Solver % Values,'Second Kind Basis',Found )
1807
IF (SecondFamily) THEN
1808
SecondOrder = ListGetLogical( Solver % Values,'Quadratic Approximation',Found )
1809
IF (.NOT. SecondOrder) THEN
1810
EDOFs = 2
1811
EDOFs_Order1 = 1
1812
ELSE
1813
EDOFs = 3
1814
IF (ListGetLogical(Solver % Values, 'Block Quadratic Hcurl Pick Simplest', Found)) THEN
1815
! To select DOFs corresponding to the lowest-order basis of the first kind
1816
EDOFs_Order1 = 1
1817
ELSE
1818
! To select DOFs corresponding to the lowest-order basis of the second kind
1819
EDOFs_Order1 = 2
1820
END IF
1821
END IF
1822
ELSE
1823
EDOFs = 2
1824
EDOFs_Order1 = 1
1825
END IF
1826
1827
NoVar = 2
1828
IF( ListGetLogical( Solver % Values,'Block Quadratic Hcurl Faces',Found ) ) NoVar = 3
1829
IF(DoCmplx) THEN
1830
NoVar = 2 * NoVar
1831
IF( ListGetLogical( Solver % Values,'Block Quadratic Hcurl semicomplex',Found ) ) NoVar = 3
1832
END IF
1833
1834
1835
A => Solver % Matrix
1836
dofs = Solver % Variable % Dofs
1837
1838
m = A % NumberOfRows
1839
n = m
1840
1841
! Set the default blocks
1842
IF( DoCmplx ) THEN
1843
! Synopsis: the tags of (4x4) block structure
1844
! - Re, lowest-order = 1
1845
! - Im, lowest-order = 2
1846
! - Re, higher-order = 3
1847
! - Im, higher-order = 4
1848
! while (3x3) structure corresponds to
1849
! - Re and Im, lowest-order = 1
1850
! - Re, higher-order = 2
1851
! - Im, higher-order = 3
1852
BlockTag(1::2) = 3
1853
BlockTag(2::2) = 4
1854
ELSE
1855
! Synopsis:
1856
! - lowest-order = 1
1857
! - higher-order = 2
1858
! - higher-order DOFs which are not associated with edges = 3 (optional)
1859
BlockTag = 2
1860
END IF
1861
1862
n0 = Mesh % NumberOfNodes
1863
DO i=1, Mesh % NumberOfEdges
1864
DO l=1,EDOFs_Order1
1865
! This corresponds to the lowest-order DOF over an edge
1866
j = n0 + EDOFs*(i-1) + l
1867
k = Solver % Variable % Perm(j)
1868
IF(k<1) CYCLE
1869
1870
! If BlockTag array were created for all DOFs with DOFs>1,
1871
! it would have a repeated entries occurring in clusters of
1872
! size DOFs. Therefore a smaller array can be used to tag DOFs.
1873
IF( dofs == 1 ) THEN
1874
BlockTag(k) = 1
1875
ELSE IF(dofs == 2 ) THEN
1876
BlockTag(2*k-1) = 1
1877
IF( DoCmplx ) THEN
1878
BlockTag(2*k) = 2
1879
ELSE
1880
BlockTag(2*k) = 1
1881
END IF
1882
END IF
1883
END DO
1884
END DO
1885
1886
! DO i=1,Mesh % NumberOfFaces
1887
! DO l=2,3
1888
! j = n0 + EDOFs*Mesh % NumberOfEdges + 3*(i-1) + l
1889
! k = Solver % Variable % Perm(j)
1890
! IF(k<1) CYCLE
1891
!
1892
! IF (dofs == 1) THEN
1893
! BlockTag(k) = 1
1894
! ELSE IF (dofs == 2) THEN
1895
! BlockTag(2*k-1) = 1
1896
! BlockTag(2*k) = 1
1897
! END IF
1898
! END DO
1899
! END DO
1900
1901
IF(NoVar == 3) THEN
1902
IF( DoCmplx ) THEN
1903
WHERE( BlockTag > 1 )
1904
BlockTag = BlockTag - 1
1905
END WHERE
1906
ELSE
1907
DO j = n0 + 2*Mesh % NumberOfEdges + 1, SIZE(Solver % Variable % Perm)
1908
k = Solver % Variable % Perm(j)
1909
IF(k==0) CYCLE
1910
1911
IF(dofs == 1 ) THEN
1912
BlockTag(k) = 3
1913
ELSE IF( dofs == 2 ) THEN
1914
BlockTag(2*k-1) = 3
1915
BlockTag(2*k) = 3
1916
END IF
1917
END DO
1918
END IF
1919
END IF
1920
1921
IF( InfoActive(20) ) THEN
1922
DO i=1,NoVar
1923
j = COUNT(BlockTag==i)
1924
CALL Info('BlockMatrixHCurl','There are '//I2S(j)//' dofs group '//I2S(i))
1925
END DO
1926
END IF
1927
1928
END SUBROUTINE BlockPickMatrixHcurl
1929
1930
1931
1932
!-------------------------------------------------------------------------------------
1933
!> Picks apart nodal and non-nodal dofs.
1934
!-------------------------------------------------------------------------------------
1935
SUBROUTINE BlockPickMatrixNodal( Solver, NoVar, DoCmplx, BlockTag )
1936
1937
TYPE(Solver_t) :: Solver
1938
INTEGER :: Novar
1939
LOGICAL :: DoCmplx
1940
INTEGER :: BlockTag(:)
1941
1942
INTEGER :: i,j,k,n,dofs
1943
TYPE(Matrix_t), POINTER :: A
1944
TYPE(Mesh_t), POINTER :: Mesh
1945
LOGICAL :: Found
1946
1947
Mesh => Solver % Mesh
1948
1949
CALL Info('BlockPickMatrixNodal','Separates nodal and non-nodal dofs from each other',Level=10)
1950
1951
NoVar = 2
1952
IF(DoCmplx) NoVar = 2 * NoVar
1953
1954
A => Solver % Matrix
1955
dofs = Solver % Variable % Dofs
1956
1957
IF( DoCmplx ) THEN
1958
BlockTag(1::2) = 3
1959
BlockTag(2::2) = 4
1960
ELSE
1961
BlockTag = 2
1962
END IF
1963
1964
DO i=1, Mesh % NumberOfNodes
1965
k = Solver % Variable % Perm(j)
1966
IF(k==0) CYCLE
1967
1968
IF( dofs == 1 ) THEN
1969
BlockTag(k) = 1
1970
ELSE IF(dofs == 2 ) THEN
1971
BlockTag(2*k-1) = 1
1972
IF( DoCmplx ) THEN
1973
BlockTag(2*k) = 2
1974
ELSE
1975
BlockTag(2*k) = 1
1976
END IF
1977
END IF
1978
END DO
1979
1980
IF( InfoActive(20) ) THEN
1981
DO i=1,NoVar
1982
j = COUNT(BlockTag==i)
1983
CALL Info('BlockMatrixNodal','There are '//I2S(j)//' dofs group '//I2S(i))
1984
END DO
1985
END IF
1986
1987
END SUBROUTINE BlockPickMatrixNodal
1988
1989
1990
1991
!-------------------------------------------------------------------------------------
1992
!> Picks the components of the constraint matrix.
1993
!-------------------------------------------------------------------------------------
1994
SUBROUTINE BlockPickConstraint( Solver, NoVar, SkipPrec )
1995
1996
TYPE(Solver_t), TARGET :: Solver
1997
INTEGER :: Novar
1998
LOGICAL :: SkipPrec
1999
2000
INTEGER :: RowVar, ColVar
2001
TYPE(Matrix_t), POINTER :: SolverMatrix
2002
TYPE(Matrix_t), POINTER :: Amat
2003
TYPE(ValueList_t), POINTER :: Params
2004
LOGICAL :: Found
2005
2006
LOGICAL :: BlockAV
2007
INTEGER::i,j,k,l,n,i1,i2,i3,rowi,colj,NoCon,rb,cb
2008
TYPE(Matrix_t), POINTER :: A,CM,C1,C2,C3,C1prec,C2prec,C3prec,Tmat
2009
REAL(KIND=dp) :: PrecCoeff,val
2010
INTEGER, POINTER :: ConsPerm(:), ConsPerm2(:)
2011
INTEGER :: DoPrec
2012
CHARACTER(:), ALLOCATABLE :: VarName
2013
TYPE(Variable_t), POINTER :: Var
2014
TYPE(Solver_t), POINTER :: PSolver
2015
LOGICAL :: InheritCM, PrecTrue
2016
2017
LOGICAL, ALLOCATABLE :: vflag(:)
2018
2019
INTEGER, ALLOCATABLE :: REdgePerm(:), RNodePerm(:), BlockNumbering(:), InvPerm(:)
2020
2021
CALL Info('BlockPickConstraint','Picking constraints to block matrix',Level=10)
2022
2023
2024
SolverMatrix => Solver % Matrix
2025
Params => Solver % Values
2026
BlockAV = ListGetLogical( Params,'Block A-V System', Found)
2027
BlockAV = BlockAV .OR. ListGetLogical( Params,'Block A-V System Old', Found)
2028
2029
A => SolverMatrix
2030
n = Solver % Mesh % NumberOfNodes
2031
2032
PrecCoeff = ListGetConstReal( Params,'Block Diag Coeff',Found)
2033
2034
IF(.NOT. Found ) PrecCoeff = 1.0_dp
2035
2036
PrecTrue = ListGetLogical( Params,'Block Diag True',Found )
2037
2038
2039
! temporarily be generic
2040
NoCon = 0
2041
CM => A % ConstraintMatrix
2042
DO WHILE(ASSOCIATED(CM))
2043
NoCon = NoCon + 1
2044
CM => CM % ConstraintMatrix
2045
END DO
2046
2047
CALL Info('BlockPickConstraint','Number of constraint matrices: '//I2S(NoCon),Level=10)
2048
2049
InheritCM = (NoVar == 1 ) .AND. (NoCon == 1 )
2050
IF( InheritCM ) THEN
2051
CALL info('BlockPickConstraint','Inheriting constraint matrix',Level=20)
2052
END IF
2053
2054
2055
IF( NoVar == 1 ) THEN
2056
IF( InheritCM ) THEN
2057
C1 => A % ConstraintMatrix
2058
TotMatrix % Submatrix(NoVar+1,1) % Mat => A % ConstraintMatrix
2059
CALL Info('BlockPickConstraint',&
2060
'Using constraint matrix ('//I2S(NoVar+1)//',1) as is!',Level=10)
2061
i = A % ConstraintMatrix % NumberOfRows
2062
CALL Info('BlockPickConstraint','Number of rows in matrix: '//I2S(i),Level=20)
2063
IF( PrecTrue ) THEN
2064
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % Mat
2065
ELSE
2066
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % PrecMat
2067
END IF
2068
ELSE
2069
C1 => TotMatrix % Submatrix(NoVar+1,1) % Mat
2070
IF( PrecTrue ) THEN
2071
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % Mat
2072
ELSE
2073
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % PrecMat
2074
END IF
2075
END IF
2076
2077
ELSE IF(BlockAV) THEN
2078
IF( PrecTrue ) THEN
2079
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % Mat
2080
C2prec => TotMatrix % Submatrix(NoVar+2,NoVar+2) % Mat
2081
ELSE
2082
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % PrecMat
2083
C2prec => TotMatrix % Submatrix(NoVar+2,NoVar+2) % PrecMat
2084
END IF
2085
C1 => TotMatrix % SubMatrix(NoVar+1,1) % Mat
2086
C2 => TotMatrix % SubMatrix(NoVar+2,2) % Mat
2087
ELSE
2088
CALL Fatal('BlockPickConstraint','Not done for vectors!')
2089
END IF
2090
2091
CM => A % ConstraintMatrix
2092
n = Solver % Mesh % NumberOfNodes
2093
DO WHILE(ASSOCIATED(CM))
2094
IF(.NOT.BlockAV ) n = MAX( n, MAXVAL(MOD(CM % InvPerm-1,A % NumberOfRows)+1) )
2095
CM => CM % ConstraintMatrix
2096
END DO
2097
CM => A % ConstraintMatrix
2098
2099
ALLOCATE( ConsPerm( A % NumberOfRows) )
2100
ConsPerm = 0;
2101
IF ( BlockAV ) THEN
2102
ALLOCATE( ConsPerm2(A % NumberofRows) )
2103
ConsPerm2 = 0
2104
END IF
2105
2106
IF ( BlockAV ) THEN
2107
ALLOCATE( InvPerm(MAXVAL(Solver % Variable % Perm)))
2108
InvPerm = 0
2109
DO i=1,SIZE(Solver % Variable % Perm)
2110
j = Solver % Variable % Perm(i)
2111
IF ( j>0 ) InvPerm(j) = i
2112
END DO
2113
2114
j = CM % NumberOfRows
2115
ALLOCATE( rEdgePerm(j), rNodePerm(j) )
2116
rEdgePerm = 0
2117
rNodePerm = 0
2118
i1 = 0
2119
i2 = 0
2120
DO i=1,CM % NumberOFRows
2121
j = CM % InvPerm(i)
2122
j = MOD(j-1,A % NumberOfRows)+1
2123
j = InvPerm(j)
2124
IF ( j > n ) THEN
2125
i2 = i2+1
2126
rEdgePerm(i) = i2
2127
ELSE IF ( j>0 .AND. j <= n ) THEN
2128
i1 = i1 +1
2129
rNodePerm(i) = i1
2130
ELSE
2131
stop 'cm invperm'
2132
END IF
2133
END DO
2134
! print*, 'edges: ', i2, 'nodes: ', i1, cm % numberofrows
2135
END IF
2136
2137
j = Solver % Matrix % NumberOfRows
2138
ALLOCATE( vFlag(j), BlockNumbering(j) )
2139
IF (BlockAV) THEN
2140
i1 = 0; i2 = 0
2141
k = SIZE(Solver % Variable % Perm)
2142
DO i=1,k
2143
j = Solver % variable % Perm(i)
2144
IF ( j<= 0 ) CYCLE
2145
vFlag(j) = i <= n
2146
END DO
2147
ELSE
2148
vFlag = .TRUE.
2149
END IF
2150
! print*, 'edges: ', COUNT(.NOT. vFlag), 'nodes: ', COUNT(vFlag), solver % matrix % numberofrows
2151
2152
2153
k = Solver % Matrix % NumberOfRows
2154
i1 = 0; i2=0
2155
BlockNumbering = 0
2156
DO i=1,k
2157
IF ( vFlag(i) ) THEN
2158
i1 = i1 + 1
2159
BlockNumbering(i) = i1
2160
ELSE
2161
i2 = i2 + 1
2162
BlockNumbering(i) = i2
2163
END IF
2164
END DO
2165
2166
IF ( .NOT. InheritCM ) THEN
2167
IF ( C1 % Format == MATRIX_CRS ) THEN
2168
C1 % Values = 0
2169
IF ( ASSOCIATED(C1prec) ) THEN
2170
IF ( ASSOCIATED(C1prec % Values) ) C1prec % Values = 0
2171
END IF
2172
END IF
2173
2174
IF ( BlockAV ) THEN
2175
IF ( C2 % Format == MATRIX_CRS ) THEN
2176
C2 % Values = 0
2177
IF ( ASSOCIATED(C2prec) ) THEN
2178
IF ( ASSOCIATED(C2prec % Values) ) C2prec % Values = 0
2179
END IF
2180
END IF
2181
END IF
2182
END IF
2183
2184
DO DoPrec = 0, 1
2185
IF( DoPrec == 1 .AND. SkipPrec ) CYCLE
2186
2187
i1 = 0
2188
i2 = 0
2189
2190
CM => A % ConstraintMatrix
2191
DO WHILE(ASSOCIATED(CM))
2192
2193
DO i=1,CM % NumberOFRows
2194
2195
rowi = MOD(CM % InvPerm(i)-1, A % NumberOfRows)+1
2196
2197
rb = 1
2198
i1 = i1 + 1
2199
IF( BlockAV ) THEN
2200
IF( rEdgePerm(i)>0 ) rb = 2
2201
IF( rb == 1 ) THEN
2202
i1 = rNodePerm(i)
2203
ELSE
2204
i2 = rEdgePerm(i)
2205
END IF
2206
END IF
2207
2208
! First round initialize the ConsPerm
2209
IF( DoPrec == 0 ) THEN
2210
IF ( rb == 1 ) THEN
2211
ConsPerm(rowi) = i1
2212
ELSE
2213
ConsPerm2(rowi) = i2
2214
END IF
2215
END IF
2216
2217
DO j=CM % Rows(i),CM % Rows(i+1)-1
2218
IF (CM % Values(j)==0._dp) CYCLE
2219
2220
colj = CM % Cols(j)
2221
cb = 1
2222
IF( BlockAV ) THEN
2223
IF( .NOT. vFlag(colj) ) cb = 2
2224
END IF
2225
colj = BlockNumbering(colj)
2226
2227
val = CM % Values(j)
2228
2229
IF( DoPrec == 1 ) THEN
2230
IF( ConsPerm( colj ) > 0 ) THEN
2231
! The sign -1 is needed for consistency
2232
val = -PrecCoeff * val
2233
IF ( cb == 1 ) THEN
2234
CALL AddToMatrixElement(C1prec,i1,ConsPerm(colj),val)
2235
ELSE
2236
CALL AddToMatrixElement(C2prec,i2,ConsPerm2(colj),val)
2237
END IF
2238
END IF
2239
ELSE IF( .NOT. InheritCM ) THEN
2240
IF ( cb == 1 ) THEN
2241
CALL AddToMatrixElement(C1,i1,colj,val)
2242
ELSE
2243
CALL AddToMatrixElement(C2,i2,colj,val)
2244
END IF
2245
END IF
2246
END DO
2247
END DO
2248
2249
CM => CM % ConstraintMatrix
2250
END DO
2251
2252
! It is more efficient to set the last entry of the list matrix first
2253
#if 0
2254
IF( DoPrec == 0 .AND. .NOT. SkipPrec ) THEN
2255
CALL AddToMatrixElement(C1prec,i1,i1,0.0_dp)
2256
END IF
2257
#endif
2258
END DO
2259
2260
CALL Info('BlockPickConstraint','Setting format of constraint blocks to CRS',Level=20)
2261
IF(.NOT. InheritCM ) THEN
2262
CALL List_toCRSMatrix(C1)
2263
END IF
2264
IF(.NOT. SkipPrec ) CALL List_toCRSMatrix(C1prec)
2265
2266
IF( BlockAV ) THEN
2267
CALL List_toCRSMatrix(C2)
2268
IF(.NOT. SkipPrec) CALL List_toCRSMatrix(C2prec)
2269
END IF
2270
2271
IF( ListGetLogical( Solver % Values,'Save Prec Matrix', Found ) ) THEN
2272
CALL SaveProjector(C1prec,.TRUE.,"CM")
2273
END IF
2274
2275
VarName = "lambda_n"
2276
Var => VariableGet( Solver % Mesh % Variables, VarName )
2277
IF(ASSOCIATED( Var ) ) THEN
2278
n = SIZE( Var % Values )
2279
DEALLOCATE(ConsPerm)
2280
CALL Info('BlockPickConstraint','Using existing variable > '//VarName//' <')
2281
ELSE
2282
CALL Info('BlockPickConstraint','Variable > '//VarName//' < does not exist, creating')
2283
n = MAXVAL(ConsPerm)
2284
PSolver => Solver
2285
Var => CreateBlockVariable(PSolver, NoVar+1, VarName, 1, ConsPerm )
2286
END IF
2287
2288
TotMatrix % SubVector(NoVar+1) % Var => Var
2289
TotMatrix % Offset(NoVar+2) = TotMatrix % Offset(NoVar+1) + n
2290
TotMatrix % MaxSize = MAX( TotMatrix % MaxSize, n )
2291
TotMatrix % TotSize = TotMatrix % TotSize + n
2292
2293
TotMatrix % SubMatrix(NoVar+1,1) % Mat => C1
2294
2295
Tmat => TotMatrix % SubMatrix(1,NoVar+1) % Mat
2296
IF ( ASSOCIATED(Tmat) ) CALL FreeMatrix(Tmat)
2297
TotMatrix % SubMatrix(1,NoVar+1) % Mat => CRS_Transpose(C1)
2298
2299
TotMatrix % SubMatrix(1,NoVar+1) % ParallelIsolatedMatrix = &
2300
TotMatrix % SubMatrix(NoVar+1,1) % ParallelIsolatedMatrix
2301
2302
IF ( BlockAV ) THEN
2303
VarName = "lambda_a"
2304
Var => VariableGet( Solver % Mesh % Variables, VarName )
2305
IF(ASSOCIATED( Var ) ) THEN
2306
n = SIZE( Var % Values )
2307
DEALLOCATE(ConsPerm2)
2308
CALL Info('BlockPickConstraint','Using existing variable > '//VarName//' <')
2309
ELSE
2310
CALL Info('BlockPickConstraint','Variable > '//VarName//' < does not exist, creating')
2311
n = MAXVAL(ConsPerm2)
2312
Var => CreateBlockVariable(PSolver, NoVar+2, VarName, 1, ConsPerm2 )
2313
END IF
2314
2315
TotMatrix % SubVector(NoVar+2) % Var => Var
2316
TotMatrix % Offset(NoVar+3) = TotMatrix % Offset(NoVar+2) + n
2317
TotMatrix % MaxSize = MAX( TotMatrix % MaxSize, n )
2318
TotMatrix % TotSize = TotMatrix % TotSize + n
2319
2320
TotMatrix % SubMatrix(NoVar+2,2) % Mat => C2
2321
2322
Tmat => TotMatrix % SubMatrix(2,NoVar+2) % Mat
2323
IF ( ASSOCIATED(Tmat) ) CALL FreeMatrix(Tmat)
2324
TotMatrix % SubMatrix(2,NoVar+2) % Mat => CRS_Transpose(C2)
2325
2326
TotMatrix % SubMatrixActive(2,NoVar+2) = .TRUE.
2327
TotMatrix % SubMatrixActive(NoVar+2,2) = .TRUE.
2328
2329
TotMatrix % SubMatrix(2,NoVar+2) % ParallelIsolatedMatrix = &
2330
TotMatrix % SubMatrix(NoVar+2,2) % ParallelIsolatedMatrix
2331
END IF
2332
2333
END SUBROUTINE BlockPickConstraint
2334
2335
2336
2337
!-------------------------------------------------------------------------------------
2338
!> The block preconditioning matrix need not be directly derived from the full
2339
!> matrix. Some or all the components may also be derived from a basic operator
2340
!> such as the Laplacian.
2341
!-------------------------------------------------------------------------------------
2342
SUBROUTINE BlockPrecMatrix( Solver, NoVar )
2343
2344
TYPE(Solver_t) :: Solver
2345
INTEGER :: Novar
2346
2347
INTEGER :: i, RowVar, ColVar, CopyVar
2348
CHARACTER(:), ALLOCATABLE :: str
2349
REAL(KIND=dp) :: Coeff, Coeff0
2350
LOGICAL :: GotIt, GotIt2, DoIt
2351
INTEGER, POINTER :: VarPerm(:)
2352
TYPE(ValueList_t), POINTER :: Params
2353
TYPE(Matrix_t), POINTER :: Amat, PMat
2354
TYPE(Variable_t), POINTER :: AVar
2355
LOGICAL :: SplitComplexHcurl
2356
2357
CALL Info('BlockPrecMatrix','Checking for tailored preconditioning matrices',Level=6)
2358
2359
Params => Solver % Values
2360
SplitComplexHcurl = ListGetLogical( Params,'Block Split Complex Hcurl', GotIt )
2361
2362
! The user may give a user defined preconditioner matrix
2363
!-----------------------------------------------------------
2364
DO RowVar=1,NoVar
2365
i = TotMatrix % Submatrix(RowVar,RowVar) % PrecMat % NumberOfRows
2366
2367
IF( i > 0 ) CYCLE
2368
2369
str = 'Prec Matrix Diffusion '//I2S(RowVar)
2370
Coeff = ListGetCReal( Params, str, GotIt)
2371
2372
str = 'Prec Matrix Density '//I2S(RowVar)
2373
Coeff = ListGetCReal( Params, str, GotIt2)
2374
2375
IF( GotIt .OR. GotIt2 ) THEN
2376
CALL CRS_CopyMatrixTopology( TotMatrix % Submatrix(RowVar,RowVar) % Mat, &
2377
TotMatrix % Submatrix(RowVar,RowVar) % PrecMat )
2378
2379
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
2380
VarPerm => TotMatrix % Subvector(RowVar) % Var % Perm
2381
IF( GotIt ) THEN
2382
CALL Info('BlockPrecMatrix','Creating simple preconditioning Laplace matrix',Level=8)
2383
CALL LaplaceMatrixAssembly( Solver, VarPerm, Amat )
2384
Amat % Values = Coeff * Amat % Values
2385
ELSE
2386
CALL Info('BlockPrecMatrix','Creating simple preconditioning mass matrix',Level=8)
2387
CALL MassMatrixAssembly( Solver, VarPerm, Amat )
2388
Amat % Values = Coeff * Amat % Values
2389
END IF
2390
Amat % ParallelInfo => TotMatrix % Submatrix(RowVar,RowVar) % Mat % ParallelInfo
2391
END IF
2392
2393
str = 'Prec Matrix Complex Coeff '//I2S(RowVar)
2394
Coeff = ListGetCReal( Params, str, GotIt )
2395
2396
IF(.NOT. GotIt) THEN
2397
str = 'Prec Matrix Complex Coeff'
2398
Coeff = ListGetCReal( Params, str, GotIt )
2399
END IF
2400
2401
IF(.NOT. GotIt) THEN
2402
GotIt = ListGetLogical( Params,'Block Split Complex', GotIt )
2403
Coeff = 1.0_dp
2404
END IF
2405
Coeff0 = Coeff
2406
2407
IF( GotIt ) THEN
2408
IF(ASSOCIATED(Solver % Matrix % PrecValues) ) THEN
2409
CALL Info('BlockPermMatrix','Skipping adding off-diagonal prec values!')
2410
GotIt = .FALSE.
2411
END IF
2412
END IF
2413
2414
IF(GotIt) THEN
2415
CALL Info('BlockPrecMatrix','Creating preconditioning matrix from block sums',Level=8)
2416
2417
IF( SplitComplexHcurl ) THEN
2418
! This is a special case where only the A matrix is split to [Re,Im] parts.
2419
IF( RowVar == 2 ) THEN
2420
ColVar = RowVar + 1
2421
Coeff = Coeff0
2422
ELSE IF( RowVar == 3 ) THEN
2423
ColVar = RowVar - 1
2424
Coeff = -Coeff0
2425
ELSE
2426
CYCLE
2427
END IF
2428
ELSE
2429
! Here all the block matrices are split.
2430
IF( MODULO(NoVar,2) /= 0) THEN
2431
CALL Fatal('BlockPrecMatrix','Assuming even number of blocks for the complex preconditioner!')
2432
END IF
2433
IF( MODULO(RowVar,2) == 1 ) THEN
2434
ColVar = RowVar + 1
2435
Coeff = Coeff0
2436
ELSE
2437
ColVar = RowVar - 1
2438
Coeff = -Coeff0
2439
END IF
2440
END IF
2441
2442
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
2443
IF(Amat % NumberOfRows == 0 ) THEN
2444
CALL CRS_CopyMatrixTopology( TotMatrix % Submatrix(RowVar,RowVar) % Mat, &
2445
TotMatrix % Submatrix(RowVar,RowVar) % PrecMat )
2446
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
2447
END IF
2448
IF( ASSOCIATED( TotMatrix % Submatrix(RowVar,RowVar) % Mat % PrecValues ) ) THEN
2449
AMat % Values = TotMatrix % Submatrix(RowVar,RowVar) % Mat % PrecValues
2450
DEALLOCATE( TotMatrix % Submatrix(RowVar,RowVar) % Mat % PrecValues )
2451
ELSE
2452
AMat % Values = TotMatrix % Submatrix(RowVar,RowVar) % Mat % Values
2453
END IF
2454
2455
IF( SIZE( Amat % Values ) /= SIZE( TotMatrix % Submatrix(RowVar,ColVar) % Mat % Values ) ) THEN
2456
CALL Fatal('BlockPrecMatrix','Mismatch in matrix size for block: '//I2S(10*RowVar+ColVar))
2457
END IF
2458
2459
AMat % Values = Amat % Values + &
2460
Coeff * TotMatrix % Submatrix(RowVar,ColVar) % Mat % Values
2461
END IF
2462
2463
str = 'Prec Matrix Diagonal '//I2S(RowVar)
2464
Coeff = ListGetCReal( Params, str, GotIt)
2465
IF( GotIt ) THEN
2466
CopyVar = NoVar+1 - RowVar
2467
PMat => TotMatrix % Submatrix(RowVar,CopyVar) % Mat
2468
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
2469
CALL Info('BlockPrecMatrix','Creating preconditioner from matrix ('&
2470
//I2S(RowVar)//','//I2S(CopyVar)//')',Level=6)
2471
2472
CALL DiagonalMatrixSumming( Solver, PMat, Amat )
2473
Amat % Values = Coeff * Amat % Values
2474
END IF
2475
END DO
2476
2477
IF( ListGetLogical( Params,'Create Schur Matrix Approximation',GotIt ) ) THEN
2478
CALL Info('BlockPrecMatrix','Generating block '//I2S(11*NoVar),Level=7)
2479
IF(NoVar == 1) THEN
2480
CALL Fatal('BlockPrecMatrix','We should have more than one block')
2481
END IF
2482
IF ( NoVar == 4 ) THEN
2483
Pmat => TotMatrix % Submatrix(3,3) % PrecMat
2484
IF ( ASSOCIATED(Pmat) ) CALL FreeMatrix(Pmat)
2485
2486
Pmat => TotMatrix % Submatrix(4,4) % PrecMat
2487
IF ( ASSOCIATED(Pmat) ) CALL FreeMatrix(Pmat)
2488
2489
Pmat => CreateSchurApproximation( &
2490
TotMatrix % Submatrix(1,1) % Mat, &
2491
TotMatrix % Submatrix(3,1) % Mat, &
2492
TotMatrix % Submatrix(1,3) % Mat )
2493
TotMatrix % Submatrix(3,3) % PrecMat => Pmat
2494
2495
Pmat => CreateSchurApproximation( &
2496
TotMatrix % Submatrix(2,2) % Mat, &
2497
TotMatrix % Submatrix(4,2) % Mat, &
2498
TotMatrix % Submatrix(2,4) % Mat )
2499
TotMatrix % Submatrix(4,4) % PrecMat => Pmat
2500
ELSE
2501
Pmat => TotMatrix % Submatrix(2,2) % PrecMat
2502
IF ( ASSOCIATED(Pmat) ) CALL FreeMatrix(Pmat)
2503
2504
Pmat => CreateSchurApproximation( &
2505
TotMatrix % Submatrix(1,1) % Mat, &
2506
TotMatrix % Submatrix(2,1) % Mat, &
2507
TotMatrix % Submatrix(1,2) % Mat )
2508
TotMatrix % Submatrix(2,2) % PrecMat => Pmat
2509
END IF
2510
NULLIFY(Pmat)
2511
END IF
2512
2513
2514
str = ListGetString( Params,'Block Matrix Schur Variable', GotIt)
2515
IF( GotIt ) THEN
2516
AVAr => VariableGet( Solver % Mesh % Variables, str )
2517
IF( .NOT. ASSOCIATED( AVar ) ) THEN
2518
CALL Fatal('BlockPrecMatrix','Schur variable does not exist: '//str)
2519
END IF
2520
IF( .NOT. ASSOCIATED( AVar % Solver ) ) THEN
2521
CALL Fatal('BlockPrecMatrix','Schur solver does not exist for: '//str)
2522
END IF
2523
IF( .NOT. ASSOCIATED( AVar % Solver % Matrix ) ) THEN
2524
CALL Fatal('BlockPrecMatrix','Schur matrix does not exist for: '//str)
2525
END IF
2526
CALL Info('BlockPrecMatrix','Using Schur matrix to precondition block '//I2S(NoVar))
2527
TotMatrix % Submatrix(NoVar,NoVar) % PrecMat => AVar % Solver % Matrix
2528
END IF
2529
2530
2531
! When we have an inner-outer iteration, we could well have a different matrix
2532
! assembled for the purpose of preconditioning. Use it here, if available.
2533
IF(ListGetLogical( Params,'Block Nested System',GotIt ) ) THEN
2534
Amat => TotMatrix % Submatrix(1,1) % Mat
2535
IF( ASSOCIATED( Amat % PrecValues ) ) THEN
2536
PMat => TotMatrix % Submatrix(1,1) % PrecMat
2537
IF (.NOT. ASSOCIATED(PMat % Values)) THEN
2538
CALL Info('BlockPrecMatrix','Moving PrecValues to PrecMat!')
2539
CALL CRS_CopyMatrixTopology( AMat, PMat )
2540
ELSE
2541
! Make a partial check that PrecMat has been derived from the right template:
2542
IF (.NOT. ASSOCIATED(AMat % Rows, PMat % Rows)) &
2543
CALL Fatal('BlockPrecMatrix', 'Inconsistent matrix structures')
2544
END IF
2545
PMat % Values => Amat % PrecValues
2546
NULLIFY(Amat % PrecValues)
2547
END IF
2548
END IF
2549
2550
END SUBROUTINE BlockPrecMatrix
2551
2552
2553
! Check if matrix C that is a coupling block in the block matrix system
2554
! couples dofs at parallel interfaces. Assume that C := C_ab where a is
2555
! associated to A and b to B.
2556
!------------------------------------------------------------------------
2557
FUNCTION CheckParallelCoupling( A, B, C ) RESULT ( Coupled )
2558
TYPE(Matrix_t), POINTER :: A, B, C
2559
LOGICAL :: Coupled
2560
2561
LOGICAL :: Acoupled, Bcoupled
2562
INTEGER :: i,j,k
2563
REAL(KIND=dp) :: Eps
2564
2565
Coupled = .FALSE.
2566
IF(.NOT. ASSOCIATED( A % ParallelInfo ) ) THEN
2567
CALL Fatal('CheckParallelCoupling','Matrix A does not have ParallelInfo!')
2568
END IF
2569
IF(.NOT. ASSOCIATED( B % ParallelInfo ) ) THEN
2570
CALL Fatal('CheckParallelCoupling','Matrix B does not have ParallelInfo!')
2571
END IF
2572
2573
DO i=1,C % NumberOfRows
2574
DO j=C % Rows(i), C % Rows(i+1)-1
2575
k = C % Cols(j)
2576
IF( ABS( C % Values(j) ) < EPSILON( Eps ) ) CYCLE
2577
IF ( ASSOCIATED(A % ParallelInfo % NeighbourList(i) % Neighbours) ) THEN
2578
IF ( SIZE(A % ParallelInfo % NeighbourList(i) % Neighbours) > 1 ) Coupled = .TRUE.
2579
END IF
2580
IF ( ASSOCIATED(B % ParallelInfo % NeighbourList(k) % Neighbours) ) THEN
2581
IF ( SIZE(B % ParallelInfo % NeighbourList(k) % Neighbours) > 1 ) Coupled = .TRUE.
2582
END IF
2583
IF( Coupled ) EXIT
2584
END DO
2585
END DO
2586
2587
IF( Coupled ) THEN
2588
CALL Info('CheckParallelCoupling','Coupling matrix has parallel connections!',Level=10)
2589
ELSE
2590
CALL Info('CheckParallelCoupling','Coupling matrix does not have parallel connections!',Level=10)
2591
END IF
2592
2593
END FUNCTION CheckParallelCoupling
2594
2595
2596
!> Create the coupling blocks for a linear FSI coupling among various types of
2597
!> elasticity and fluid solvers.
2598
!--------------------------------------------------------------------------------
2599
SUBROUTINE FsiCouplingBlocks( Solver )
2600
2601
TYPE(Solver_t) :: Solver
2602
INTEGER :: i, j, k, Novar
2603
2604
TYPE(ValueList_t), POINTER :: Params
2605
TYPE(Matrix_t), POINTER :: A_fs, A_sf, A_s, A_f
2606
TYPE(Variable_t), POINTER :: FVar, SVar
2607
INTEGER, POINTER :: ConstituentSolvers(:)
2608
LOGICAL :: Found
2609
LOGICAL :: IsPlate, IsShell, IsNs, IsPres
2610
CHARACTER(*), PARAMETER :: Caller = 'FsiCouplingBlocks'
2611
2612
Params => Solver % Values
2613
ConstituentSolvers => ListGetIntegerArray(Params, 'Block Solvers', Found)
2614
2615
IsPlate = .FALSE.
2616
IsShell = .FALSE.
2617
IsNS = .FALSE.
2618
IsPres = .FALSE.
2619
2620
i = ListGetInteger( Params,'Structure Solver Index',Found)
2621
2622
IF ( Found ) THEN
2623
IsPlate = ListGetLogical( CurrentModel % Solvers(i) % Values,&
2624
'Plate Solver', Found )
2625
IsShell = ListGetLogical( CurrentModel % Solvers(i) % Values,&
2626
'Shell Solver', Found )
2627
ELSE
2628
i = ListGetInteger( Params,'Plate Solver Index',IsPlate)
2629
IF(.NOT. IsPlate ) THEN
2630
i = ListGetInteger( Params,'Shell Solver Index',IsShell)
2631
END IF
2632
END IF
2633
2634
! The first and second entries in the "Block Solvers" list define
2635
! the solver sections to assemble the (1,1)-block and (2,2)-block,
2636
! respectively. The following check is needed as the solver section
2637
! numbers may not index TotMatrix % Submatrix(:,:) directly.
2638
!
2639
IF (i > 0) THEN
2640
Found = .FALSE.
2641
DO k=1,SIZE(ConstituentSolvers)
2642
IF (i == ConstituentSolvers(k)) THEN
2643
Found = .TRUE.
2644
EXIT
2645
END IF
2646
END DO
2647
IF (.NOT. Found) THEN
2648
CALL Fatal(Caller, &
2649
'Structure/Plate/Shell Solver Index is not an entry in the Block Solvers array')
2650
ELSE
2651
i = k
2652
END IF
2653
END IF
2654
IF (i > 2) CALL Fatal(Caller, &
2655
'Use the first two entries of Block Solvers to define FSI coupling')
2656
2657
j = ListGetInteger( Params,'Fluid Solver Index',Found)
2658
IF(.NOT. Found ) THEN
2659
j = ListGetInteger( Params,'NS Solver Index', IsNs )
2660
IF( .NOT. IsNs ) THEN
2661
j = ListGetInteger( Params,'Pressure Solver Index',IsPres)
2662
END IF
2663
END IF
2664
2665
IF (j > 0) THEN
2666
Found = .FALSE.
2667
DO k=1,SIZE(ConstituentSolvers)
2668
IF (j == ConstituentSolvers(k)) THEN
2669
Found = .TRUE.
2670
EXIT
2671
END IF
2672
END DO
2673
IF (.NOT. Found) THEN
2674
CALL Fatal(Caller, &
2675
'Fluid/NS/Pressure Solver Index is not an entry in the Block Solvers array')
2676
ELSE
2677
j = k
2678
END IF
2679
END IF
2680
IF (j > 2) CALL Fatal(Caller, &
2681
'Use the first two entries of Block Solvers to define FSI coupling')
2682
2683
IF( j == 0 ) THEN
2684
IF( i > 1 .AND. TotMatrix % NoVar == 2 ) j = 3 - i
2685
END IF
2686
IF( i == 0 ) THEN
2687
IF( j > 1 .AND. TotMatrix % NoVar == 2 ) i = 3 - j
2688
END IF
2689
2690
IF(i<=0 .OR. j<=0) THEN
2691
IF( i > 0 ) CALL Warn(Caller,'Structure solver given but not fluid!')
2692
IF( j > 0 ) CALL Warn(Caller,'Fluid solver given but not structure!')
2693
RETURN
2694
END IF
2695
2696
! IF (i > TotMatrix % NoVar .OR. j > TotMatrix % NoVar) &
2697
! CALL Fatal(Caller,'Use solver sections 1 and 2 to define FSI coupling')
2698
2699
A_fs => TotMatrix % Submatrix(j,i) % Mat
2700
A_sf => TotMatrix % Submatrix(i,j) % Mat
2701
2702
IF(.NOT. ASSOCIATED( A_fs ) ) THEN
2703
CALL Fatal(Caller,'Fluid-structure coupling matrix not allocated!')
2704
END IF
2705
IF(.NOT. ASSOCIATED( A_sf ) ) THEN
2706
CALL Fatal(Caller,'Structure-fluid coupling matrix not allocated!')
2707
END IF
2708
2709
SVar => TotMatrix % Subvector(i) % Var
2710
FVar => TotMatrix % Subvector(j) % Var
2711
2712
A_s => TotMatrix % Submatrix(i,i) % Mat
2713
A_f => TotMatrix % Submatrix(j,j) % Mat
2714
2715
IF(.NOT. ASSOCIATED( FVar ) ) THEN
2716
CALL Fatal(Caller,'Fluid variable not present!')
2717
END IF
2718
IF(.NOT. ASSOCIATED( FVar ) ) THEN
2719
CALL Fatal(Caller,'Structure variable not present!')
2720
END IF
2721
2722
IF(.NOT. (IsNs .OR. IsPres ) ) THEN
2723
IsPres = ( FVar % Dofs <= 2 )
2724
IsNs = .NOT. IsPres
2725
END IF
2726
2727
CALL FsiCouplingAssembly( Solver, FVar, SVar, A_f, A_s, A_fs, A_sf, &
2728
IsPlate, IsShell, IsNS )
2729
2730
IF( ParEnv % PEs > 1 ) THEN
2731
TotMatrix % Submatrix(i,j) % ParallelSquareMatrix = .FALSE.
2732
TotMatrix % Submatrix(j,i) % ParallelSquareMatrix = .FALSE.
2733
2734
TotMatrix % Submatrix(i,j) % ParallelIsolatedMatrix = &
2735
.NOT. CheckParallelCoupling(A_s, A_f, A_sf )
2736
TotMatrix % Submatrix(j,i) % ParallelIsolatedMatrix = &
2737
.NOT. CheckParallelCoupling(A_f, A_s, A_fs )
2738
END IF
2739
2740
2741
END SUBROUTINE FsiCouplingBlocks
2742
2743
2744
!> Create the coupling between elasticity solvers of various types.
2745
!--------------------------------------------------------------------------------
2746
SUBROUTINE StructureCouplingBlocks( Solver )
2747
2748
TYPE(Solver_t) :: Solver
2749
2750
INTEGER :: i,j,k,ind1,ind2,Novar,Nsol
2751
INTEGER, POINTER :: ConstituentSolvers(:)
2752
LOGICAL :: Found
2753
TYPE(ValueList_t), POINTER :: Params, ShellParams
2754
TYPE(Matrix_t), POINTER :: A_fs, A_sf, A_s, A_f
2755
TYPE(Variable_t), POINTER :: FVar, SVar
2756
LOGICAL :: IsPlate, IsShell, IsBeam, IsSolid, GotBlockSolvers
2757
LOGICAL :: DrillingDOFs
2758
TYPE(Solver_t), POINTER :: PSol
2759
CHARACTER(*), PARAMETER :: Caller = 'StructureCouplingBlocks'
2760
2761
2762
Params => Solver % Values
2763
ConstituentSolvers => ListGetIntegerArray(Params, 'Block Solvers', GotBlockSolvers)
2764
IF(.NOT. GotBlockSolvers ) THEN
2765
CALL Fatal(Caller,'We need "Block Solvers" defined!')
2766
END IF
2767
2768
! Currently we simply assume the master solver to be listed as the first entry in
2769
! the 'Block Solvers' array.
2770
i = 1
2771
SVar => TotMatrix % Subvector(i) % Var
2772
IF(.NOT. ASSOCIATED( SVar ) ) THEN
2773
CALL Fatal(Caller,'Master structure variable not present!')
2774
END IF
2775
A_s => TotMatrix % Submatrix(i,i) % Mat
2776
2777
Nsol = SIZE( ConstituentSolvers )
2778
2779
2780
DO j = 1, Nsol
2781
! No need to couple to one self!
2782
IF(j==1) CYCLE
2783
IF (j > size(ConstituentSolvers)) CALL Fatal(Caller, &
2784
'Solid/Plate/Shell/Beam Solver Index larger than Block Solvers array')
2785
2786
k = ConstituentSolvers(j)
2787
PSol => CurrentModel % Solvers(k)
2788
2789
IsSolid = ListGetLogical( Psol % Values,'Solid Solver',IsSolid)
2790
IsPlate = ListGetLogical( Psol % Values,'Plate Solver',IsPlate)
2791
IsShell = ListGetLogical( Psol % Values,'Shell Solver',IsShell)
2792
IsBeam = ListGetLogical( Psol % Values,'Beam Solver',IsBeam)
2793
2794
ind1 = ConstituentSolvers(i)
2795
ind2 = ConstituentSolvers(j)
2796
CALL Info(Caller,'Generating coupling between solvers '&
2797
//I2S(ind1)//' and '//I2S(ind2))
2798
2799
2800
A_fs => TotMatrix % Submatrix(j,i) % Mat
2801
A_sf => TotMatrix % Submatrix(i,j) % Mat
2802
2803
!SVar => TotMatrix % Subvector(i) % Var
2804
FVar => TotMatrix % Subvector(j) % Var
2805
IF(.NOT. ASSOCIATED( FVar ) ) THEN
2806
CALL Fatal(Caller,'Slave structure variable not present!')
2807
END IF
2808
2809
!A_s => TotMatrix % Submatrix(i,i) % Mat
2810
A_f => TotMatrix % Submatrix(j,j) % Mat
2811
2812
IF (IsShell) THEN
2813
ShellParams => Fvar % Solver % Values
2814
DrillingDOFs = GetLogical(ShellParams, 'Drilling DOFs', Found)
2815
ELSE
2816
DrillingDOFs = .FALSE.
2817
END IF
2818
2819
CALL StructureCouplingAssembly( Solver, FVar, SVar, A_f, A_s, A_fs, A_sf, &
2820
IsSolid, IsPlate, IsShell, IsBeam, DrillingDOFs)
2821
2822
IF( ParEnv % PEs > 1 ) THEN
2823
TotMatrix % Submatrix(i,j) % ParallelSquareMatrix = .FALSE.
2824
TotMatrix % Submatrix(j,i) % ParallelSquareMatrix = .FALSE.
2825
2826
TotMatrix % Submatrix(i,j) % ParallelIsolatedMatrix = &
2827
.NOT. CheckParallelCoupling(A_s, A_f, A_sf )
2828
TotMatrix % Submatrix(j,i) % ParallelIsolatedMatrix = &
2829
.NOT. CheckParallelCoupling(A_f, A_s, A_fs )
2830
END IF
2831
2832
END DO
2833
2834
END SUBROUTINE StructureCouplingBlocks
2835
2836
2837
! This is tailored L2 norm for the many use types of the block solver.
2838
!---------------------------------------------------------------------
2839
FUNCTION CompNorm( x, n, npar, A) RESULT ( nrm )
2840
REAL(KIND=dp) :: x(:)
2841
INTEGER :: n
2842
INTEGER, OPTIONAL :: npar
2843
TYPE(Matrix_t), POINTER, OPTIONAL :: A
2844
REAL(KIND=dp) :: nrm
2845
2846
INTEGER :: i,m
2847
REAL(KIND=dp) :: s,stot,ntot
2848
2849
IF( ParEnv % PEs > 1 .AND. PRESENT( A ) ) THEN
2850
m = 0
2851
s = 0.0_dp
2852
DO i=1,A % NumberOfRows
2853
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(i) % Neighbours(1)) CYCLE
2854
m = m+1
2855
s = s + x(i)**2
2856
END DO
2857
ELSE
2858
IF( ParEnv % PEs > 1 .AND. PRESENT( npar ) ) THEN
2859
m = npar
2860
ELSE
2861
m = n
2862
END IF
2863
s = SUM(x(1:m)**2)
2864
END IF
2865
2866
stot = ParallelReduction(s)
2867
ntot = ParallelReduction(m)
2868
2869
nrm = SQRT( stot / ntot )
2870
2871
END FUNCTION CompNorm
2872
2873
2874
!------------------------------------------------------------------------------
2875
!> Compute the rhs for the block matrix system which is solved
2876
!> accounting only the diagonal entries i.e. subtract the non-diagonal
2877
!> matrix-vector results from the original r.h.s. vectors.
2878
!> After this the block diagonal problem Ax=b may be solved.
2879
!----------------------------------------------------------------------------------
2880
SUBROUTINE BlockUpdateRhs( BlockMatrix, ThisRow )
2881
2882
TYPE(BlockMatrix_t), TARGET :: BlockMatrix
2883
INTEGER, OPTIONAL :: ThisRow
2884
2885
TYPE(Matrix_t), POINTER :: A
2886
INTEGER :: n, NoRow,NoCol, NoVar
2887
REAL(KIND=dp), POINTER :: x(:),rtmp(:),rhs(:)
2888
REAL(KIND=dp) :: bnorm
2889
TYPE(Variable_t), POINTER :: Var
2890
2891
CALL Info('BlockUpdateRhs','Computing block r.h.s',Level=8)
2892
2893
NoVar = BlockMatrix % NoVar
2894
2895
! The residual is used only as a temporary vector
2896
ALLOCATE( rtmp(BlockMatrix % MaxSize) )
2897
2898
2899
DO NoRow = 1,NoVar
2900
2901
! Optionally only one diagonal block may be updated for
2902
IF( PRESENT( ThisRow ) ) THEN
2903
IF( NoRow /= ThisRow ) CYCLE
2904
END IF
2905
2906
Var => BlockMatrix % SubVector(NoRow) % Var
2907
x => Var % Values
2908
n = SIZE( x )
2909
2910
! The r.h.s. of the initial system is stored in the Matrix
2911
!-----------------------------------------------------------
2912
IF(.NOT. ALLOCATED( BlockMatrix % SubVector(NoRow) % rhs )) THEN
2913
ALLOCATE( BlockMatrix % SubVector(NoRow) % rhs(n) )
2914
CALL Info('BlockUpdateRhs','Creating rhs for component: '//I2S(NoRow),Level=12)
2915
END IF
2916
rhs => BlockMatrix % SubVector(NoRow) % rhs
2917
rhs = 0.0_dp
2918
2919
A => BlockMatrix % SubMatrix( NoRow, NoRow ) % Mat
2920
IF( ASSOCIATED( A ) ) THEN
2921
IF( ASSOCIATED( A % rhs ) ) rhs = A % rhs
2922
END IF
2923
2924
DO NoCol = 1,NoVar
2925
! This ensures that the diagonal itself is not subtracted
2926
! before computing the bnorm used to estimate the convergence.
2927
IF( NoCol == NoRow ) CYCLE
2928
2929
Var => BlockMatrix % SubVector(NoCol) % Var
2930
x => Var % Values
2931
2932
A => BlockMatrix % SubMatrix( NoRow, NoCol ) % Mat
2933
IF( A % NumberOfRows == 0 ) CYCLE
2934
2935
CALL CRS_MatrixVectorMultiply( A, x, rtmp)
2936
rhs(1:n) = rhs(1:n) - rtmp(1:n)
2937
END DO
2938
2939
2940
bnorm = CompNorm(rhs,n)
2941
BlockMatrix % SubVector(NoRow) % bnorm = bnorm
2942
2943
! Finally deduct the diagonal entry so that we can solve for the residual
2944
NoCol = NoRow
2945
Var => BlockMatrix % SubVector(NoCol) % Var
2946
x => Var % Values
2947
A => BlockMatrix % SubMatrix( NoRow, NoCol ) % Mat
2948
IF( A % NumberOfRows > 0 ) THEN
2949
CALL CRS_MatrixVectorMultiply( A, x, rtmp)
2950
rhs(1:n) = rhs(1:n) - rtmp(1:n)
2951
END IF
2952
2953
END DO
2954
2955
DEALLOCATE( rtmp )
2956
2957
END SUBROUTINE BlockUpdateRhs
2958
2959
2960
!------------------------------------------------------------------------------
2961
!> Perform matrix-vector product v=Au for block matrices.
2962
!> Has to be callable outside the module by Krylov methods.
2963
!------------------------------------------------------------------------------
2964
!------------------------------------------------------------------------------
2965
SUBROUTINE BlockMatrixVectorProd( u,v,ipar )
2966
!------------------------------------------------------------------------------
2967
REAL(KIND=dp), INTENT(in) :: u(*)
2968
REAL(KIND=dp), INTENT(out) :: v(*)
2969
INTEGER, INTENT(in) :: ipar(*)
2970
2971
INTEGER :: n,i,j,k,NoVar,i1,i2,j1,j2,ll,kk
2972
REAL(KIND=dp), ALLOCATABLE :: s(:)
2973
INTEGER :: maxsize,ndofs
2974
INTEGER, POINTER :: Offset(:)
2975
REAL(KIND=dp) :: nrm
2976
TYPE(Matrix_t), POINTER :: A
2977
REAL(KIND=dp), POINTER :: b(:)
2978
2979
LOGICAL :: Isolated
2980
LOGICAL :: DoSum , DoAMGXMV, Found
2981
2982
DoAMGXMV = ListGetLogical( SolverRef % Values, 'Block AMGX M-V', Found)
2983
2984
CALL Info('BlockMatrixVectorProd','Starting block matrix multiplication',Level=20)
2985
2986
NoVar = TotMatrix % NoVar
2987
MaxSize = TotMatrix % MaxSize
2988
ALLOCATE( s(MaxSize) )
2989
2990
IF( isParallel ) THEN
2991
Offset => TotMatrix % ParOffset
2992
ELSE
2993
Offset => TotMatrix % Offset
2994
END IF
2995
2996
v(1:offset(NoVar+1)) = 0
2997
2998
DO i=1,NoVar
2999
DO j=1,NoVar
3000
s = 0._dp
3001
3002
j1 = offset(j)+1
3003
j2 = offset(j+1)
3004
3005
IF ( ListGetLogical(SolverRef % Values, 'Dummy block'//I2S(i), Found) ) CYCLE
3006
A => TotMatrix % SubMatrix(i,j) % Mat
3007
IF ( .NOT. ASSOCIATED(A) ) CYCLE
3008
IF ( A % NumberOfRows == 0) CYCLE
3009
Isolated = TotMatrix % SubMatrix(i,j) % ParallelIsolatedMatrix
3010
3011
CALL Info('BlockMatrixVectorProd','Multiplying with submatrix ('&
3012
//I2S(i)//','//I2S(j)//')',Level=15)
3013
3014
IF (isParallel) THEN
3015
IF( ASSOCIATED( A % ParMatrix ) ) THEN
3016
CALL ParallelMatrixVector( A, u(j1:j2), s )
3017
ELSE IF( Isolated ) THEN
3018
CALL CRS_MatrixVectorMultiply( A, u(j1:j2), s )
3019
ELSE
3020
CALL Fatal('BlockMatrixVectorProd','Cannot make the matric-vector product in parallel!')
3021
END IF
3022
ELSE
3023
IF ( DoAMGXMV ) THEN
3024
CALL AMGXMatrixVectorMultiply(A, u(j1:j2), s, SolverRef )
3025
ELSE
3026
CALL CRS_MatrixVectorMultiply( A, u(j1:j2), s )
3027
END IF
3028
END IF
3029
3030
IF( InfoActive( 25 ) ) THEN
3031
PRINT *,'MatVecProdNorm u:',i,j,&
3032
SQRT(SUM(u(j1:j2)**2)),SUM( u(j1:j2) ), MINVAL( u(j1:j2) ), MAXVAL( u(j1:j2) )
3033
PRINT *,'MatVecProdNorm s:',i,j,&
3034
SQRT(SUM(s**2)), SUM( s ), MINVAL( s ), MAXVAL( s )
3035
END IF
3036
3037
v(offset(i)+1:offset(i+1)) = v(offset(i)+1:offset(i+1)) + s(1:offset(i+1)-offset(i))
3038
END DO
3039
3040
IF( InfoActive( 25 ) ) THEN
3041
i1 = offset(i)+1
3042
i2 = offset(i+1)
3043
b => TotMatrix % Submatrix(i,i) % Mat % Rhs
3044
IF( ASSOCIATED( b ) ) THEN
3045
PRINT *,'MatVecProdNorm b:',i,&
3046
SQRT(SUM(b**2)),SUM( b ), MINVAL( b ), MAXVAL( b )
3047
END IF
3048
PRINT *,'MatVecProdNorm v:',i,&
3049
SQRT(SUM(v(i1:i2)**2)), SUM( v(i1:i2) ), MINVAL( v(i1:i2) ), MAXVAL( v(i1:i2) )
3050
END IF
3051
END DO
3052
3053
IF( InfoActive( 25 ) ) THEN
3054
n = offset(NoVar+1)
3055
nrm = CompNorm(v(1:n),n)
3056
WRITE( Message,'(A,ES12.5)') 'Mv result norm: ',nrm
3057
CALL Info('BlockMatrixVectorProd',Message )
3058
END IF
3059
3060
CALL Info('BlockMatrixVectorProd','Finished block matrix multiplication',Level=20)
3061
!------------------------------------------------------------------------------
3062
END SUBROUTINE BlockMatrixVectorProd
3063
!------------------------------------------------------------------------------
3064
3065
3066
!------------------------------------------------------------------------------
3067
!> Given a permutation between monolithic and block matrix solutions
3068
!> create a map between the owned dofs for the same in parallel.
3069
!------------------------------------------------------------------------------
3070
SUBROUTINE ParallelShrinkPerm()
3071
TYPE(Matrix_t), POINTER :: A, Adiag
3072
INTEGER, POINTER :: BlockPerm(:), ParBlockPerm(:), ParPerm(:)
3073
INTEGER :: i,j,k,l,n,m
3074
INTEGER, ALLOCATABLE :: ShrinkPerm(:),RenumPerm(:)
3075
LOGICAL :: Halt
3076
3077
n = TotMatrix % TotSize
3078
Halt = .FALSE.
3079
3080
! Example of blockperm: block solution u to monolithic solution v
3081
! v(1:n) = u(BlockPerm(1:n))
3082
3083
! Dense numbering the monolithic dofs
3084
A => TotMatrix % ParentMatrix
3085
IF(.NOt. ASSOCIATED(A) ) A => SolverMatrix
3086
3087
IF( ASSOCIATED( A ) ) THEN
3088
CALL Info('ParallelShrinkPerm','Using the monolithic matrix to deduce permutation',Level=6)
3089
ELSE
3090
CALL Info('ParallelShrinkPerm','Using the block matrix to deduce permutation',Level=6)
3091
END IF
3092
3093
ALLOCATE(ShrinkPerm(n))
3094
3095
DO j=1,TotMatrix % Novar
3096
Adiag => TotMatrix % Submatrix(j,j) % Mat
3097
IF(.NOT. ASSOCIATED( Adiag % ParallelInfo ) ) CYCLE
3098
k = 0
3099
l = 0
3100
m = 0
3101
ShrinkPerm(1:Adiag % NumberOfRows) = 0
3102
DO i=1,Adiag % NumberOfRows
3103
k = k + 1
3104
IF (Parenv % MyPE /= Adiag % ParallelInfo % NeighbourList(i) % Neighbours(1)) THEN
3105
m = m+1
3106
CYCLE
3107
END IF
3108
l = l+1
3109
ShrinkPerm(k) = l
3110
END DO
3111
3112
IF(ASSOCIATED(TotMatrix % Submatrix(j,j) % ParPerm )) THEN
3113
k = SIZE(TotMatrix % SubMatrix(j,j) % ParPerm)
3114
IF(k /= l) THEN
3115
CALL Warn('ParallelShrinkPerm','Different size for ParPerm '&
3116
//I2S(l)//': '//I2S(k)//' vs. '//I2S(l))
3117
PRINT *,'ParBlockPerm skipped1',ParEnv % MyPe, m, j
3118
DEALLOCATE(TotMatrix % SubMatrix(j,j) % ParPerm )
3119
Halt = .TRUE.
3120
END IF
3121
END IF
3122
3123
IF(.NOT. ASSOCIATED(TotMatrix % Submatrix(j,j) % ParPerm ) ) THEN
3124
ALLOCATE( TotMatrix % Submatrix(j,j) % ParPerm(l) )
3125
END IF
3126
ParPerm => TotMatrix % Submatrix(j,j) % ParPerm
3127
ParPerm = 0
3128
DO i=1,Adiag % NumberOfRows
3129
k = ShrinkPerm(i)
3130
IF(k==0) CYCLE
3131
ParPerm(k) = i
3132
END DO
3133
END DO
3134
3135
m = 0
3136
3137
ShrinkPerm = 0
3138
IF( ASSOCIATED( A ) ) THEN
3139
l = 0
3140
DO i=1,A % NumberOfRows
3141
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(i) % Neighbours(1)) THEN
3142
m = m+1
3143
CYCLE
3144
END IF
3145
l = l+1
3146
ShrinkPerm(i) = l
3147
END DO
3148
END IF
3149
3150
IF(.NOT. ASSOCIATED(TotMatrix % ParPerm) ) THEN
3151
ALLOCATE( TotMatrix % ParPerm(l) )
3152
END IF
3153
ParPerm => TotMatrix % ParPerm
3154
ParPerm = 0
3155
DO i=1,n
3156
j = ShrinkPerm(i)
3157
IF(j==0) CYCLE
3158
ParPerm(j) = i
3159
END DO
3160
3161
3162
IF(.NOT. ASSOCIATED(TotMatrix % ParOffset) ) THEN
3163
ALLOCATE( TotMatrix % ParOffset(TotMatrix % NoVar+1))
3164
END IF
3165
TotMatrix % ParOffset = 0
3166
k = 0
3167
l = 0
3168
DO j=1,TotMatrix % Novar
3169
m = 0
3170
A => TotMatrix % Submatrix(j,j) % Mat
3171
DO i=1,A % NumberOfRows
3172
k = k + 1
3173
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(i) % Neighbours(1)) THEN
3174
m = m+1
3175
CYCLE
3176
END IF
3177
l = l+1
3178
END DO
3179
TotMatrix % ParOffset(j+1) = l
3180
END DO
3181
3182
3183
CALL Info('ParallelShrinkPerm','Number of parallel dofs in this partition: '// &
3184
I2S(l)//' / '//I2S(n), Level=6)
3185
3186
! We can only make the ParBlockPerm if also BlockPerm exists!
3187
BlockPerm => TotMatrix % BlockPerm
3188
IF(.NOT. ASSOCIATED(BlockPerm) ) THEN
3189
IF(Halt) STOP
3190
RETURN
3191
END IF
3192
3193
! Dense numbering for the block system dofs
3194
ALLOCATE(RenumPerm(n))
3195
RenumPerm = 1
3196
DO i=1,n
3197
j = BlockPerm(i)
3198
IF( ShrinkPerm(j) == 0 ) RenumPerm(i) = 0
3199
END DO
3200
l = 0
3201
DO i=1,n
3202
IF(RenumPerm(i) > 0) THEN
3203
l=l+1
3204
RenumPerm(i) = l
3205
END IF
3206
END DO
3207
3208
! Allocate the parallel permutation, if not already done
3209
IF(ASSOCIATED(TotMatrix % ParBlockPerm)) THEN
3210
k = SIZE(TotMatrix % ParBlockPerm)
3211
IF(k /= l) THEN
3212
CALL Warn('ParallelShrinkPerm','Different size for ParBlockPerm: '//I2S(k)//' vs. '//I2S(l))
3213
PRINT *,'ParBlockPerm skipped2',ParEnv % MyPe, m
3214
DEALLOCATE(TotMatrix % ParBlockPerm)
3215
Halt = .TRUE.
3216
END IF
3217
END IF
3218
IF(.NOT. ASSOCIATED(TotMatrix % ParBlockPerm) ) THEN
3219
ALLOCATE(TotMatrix % ParBlockPerm(l))
3220
END IF
3221
ParBlockPerm => TotMatrix % ParBlockPerm
3222
ParBlockPerm = 0
3223
3224
! And finally create the renumbering scheme.
3225
! This was tough to settle. Don't doubt it!
3226
DO i=1,n
3227
IF(RenumPerm(i)==0) CYCLE
3228
ParBlockPerm(RenumPerm(i)) = ShrinkPerm(BlockPerm(i))
3229
END DO
3230
3231
IF(Halt) STOP
3232
3233
END SUBROUTINE ParallelShrinkPerm
3234
3235
3236
!------------------------------------------------------------------------------
3237
! If the block matrix is just a remake of the monolithic one we may actually
3238
! use the monolithic version when we make the necessary permutations.
3239
! The advantage may be that we have an alternative (more simple) routine for
3240
! debugging and it may also be faster...
3241
! Note that here u and v only include the owned dofs for each partition.
3242
! Hence if we want to make a standard matrix-vector product we need to expand
3243
! these to include all dofs.
3244
!------------------------------------------------------------------------------
3245
SUBROUTINE BlockMatrixVectorProdMono( u,v,ipar )
3246
!------------------------------------------------------------------------------
3247
REAL(KIND=dp), INTENT(in) :: u(*)
3248
REAL(KIND=dp), INTENT(out) :: v(*)
3249
INTEGER, INTENT(in) :: ipar(*)
3250
3251
INTEGER :: n,m,i,j,k,NoVar,i1,i2,j1,j2
3252
REAL(KIND=dp), ALLOCATABLE :: s(:)
3253
INTEGER :: maxsize,ndofs
3254
INTEGER, POINTER :: Offset(:)
3255
REAL(KIND=dp) :: nrm
3256
TYPE(Matrix_t), POINTER :: A
3257
REAL(KIND=dp), POINTER :: b(:)
3258
LOGICAL :: DoSum, GotBlockStruct
3259
REAL(KIND=dp), POINTER :: utmp(:),vtmp(:)
3260
INTEGER, POINTER :: BlockPerm(:)
3261
3262
CALL Info('BlockMatrixVectorProdMono','Starting monolithic matrix multiplication',Level=20)
3263
3264
IF(.NOT.ASSOCIATED(SolverMatrix)) THEN
3265
CALL Fatal('BlockMatrixVectorProdMono','No matrix to apply.')
3266
END IF
3267
3268
NoVar = TotMatrix % NoVar
3269
MaxSize = TotMatrix % MaxSize
3270
GotBlockStruct = TotMatrix % GotBlockStruct
3271
3272
n = ipar(3)
3273
3274
IF(isParallel) THEN
3275
BlockPerm => TotMatrix % ParBlockPerm
3276
IF(.NOT. ASSOCIATED( BlockPerm ) ) THEN
3277
BlockPerm => TotMatrix % ParPerm
3278
END IF
3279
IF(.NOT. ASSOCIATED(BlockPerm) ) THEN
3280
CALL Fatal('BlockMatrixVectorProdMono','How come there is no permutation in parallel?')
3281
END IF
3282
Offset => TotMatrix % ParOffset
3283
ELSE
3284
BlockPerm => TotMatrix % BlockPerm
3285
Offset => TotMatrix % Offset
3286
END IF
3287
3288
IF( ASSOCIATED( BlockPerm ) ) THEN
3289
IF(InfoActive(20)) THEN
3290
i = MAXVAL( BlockPerm )
3291
j = MINVAL( BlockPerm )
3292
IF( j <= 0 .OR. i > n ) THEN
3293
CALL Fatal('BlockMatrixVectorProdMono','Invalid sizes: '&
3294
//I2S(i)//' '//I2S(j)//' '//I2S(n)//' '//I2S(SIZE(BlockPerm)))
3295
END IF
3296
CALL Info('BlockMatrixVectorProdMono','BlockPermSizes: '//I2S(i)//' '//I2S(j)//' '//I2S(n))
3297
END IF
3298
END IF
3299
3300
3301
IF(isParallel) THEN
3302
! Reorder & copy block variable to monolithic variable
3303
m = SolverMatrix % NumberOfRows
3304
ALLOCATE(utmp(m),vtmp(m))
3305
utmp(1:m) = 0.0_dp
3306
utmp(BlockPerm(1:n)) = u(1:n)
3307
CALL ParallelMatrixVector(SolverMatrix, utmp(1:m), vtmp(1:m) )
3308
v(1:n) = vtmp(BlockPerm(1:n))
3309
DEALLOCATE(utmp,vtmp)
3310
ELSE
3311
IF( ASSOCIATED( BlockPerm ) ) THEN
3312
! Only reorder between block and monolithic ordering
3313
ALLOCATE(utmp(n))
3314
utmp(BlockPerm(1:n)) = u(1:n)
3315
CALL CRS_MatrixVectorMultiply( SolverMatrix, utmp, v )
3316
v(1:n) = v(BlockPerm(1:n))
3317
ELSE
3318
CALL CRS_MatrixVectorMultiply( SolverMatrix, u(1:n), v(1:n) )
3319
END IF
3320
END IF
3321
3322
IF( InfoActive( 25 ) ) THEN
3323
nrm = CompNorm(v(1:n),n)
3324
WRITE( Message,'(A,ES12.5)') 'Mv result norm: ',nrm
3325
CALL Info('BlockMatrixVectorProdMono',Message )
3326
END IF
3327
3328
CALL Info('BlockMatrixVectorProdMono','Finished block matrix multiplication',Level=20)
3329
!------------------------------------------------------------------------------
3330
END SUBROUTINE BlockMatrixVectorProdMono
3331
!------------------------------------------------------------------------------
3332
3333
3334
3335
!> Create the vectors needed for block matrix scaling. Currently only
3336
!> real and complex valued row equilibration is supported. Does not perform
3337
!> the actual scaling.
3338
!------------------------------------------------------------------------------
3339
SUBROUTINE CreateBlockMatrixScaling( )
3340
!------------------------------------------------------------------------------
3341
IMPLICIT NONE
3342
3343
INTEGER :: i,j,k,l,n,m,NoVar,istat
3344
REAL(KIND=dp) :: nrm, tmp, blocknrm
3345
TYPE(Matrix_t), POINTER :: A
3346
REAL(KIND=dp), POINTER :: b(:), Diag(:), Values(:)
3347
LOGICAL :: ComplexMatrix, GotIt, DiagOnly, PrecScale
3348
INTEGER, POINTER :: Rows(:), Cols(:)
3349
LOGICAL :: Found
3350
TYPE(ValueList_t), POINTER :: Params
3351
TYPE(Variable_t), POINTER :: SolverVar
3352
CHARACTER(*), PARAMETER :: Caller = 'CreateBlockMatrixScaling'
3353
3354
CALL Info(Caller,'Starting block matrix row equilibration',Level=20)
3355
3356
NoVar = TotMatrix % NoVar
3357
3358
Params => CurrentModel % Solver % Values
3359
DiagOnly = ListGetLogical( Params,'Block Scaling Diagonal',Found )
3360
IF( DiagOnly ) THEN
3361
CALL Info(Caller,'Considering only diagonal matrices in scaling',Level=20)
3362
END IF
3363
3364
PrecScale = ListGetLogical( Params,'Block Scaling PrecMatrix',Found )
3365
3366
m = 0
3367
DO k=1,NoVar
3368
A => TotMatrix % SubMatrix(k,k) % Mat
3369
n = A % NumberOfRows
3370
IF(.NOT. ASSOCIATED(TotMatrix % Subvector )) THEN
3371
CALL Fatal(Caller,'Subvector not associated!')
3372
END IF
3373
IF( ASSOCIATED(TotMatrix % Subvector(k) % Var) ) THEN
3374
! We might have a constraint and then the block diagonal matrix may not exist.
3375
n = MAX(n, SIZE(TotMatrix % SubVector(k) % Var % Values) )
3376
END IF
3377
3378
IF( .NOT. ALLOCATED( Totmatrix % SubVector(k) % DiagScaling ) ) THEN
3379
m = m + 1
3380
ALLOCATE( TotMatrix % SubVector(k) % DiagScaling(n), STAT=istat )
3381
IF( istat /= 0 ) THEN
3382
CALL Fatal(Caller,'Cannot allocate scaling vectors '//I2S(k)//' of size: '//I2S(n))
3383
END IF
3384
CALL Info(Caller,'Allocated scaling vector of size '//I2S(n)//' to block '//I2S(k),Level=20)
3385
END IF
3386
END DO
3387
IF( m > 0 ) THEN
3388
CALL Info(Caller,'Allocated '//I2S(m)//' scaling vectors for rhs!',Level=8)
3389
END IF
3390
3391
3392
GotIt = .FALSE.
3393
blocknrm = 0.0_dp
3394
ComplexMatrix = .FALSE.
3395
DO k=1,NoVar
3396
A => TotMatrix % SubMatrix(k,k) % Mat
3397
IF( ASSOCIATED( A ) ) THEN
3398
IF( A % NumberOfRows > 0 .AND. .NOT. GotIt) THEN
3399
GotIt = .TRUE.
3400
! We assume that if complex flag is not found for k>1 it is inherited from previous ones.
3401
ComplexMatrix = A % COMPLEX
3402
IF( ComplexMatrix ) THEN
3403
m = 2
3404
CALL Info(Caller,'Assuming complex block matrix in scaling!',Level=20)
3405
ELSE
3406
m = 1
3407
CALL Info(Caller,'Assuming real valued block matrix in scaling!',Level=20)
3408
END IF
3409
END IF
3410
END IF
3411
IF(.NOT. GotIt) CALL Warn(Caller,'Improve complex matrix detection!')
3412
3413
Diag => TotMatrix % SubVector(k) % DiagScaling
3414
Diag = 0.0_dp
3415
3416
3417
DO l=1,NoVar
3418
IF( DiagOnly ) THEN
3419
IF( k /= l ) CYCLE
3420
END IF
3421
3422
Found = .FALSE.
3423
IF(k==l .AND. PrecScale ) THEN
3424
A => TotMatrix % Submatrix(k,k) % PrecMat
3425
Found = ( A % NumberOfRows > 0 )
3426
IF(Found) THEN
3427
CALL Info(Caller,'Using PrecMat to define the scaling of block row '//I2S(k),Level=20)
3428
END IF
3429
END IF
3430
3431
IF(.NOT.Found) THEN
3432
A => TotMatrix % Submatrix(k,l) % Mat
3433
END IF
3434
IF(.NOT. ASSOCIATED( A ) ) CYCLE
3435
3436
n = A % NumberOfRows
3437
IF( n == 0 ) CYCLE
3438
3439
Rows => A % Rows
3440
Cols => A % Cols
3441
Values => A % Values
3442
3443
!---------------------------------------------
3444
! Compute 1-norm of each row
3445
!---------------------------------------------
3446
DO i=1,n,m
3447
tmp = 0.0_dp
3448
3449
IF( ComplexMatrix ) THEN
3450
DO j=Rows(i),Rows(i+1)-1,2
3451
tmp = tmp + SQRT( Values(j)**2 + Values(j+1)**2 )
3452
END DO
3453
ELSE
3454
DO j=Rows(i),Rows(i+1)-1
3455
tmp = tmp + ABS(Values(j))
3456
END DO
3457
END IF
3458
3459
! Compute the sum to the real component, scaling for imaginary will be the same
3460
Diag(i) = Diag(i) + tmp
3461
END DO
3462
END DO
3463
3464
IF (ParEnv % PEs > 1) THEN
3465
A => TotMatrix % SubMatrix(k,k) % Mat
3466
IF( A % NumberOfRows > 0 ) THEN
3467
! We need the parallel info that is only available in the matrix.
3468
CALL ParallelSumVector(A, Diag)
3469
END IF
3470
END IF
3471
3472
n = SIZE(Diag)
3473
nrm = MAXVAL(Diag(1:n))
3474
IF( ParEnv % PEs > 1 ) THEN
3475
nrm = ParallelReduction(nrm,2)
3476
END IF
3477
blocknrm = MAX(blocknrm,nrm)
3478
3479
! Define the actual scaling vector (for real component)
3480
DO i=1,n,m
3481
IF (Diag(i) > EPSILON( nrm ) ) THEN
3482
Diag(i) = 1.0_dp / Diag(i)
3483
ELSE
3484
Diag(i) = 1.0_dp
3485
END IF
3486
END DO
3487
3488
! Scaling of complex component
3489
IF( ComplexMatrix ) Diag(2::2) = Diag(1::2)
3490
3491
WRITE( Message,'(A,ES12.5)') 'Unscaled matrix norm for block '//I2S(k)//': ', nrm
3492
CALL Info(Caller, Message, Level=10 )
3493
END DO
3494
3495
WRITE( Message,'(A,ES12.5)') 'Unscaled matrix norm: ', blocknrm
3496
CALL Info(Caller, Message, Level=7 )
3497
3498
END SUBROUTINE CreateBlockMatrixScaling
3499
!------------------------------------------------------------------------------
3500
3501
3502
!------------------------------------------------------------------------------
3503
SUBROUTINE BlockMatrixInfo()
3504
!------------------------------------------------------------------------------
3505
IMPLICIT NONE
3506
INTEGER :: i,j,k,l,n,m,NoVar
3507
INTEGER(KIND=8) :: ll
3508
REAL(KIND=dp) :: nrm, tmp, blocknrm
3509
TYPE(Matrix_t), POINTER :: A
3510
REAL(KIND=dp), POINTER :: b(:), Diag(:), Values(:)
3511
LOGICAL :: ComplexMatrix, GotIt, DiagOnly
3512
INTEGER, POINTER :: Rows(:), Cols(:)
3513
LOGICAL :: Found
3514
CHARACTER(:), ALLOCATABLE :: pre
3515
3516
3517
CALL Info('BlockMatrixInfo','')
3518
CALL Info('BlockMatrixInfo','Showing some ranges of block matrix stuff',Level=10)
3519
3520
NoVar = TotMatrix % NoVar
3521
m = 0
3522
3523
pre = 'BlockInfo'//I2S(ParEnv % MyPe)//': '
3524
3525
PRINT *,pre,NoVar, ParEnv % Mype
3526
DO k=1,NoVar
3527
DO l=1,NoVar
3528
3529
A => TotMatrix % SubMatrix(k,l) % Mat
3530
IF( .NOT. ASSOCIATED( A ) ) CYCLE
3531
IF( A % NumberOfRows == 0 ) CYCLE
3532
3533
n = 0
3534
m = 0
3535
3536
IF( ASSOCIATED( TotMatrix % Offset ) ) THEN
3537
n = TotMatrix % offset(k+1) - TotMatrix % offset(k)
3538
END IF
3539
IF(isParallel ) THEN
3540
IF( ASSOCIATED( TotMatrix % ParOffset ) ) THEN
3541
m = TotMatrix % ParOffset(k+1) -TotMatrix % ParOffset(k)
3542
END IF
3543
END IF
3544
3545
PRINT *,TRIM(pre)//' size',k,l,A % NumberOfRows, n, m, A % COMPLEX
3546
3547
Rows => A % Rows
3548
Cols => A % Cols
3549
Values => A % Values
3550
3551
PRINT *,pre,'A'//I2S(10*k+l)//' range',SUM( Values ), SUM( ABS( Values ) ), &
3552
MINVAL( Values ), MAXVAL( Values )
3553
3554
A => TotMatrix % SubMatrix(k,k) % PrecMat
3555
IF( .NOT. ASSOCIATED( A ) ) CYCLE
3556
IF( A % NumberOfRows == 0 ) CYCLE
3557
3558
Values => A % Values
3559
PRINT *,TRIM(pre),'B'//I2S(11*k)//' range',SUM( Values ), SUM( ABS( Values ) ), &
3560
MINVAL( Values ), MAXVAL( Values )
3561
END DO
3562
END DO
3563
3564
3565
DO k=1,NoVar
3566
PRINT *,'BlockInfo rhs:',k
3567
3568
A => TotMatrix % SubMatrix(k,k) % Mat
3569
IF( ASSOCIATED( A ) ) THEN
3570
b => A % rhs
3571
IF(ASSOCIATED(b)) THEN
3572
PRINT *,pre, 'A rhs range',k,SUM( b ), SUM( ABS( b ) ), &
3573
MINVAL( b ), MAXVAL( b )
3574
END IF
3575
END IF
3576
3577
b => TotMatrix % SubVector(k) % rhs
3578
IF(ASSOCIATED(b)) THEN
3579
PRINT *,pre,'b range',k,SUM( b ), SUM( ABS( b ) ), &
3580
MINVAL( b ), MAXVAL( b )
3581
END IF
3582
END DO
3583
3584
IF(isParallel) THEN
3585
DO k=1,NoVar
3586
PRINT *,'BlockInfo ParallelInfo'//I2S(k)
3587
3588
A => TotMatrix % SubMatrix(k,k) % Mat
3589
IF(.NOT. ASSOCIATED(A % ParallelInfo) ) THEN
3590
PRINT *,pre,'No ParallelInfo associated', k
3591
CYCLE
3592
END IF
3593
3594
n = A % NumberOfRows
3595
j = 0
3596
ll = 0
3597
IF( ASSOCIATED(A % ParallelInfo % NeighbourList ) ) THEN
3598
i = SIZE( A % ParallelInfo % NeighbourList)
3599
DO l=1,i
3600
j = j+SIZE(A % ParallelInfo % NeighbourList(l) % Neighbours)
3601
ll = ll+SUM(A % ParallelInfo % NeighbourList(l) % Neighbours)
3602
END DO
3603
PRINT *,pre,'BlockInfo NeighbourList:',n,i,j,ll
3604
END IF
3605
IF( ASSOCIATED(A % ParallelInfo % GInterface) ) THEN
3606
i = SIZE( A % ParallelInfo % Ginterface)
3607
j = COUNT(A % ParallelInfo % GInterface)
3608
PRINT *,pre,'BlockInfo GInterface', n,i,j
3609
END IF
3610
IF( ASSOCIATED(A % ParallelInfo % GlobalDOFs) ) THEN
3611
i = SIZE( A % ParallelInfo % GlobalDOFs)
3612
ll = SUM(A % ParallelInfo % GlobalDOFs)
3613
PRINT *,pre,'BlockInfo GlobalDofs', n,i,ll
3614
END IF
3615
3616
END DO
3617
END IF
3618
3619
END SUBROUTINE BlockMatrixInfo
3620
!------------------------------------------------------------------------------
3621
3622
3623
3624
3625
!> Performs the actual forward or reverse scaling. Optionally the scaling may be
3626
!> applied to only one matrix with an optional r.h.s. The idea is that for
3627
!> block preconditioning we may revert to the original symmetric matrix but
3628
!> still use the optimal row equilibration scaling for the block system.
3629
!------------------------------------------------------------------------------
3630
SUBROUTINE DoBlockMatrixScaling( reverse, blockrow, blockcol, bext, SkipMatrixScale )
3631
!------------------------------------------------------------------------------
3632
IMPLICIT NONE
3633
LOGICAL, OPTIONAL :: reverse
3634
INTEGER, OPTIONAL :: blockrow, blockcol
3635
REAL(KIND=dp), POINTER, OPTIONAL :: bext(:)
3636
LOGICAL, OPTIONAL :: SkipMatrixScale
3637
3638
INTEGER :: i,j,k,l,n,m,NoVar
3639
REAL(KIND=dp) :: nrm, tmp
3640
TYPE(Matrix_t), POINTER :: A
3641
REAL(KIND=dp), POINTER :: b(:), Diag(:), Values(:)
3642
INTEGER, POINTER :: Rows(:), Cols(:)
3643
LOGICAL :: backscale
3644
CHARACTER(*), PARAMETER :: Caller = 'DoBlockMatrixScaling'
3645
3646
IF( PRESENT( Reverse ) ) THEN
3647
BackScale = Reverse
3648
ELSE
3649
BackScale = .FALSE.
3650
END IF
3651
IF( BackScale ) THEN
3652
Message = 'Performing block matrix reverse row equilibration'
3653
ELSE
3654
Message = 'Performing block matrix row equilibration'
3655
END IF
3656
IF(PRESENT(blockrow)) THEN
3657
Message = TRIM(Message)//' for block '//I2S(blockrow)
3658
END IF
3659
CALL Info(Caller,Message,Level=12)
3660
3661
NoVar = TotMatrix % NoVar
3662
DO k=1,NoVar
3663
3664
IF( PRESENT( blockrow ) ) THEN
3665
IF( blockrow /= k ) CYCLE
3666
END IF
3667
3668
Diag => TotMatrix % SubVector(k) % DiagScaling
3669
IF( .NOT. ASSOCIATED( Diag ) ) THEN
3670
CALL Fatal(Caller,'Diag for scaling not associated!')
3671
END IF
3672
3673
IF( BackScale ) Diag = 1.0_dp / Diag
3674
3675
DO l=1,NoVar
3676
3677
IF( PRESENT( blockcol ) ) THEN
3678
IF( blockcol /= l ) CYCLE
3679
END IF
3680
3681
! If we use unscaled special preconditioning matrix we don't need to scale it
3682
IF( PRESENT( SkipMatrixScale ) ) THEN
3683
IF( SkipMatrixScale ) THEN
3684
CALL Info(Caller,'Skipping preconditioning matrix for block '//I2S(l),Level=20)
3685
CYCLE
3686
END IF
3687
END IF
3688
3689
A => TotMatrix % SubMatrix(k,l) % Mat
3690
n = A % NumberOfRows
3691
IF( n == 0 ) CYCLE
3692
3693
Rows => A % Rows
3694
Cols => A % Cols
3695
Values => A % Values
3696
3697
DO i=1,n
3698
DO j=Rows(i),Rows(i+1)-1
3699
Values(j) = Values(j) * Diag(i)
3700
END DO
3701
END DO
3702
3703
#if 0
3704
! This does not seem to be necessary but actually harmfull.
3705
A => TotMatrix % SubMatrix(k,l) % PrecMat
3706
IF( A % NumberOfRows == 0 ) CYCLE
3707
DO i=1,n
3708
DO j=A % Rows(i),A % Rows(i+1)-1
3709
A % Values(j) = A % Values(j) * Diag(i)
3710
END DO
3711
END DO
3712
#endif
3713
END DO
3714
3715
IF( PRESENT( bext ) ) THEN
3716
b => bext
3717
ELSE
3718
b => TotMatrix % Submatrix(k,k) % Mat % Rhs
3719
END IF
3720
3721
IF( ASSOCIATED( b ) ) THEN
3722
n = SIZE(Diag)
3723
b(1:n) = Diag(1:n) * b(1:n)
3724
END IF
3725
3726
IF( BackScale ) Diag = 1.0_dp / Diag
3727
END DO
3728
3729
IF( BackScale ) THEN
3730
CALL Info(Caller,'Finished block matrix reverse row equilibration',Level=25)
3731
ELSE
3732
CALL Info(Caller,'Finished block matrix row equilibration',Level=25)
3733
END IF
3734
3735
END SUBROUTINE DoBlockMatrixScaling
3736
!------------------------------------------------------------------------------
3737
3738
3739
!> Deallocates the block matrix scaling vectors.
3740
!------------------------------------------------------------------------------
3741
SUBROUTINE DestroyBlockMatrixScaling()
3742
!------------------------------------------------------------------------------
3743
INTEGER :: k,NoVar
3744
3745
CALL Info('DestroyBlockMatrixScaling','Deallocating the vectors for block system scaling',Level=10)
3746
3747
NoVar = TotMatrix % NoVar
3748
DO k=1,NoVar
3749
IF( ALLOCATED( TotMatrix % SubVector(k) % DiagScaling ) ) THEN
3750
DEALLOCATE( TotMatrix % SubVector(k) % DiagScaling )
3751
END IF
3752
END DO
3753
3754
END SUBROUTINE DestroyBlockMatrixScaling
3755
!------------------------------------------------------------------------------
3756
3757
3758
3759
!------------------------------------------------------------------------------
3760
!> Perform block preconditioning for Au=v by solving all the individual diagonal problems.
3761
!> Has to be called outside the module by Krylov methods.
3762
!------------------------------------------------------------------------------
3763
SUBROUTINE BlockMatrixPrec( u,v,ipar )
3764
IMPLICIT NONE
3765
REAL(KIND=dp), TARGET, INTENT(out) :: u(*)
3766
REAL(KIND=dp), TARGET, INTENT(in) :: v(*)
3767
INTEGER :: ipar(*)
3768
!---------------------------------------------------------------------------------
3769
REAL(KIND=dp), POINTER :: rtmp(:),vtmp(:),xtmp(:),btmp(:),diagtmp(:),b(:),x(:), a_rhs_save(:)
3770
REAL(KIND=dp), POINTER CONTIG :: rhs_save(:)
3771
INTEGER :: i,j,k,l,n,m,NoVar,nc,kk,ll,istat
3772
TYPE(Solver_t), POINTER :: Solver, Solver_save, ASolver
3773
INTEGER, POINTER :: Offset(:), BlockPerm(:),ParPerm(:)
3774
TYPE(ValueList_t), POINTER :: Params
3775
INTEGER, POINTER :: BlockOrder(:)
3776
TYPE(Matrix_t), POINTER :: A, Aij, mat_save
3777
TYPE(Variable_t), POINTER :: Var, Var_save
3778
REAL(KIND=dp) :: nrm
3779
LOGICAL :: GotOrder, BlockGS, Found, NS, ScaleSystem, DoSum, &
3780
IsComplex, BlockScaling, DoDiagScaling, DoPrecScaling, UsePrecMat, &
3781
Isolated, NoNestedScaling, DoAMGXmv, CalcLoads, BlockSch
3782
CHARACTER(:), ALLOCATABLE :: str
3783
INTEGER(KIND=AddrInt) :: AddrFunc
3784
EXTERNAL :: AddrFunc
3785
3786
CALL Info('BlockMatrixPrec','Starting block matrix preconditioning',Level=8)
3787
3788
DoAMGXMV = ListGetLogical( SolverRef % Values, 'Block AMGX M-V', Found)
3789
3790
n = ipar(3)
3791
3792
IF( InfoActive(25) ) THEN
3793
nrm = CompNorm(v(1:n),n)
3794
WRITE( Message,'(A,ES12.5)') 'V start norm: ',nrm
3795
CALL Info('BlockMatrixPrec',Message,Level=10)
3796
END IF
3797
3798
Solver => CurrentModel % Solver
3799
Params => Solver % Values
3800
3801
NoVar = TotMatrix % NoVar
3802
Solver => TotMatrix % Solver
3803
3804
TotMatrix % NoIters = TotMatrix % NoIters + 1
3805
3806
3807
! Enable user defined order for the solution of blocks
3808
!---------------------------------------------------------------
3809
BlockOrder => ListGetIntegerArray( Params,'Block Order',GotOrder)
3810
IF(GotOrder) THEN
3811
IF(SIZE(BlockOrder) /= NoVar) THEN
3812
CALL Fatal('BlockMatrixPrec','Block Order size should be '//I2S(NoVar))
3813
END IF
3814
END IF
3815
3816
BlockGS = ListGetLogical( Params,'Block Gauss-Seidel',Found)
3817
BlockSch = ListGetLogical( Params,'Block Schur',Found)
3818
3819
3820
3821
IF( isParallel ) THEN
3822
offset => TotMatrix % ParOffset
3823
ELSE
3824
offset => TotMatrix % Offset
3825
END IF
3826
3827
IF( n /= Offset(NoVar+1) ) THEN
3828
CALL Warn('BlockMatrixPrec','There is a mismatch between sizes: '&
3829
//I2S(n)//' vs. '//I2S(Offset(NoVar+1)))
3830
END IF
3831
3832
! Save the initial solver stuff
3833
solver_save => Solver
3834
var_save => Solver % Variable
3835
mat_save => Solver % Matrix
3836
rhs_save => Solver % Matrix % RHS
3837
3838
BlockScaling = ListGetLogical( Params,'Block Scaling',Found )
3839
3840
DoDiagScaling = .FALSE.
3841
IF( ASSOCIATED( Solver % Matrix ) ) THEN
3842
DoDiagScaling = ASSOCIATED( Solver % Matrix % diagscaling )
3843
END IF
3844
IF( DoDiagScaling ) THEN
3845
CALL Info('BlockMatrixPrec','External diagonal scaling is active!',Level=20)
3846
ELSE
3847
CALL Info('BlockMatrixPrec','External diagonal scaling is not active!',Level=30)
3848
END IF
3849
IF( BlockScaling ) THEN
3850
CALL Info('BlockMatrixPrec','Block matrix scaling is active!',Level=20)
3851
ELSE
3852
CALL Info('BlockMatrixPrec','Block matrix scaling is not active!',Level=30)
3853
END IF
3854
3855
IF(DoDiagscaling) THEN
3856
NoNestedScaling = ListGetLogical( Params,'Eliminate Nested Scaling',Found )
3857
IF(.NOT. Found) NoNestedScaling = .TRUE.
3858
ELSE
3859
NoNestedScaling = .FALSE.
3860
END IF
3861
3862
! Always treat the inner iterations as truly complex if they are
3863
CALL ListAddLogical( Params,'Linear System Skip Complex',.FALSE.)
3864
CALL ListAddLogical( Params,'Linear System Skip Loads',.TRUE.)
3865
3866
IF (isParallel) THEN
3867
ALLOCATE( x(TotMatrix % MaxSize), b(TotMatrix % MaxSize) )
3868
END IF
3869
3870
! Initial guess:
3871
!-----------------------------------------
3872
u(1:n) = 0.0_dp
3873
3874
BlockSch = ListCheckPrefix( Params,'Schur Operator' )
3875
3876
IF( BlockGS .OR. BlockSch ) THEN
3877
ALLOCATE( vtmp(n), rtmp(n), xtmp(n),STAT=istat)
3878
IF ( istat /= 0 ) CALL Fatal('BlockMatrixPrec','Memory allocation error for wrk space!')
3879
vtmp(1:n) = v(1:n)
3880
END IF
3881
3882
CALL ListPushNameSpace('block:')
3883
3884
DO j=1,NoVar
3885
IF( GotOrder ) THEN
3886
i = BlockOrder(j)
3887
ELSE
3888
i = j
3889
END IF
3890
3891
WRITE(Message,'(A,I0)') 'Solving block: ',i
3892
CALL Info('BlockMatrixPrec',Message,Level=8)
3893
3894
IF ( ListGetLogical( Solver % Values, 'Dymmy block '//I2S(i), Found) ) THEN
3895
u(offset(i)+1:offset(i+1)) = v(offset(i)+1:offset(i+1)); cycle
3896
end if
3897
3898
! We do probably not want to compute the change within each iteration
3899
CALL ListAddLogical( Params,'Skip Advance Nonlinear iter',.TRUE.)
3900
CALL ListAddLogical( Params,'Skip Compute Nonlinear Change',.TRUE.)
3901
3902
3903
! Set pointers to the new linear system
3904
!-------------------------------------------------------------------
3905
Var => TotMatrix % SubVector(i) % Var
3906
3907
UsePrecMat = .FALSE.
3908
IF( ASSOCIATED( TotMatrix % Subvector(i) % Solver ) ) THEN
3909
ASolver => TotMatrix % SubVector(i) % Solver
3910
A => ASolver % Matrix
3911
ELSE
3912
A => TotMatrix % Submatrix(i,i) % PrecMat
3913
IF( A % NumberOfRows == 0 ) THEN
3914
A => TotMatrix % Submatrix(i,i) % Mat
3915
ELSE
3916
UsePrecMat = .TRUE.
3917
CALL Info('BlockMatrixPrec','Using specialized (Schur) preconditioning block',Level=9)
3918
END IF
3919
ASolver => Solver
3920
END IF
3921
3922
IF ( A % NumberOfRows == 0 ) CYCLE
3923
3924
IF (isParallel) THEN
3925
! copy part of full solution to block solution
3926
x = 0.0_dp
3927
b = 0.0_dp
3928
ParPerm => TotMatrix % Submatrix(i,i) % ParPerm
3929
x(ParPerm) = u(offset(i)+1:offset(i+1))
3930
IF( BlockGS ) THEN
3931
b(ParPerm) = vtmp(offset(i)+1:offset(i+1))
3932
ELSE
3933
b(ParPerm) = v(offset(i)+1:offset(i+1))
3934
END IF
3935
ELSE
3936
x => u(offset(i)+1:offset(i+1))
3937
IF( BlockGS ) THEN
3938
b => vtmp(offset(i)+1:offset(i+1))
3939
ELSE
3940
b => v(offset(i)+1:offset(i+1))
3941
END IF
3942
END IF
3943
3944
IF( InfoActive(25) ) THEN
3945
! l is uninitialized!
3946
!nrm = CompNorm(b,offset(i+1)-offset(i),npar=l)
3947
nrm = CompNorm(b,offset(i+1)-offset(i))
3948
WRITE( Message,'(A,ES12.5)') 'Rhs '//I2S(i)//' norm: ',nrm
3949
CALL Info('BlockMatrixPrec',Message,Level=10)
3950
END IF
3951
3952
! Reuse block preconditioner from the first block to other components
3953
!--------------------------------------------------------------------
3954
IF( ListGetLogical( Params,'Block Prec Reuse',Found) ) THEN
3955
DO k = 1, NoVar
3956
IF( k == i ) CYCLE
3957
IF( CRS_CopyMatrixPrec( TotMatrix % Submatrix(k,k) % Mat, A ) ) EXIT
3958
END DO
3959
END IF
3960
3961
IF( BlockScaling ) CALL DoBlockMatrixScaling(.TRUE.,i,i,b,UsePrecMat)
3962
3963
! The special preconditioning matrices have not been scaled with the monolithic system.
3964
! So we need to transfer the (x,b) of this block to the unscaled system before going
3965
! to solve it. It is probably desirable to use separate scaling for this system.
3966
DoPrecScaling = DoDiagScaling .AND. UsePrecMat
3967
IF( DoPrecScaling ) THEN
3968
n = A % NumberOfRows
3969
ALLOCATE( btmp(n), diagtmp(n), STAT=istat)
3970
IF ( istat /= 0 ) CALL Fatal('BlockMatrixPrec',&
3971
'Memory allocation error for scaling wrk space!')
3972
3973
IF( TotMatrix % GotBlockStruct ) THEN
3974
k = TotMatrix % InvBlockStruct(i)
3975
IF( k <= 0 ) THEN
3976
CALL Fatal('BlockMatrixPrec','Cannot define the originating block '&
3977
//I2S(i)//' for scaling!')
3978
ELSE
3979
CALL Info('BlockMatrixPrec','Using initial block '//I2S(k)//&
3980
' in scaling of prec matrix '//I2S(i),Level=12)
3981
END IF
3982
ELSE
3983
k = i
3984
END IF
3985
3986
l = Solver % Variable % DOFs
3987
diagtmp(1:n) = Solver % Matrix % DiagScaling(k::l)
3988
3989
! Scale x & b to the unscaled system of the tailored preconditioning matrix for given block.
3990
x(1:n) = x(1:n) * diagtmp(1:n) * Solver % Matrix % RhsScaling
3991
btmp(1:n) = b(1:n) / diagtmp(1:n) * Solver % Matrix % RhsScaling
3992
ELSE
3993
btmp => b
3994
IF( NoNestedScaling ) THEN
3995
CALL Info('BlockMatrixPrec','Eliminating scaling for block as outer scaling already done!',Level=25)
3996
CALL ListAddLogical( Params,'Linear System Skip Scaling',.TRUE.)
3997
END IF
3998
END IF
3999
4000
IF( InfoActive( 25 ) ) THEN
4001
CALL BlockMatrixInfo()
4002
END IF
4003
4004
IF( A % COMPLEX ) THEN
4005
nc = 2
4006
ELSE
4007
nc = 1
4008
END IF
4009
4010
k = ListGetInteger( Params,'Schur Operator '//I2S(i),Found )
4011
IF( k > 0 ) THEN
4012
CALL Info('BlockMatrixPrec','Perform Schur complement operation for block '//I2S(i), Level=7 )
4013
4014
! The residual is used only as a temporary vector
4015
!-------------------------------------------------------------
4016
Aij => TotMatrix % SubMatrix(i,k) % Mat
4017
IF( Aij % NumberOfRows == 0) CYCLE
4018
4019
! r = P^T b
4020
Aij => TotMatrix % Submatrix(k,i) % Mat
4021
IF( BlockGS ) THEN
4022
b => vtmp(offset(i)+1:offset(i+1))
4023
ELSE
4024
b => v(offset(i)+1:offset(i+1))
4025
END IF
4026
IF(DoAMGXMV) THEN
4027
CALL AMGXMatrixVectorMultiply(Aij,b,rtmp,SolverRef )
4028
ELSE
4029
CALL CRS_MatrixVectorMultiply(Aij,b,rtmp )
4030
END IF
4031
4032
! u = A^-1 r
4033
CALL ListPushNameSpace('block '//i2s(11*k)//':')
4034
4035
Aij => TotMatrix % Submatrix(k,k) % Mat
4036
Isolated = TotMatrix % SubMatrix(k,k) % ParallelIsolatedMatrix
4037
IF(DoAMGXMv) THEN
4038
ScaleSystem = ListGetLogical( Params,'Linear System Scaling', Found )
4039
IF(.NOT. Found) ScaleSystem = .TRUE.
4040
IF ( ScaleSystem ) CALL ScaleLinearSystem(ASolver, Aij,btmp,xtmp )
4041
CALL AMGXSolver( Aij, xtmp, btmp, ASolver )
4042
IF( ScaleSystem ) CALL BackScaleLinearSystem(ASolver,Aij,btmp,xtmp)
4043
ELSE
4044
CALL SolveLinearSystem( Aij, rtmp, xtmp, Var % Norm, Var % DOFs, ASolver )
4045
END IF
4046
4047
! x = -P u
4048
rtmp = 0.0_dp
4049
Aij => TotMatrix % Submatrix(i,k) % Mat
4050
IF(DoAMGXMV) THEN
4051
CALL AMGXMatrixVectorMultiply(Aij,xtmp,rtmp,SolverRef )
4052
ELSE
4053
CALL CRS_MatrixVectorMultiply(Aij,xtmp,rtmp )
4054
END IF
4055
4056
BLOCK
4057
REAL(KIND=dp) :: cmult
4058
cmult = ListGetCReal( Params,'Schur Multiplier '//I2S(i),Found, DefValue=1.0_dp )
4059
! Up-date the off-diagonal entries to the r.h.s.
4060
u(offset(i)+1:offset(i+1)) = u(offset(i)+1:offset(i+1)) &
4061
- cmult * rtmp(1:offset(i+1)-offset(i))
4062
END BLOCK
4063
CALL ListPopNameSpace() ! block ij:
4064
4065
CYCLE
4066
ELSE
4067
CALL ListPushNameSpace('block '//i2s(11*i)//':')
4068
4069
IF(DoAMGXMv) THEN
4070
ScaleSystem = ListGetLogical( Params,'Linear System Scaling', Found )
4071
IF(.NOT. Found) ScaleSystem = .TRUE.
4072
4073
IF ( ScaleSystem ) CALL ScaleLinearSystem(ASolver, A,btmp,x )
4074
CALL AMGXSolver( A, x, btmp, ASolver )
4075
IF( ScaleSystem ) CALL BackScaleLinearSystem(ASolver,A,btmp,x)
4076
ELSE
4077
CALL SolveLinearSystem( A, btmp, x, Var % Norm, Var % DOFs, ASolver )
4078
END IF
4079
END IF
4080
4081
! If this was a special preconditioning matrix then update the solution in the scaled system.
4082
IF( DoPrecScaling ) THEN
4083
! This tentatively fixes the issues introduced scaling in May 2025 that made the outer iteration converge slower.
4084
x(1:n) = x(1:n) / ( diagtmp(1:n) * Solver % Matrix % RhsScaling )
4085
DEALLOCATE( btmp, diagtmp )
4086
ELSE IF( NoNestedScaling ) THEN
4087
CALL ListAddLogical( Params,'Linear System Skip Scaling',.FALSE.)
4088
END IF
4089
4090
IF( InfoActive(20) ) THEN
4091
nrm = CompNorm(x,offset(i+1)-offset(i),A=A)
4092
WRITE( Message,'(A,ES12.5)') 'Linear system '//I2S(i)//' norm: ',nrm
4093
CALL Info('BlockMatrixPrec',Message)
4094
END IF
4095
4096
IF( BlockScaling ) CALL DoBlockMatrixScaling(.FALSE.,i,i,b,UsePrecMat)
4097
4098
IF (isParallel) THEN
4099
x(1:offset(i+1)-offset(i)) = x(ParPerm)
4100
u(offset(i)+1:offset(i+1)) = x(1:offset(i+1)-offset(i))
4101
END IF
4102
4103
!---------------------------------------------------------------------
4104
IF( BlockGS ) THEN
4105
CALL Info('BlockMatrixPrec','Updating block r.h.s',Level=9)
4106
4107
DO l=j+1,NoVar
4108
IF( GotOrder ) THEN
4109
k = BlockOrder(l)
4110
ELSE
4111
k = l
4112
END IF
4113
4114
str = 'Block Gauss-Seidel Passive '//I2S(k)//I2S(i)
4115
IF( ListGetLogical( Params, str, Found ) ) CYCLE
4116
4117
CALL Info('BlockMatrixPrec','Updating r.h.s for component '//I2S(k),Level=15)
4118
4119
! The residual is used only as a temporary vector
4120
!-------------------------------------------------------------
4121
Aij => TotMatrix % SubMatrix(k,i) % Mat
4122
4123
IF( Aij % NumberOfRows == 0) CYCLE
4124
Isolated = TotMatrix % SubMatrix(k,i) % ParallelIsolatedMatrix
4125
4126
IF (isParallel) THEN
4127
IF(ASSOCIATED(Aij % ParMatrix)) THEN
4128
! x is packed, r is full
4129
CALL ParallelMatrixVector(Aij,x,rtmp )
4130
4131
ELSE IF( Isolated ) THEN
4132
! If our matrix is not active on shared nodes we may apply serial Mv
4133
! and pack the results to include only the dofs owned by the partition.
4134
CALL CRS_MatrixVectorMultiply(Aij,x,rtmp)
4135
ParPerm => TotMatrix % Submatrix(i,i) % ParPerm
4136
4137
#if 0
4138
rtmp(1:offset(i+1)-offset(i)) = rtmp(ParPerm)
4139
#else
4140
ll = 0
4141
DO kk=1,A % NumberofRows
4142
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(kk) % Neighbours(1)) CYCLE
4143
ll = ll+1
4144
rtmp(ll) = rtmp(kk)
4145
IF(parperm(ll) /= kk) PRINT *,'Problem:',ll,kk,parperm(ll)
4146
END DO
4147
#endif
4148
4149
ELSE IF (ASSOCIATED(SolverMatrix)) THEN
4150
! Here we don't have the luxury that the block matrix would either have parallel
4151
! communication initiated, or not have interface dofs. The last resort is to use
4152
! the initial monolithic matrix to perform Mv also for a given block by setting
4153
! other dofs to zero.
4154
xtmp = 0.0_dp
4155
xtmp(offset(i)+1:offset(i+1)) = x(offset(i)+1:offset(i+1))
4156
4157
BlockPerm => TotMatrix % ParBlockPerm
4158
4159
xtmp(BlockPerm(1:n)) = xtmp(1:n)
4160
CALL ParallelMatrixVector(SolverMatrix,xtmp,rtmp)
4161
rtmp(1:n) = rtmp(BlockPerm(1:n))
4162
4163
rtmp(1:offset(k+1)-offset(k)) = rtmp(offset(k)+1:offset(k+1))
4164
4165
ELSE
4166
CALL Fatal('BlockMatrixPrec','Do not know how to apply parallel matrix!')
4167
END IF
4168
ELSE
4169
Aij => TotMatrix % Submatrix(k,i) % Mat
4170
IF(DoAMGXMV) THEN
4171
CALL AMGXMatrixVectorMultiply(Aij, x, rtmp, SolverRef )
4172
ELSE
4173
CALL CRS_MatrixVectorMultiply(Aij,x,rtmp )
4174
END IF
4175
END IF
4176
4177
! Up-date the off-diagonal entries to the r.h.s.
4178
vtmp(offset(k)+1:offset(k+1)) = vtmp(offset(k)+1:offset(k+1)) &
4179
- rtmp(1:offset(k+1)-offset(k))
4180
4181
END DO ! l=j+1,NoVar
4182
4183
END IF ! Gauss-Seidel
4184
4185
CALL ListPopNameSpace() ! block ij:
4186
4187
END DO ! j=1,NoVar
4188
4189
IF (isParallel) DEALLOCATE(x,b)
4190
4191
CALL ListPopNameSpace('block:') ! block:
4192
4193
CALL ListAddLogical( Params,'Linear System Refactorize',.FALSE. )
4194
CALL ListAddLogical( Params,'Skip Advance Nonlinear iter',.FALSE.)
4195
CALL ListAddLogical( Params,'Skip Compute Nonlinear Change',.FALSE.)
4196
CALL ListAddLogical( Params,'Linear System Skip Loads',.FALSE.)
4197
4198
Solver => Solver_save
4199
Solver % Matrix => mat_save
4200
Solver % Matrix % RHS => rhs_save
4201
Solver % Variable => Var_save
4202
4203
IF( BlockGS .OR. BlockSch ) THEN
4204
DEALLOCATE( vtmp, rtmp, xtmp )
4205
END IF
4206
4207
IF( InfoActive(20) ) THEN
4208
nrm = CompNorm(v(1:n),n)
4209
WRITE( Message,'(A,ES12.5)') 'V fin norm: ',nrm
4210
CALL Info('BlockMatrixPrec',Message,Level=10)
4211
4212
nrm = CompNorm(u(1:n),n)
4213
WRITE( Message,'(A,ES12.5)') 'U fin norm: ',nrm
4214
CALL Info('BlockMatrixPrec',Message,Level=10)
4215
END IF
4216
4217
CALL Info('BlockMatrixPrec','Finished block matrix preconditioning',Level=8)
4218
4219
END SUBROUTINE BlockMatrixPrec
4220
4221
4222
4223
!> This call takes care of Jacobi & Gauss Seidel block methods.
4224
!-----------------------------------------------------------------
4225
SUBROUTINE BlockStandardIter( Solver, MaxChange )
4226
4227
TYPE(Solver_t) :: Solver
4228
REAL(KIND=dp) :: MaxChange
4229
4230
INTEGER :: i,j,NoVar,RowVar,iter,LinIter,MinIter
4231
INTEGER, POINTER :: BlockOrder(:)
4232
LOGICAL :: GotIt, GotBlockOrder, BlockGS
4233
REAL(KIND=dp), POINTER CONTIG :: rhs_save(:), b(:)
4234
REAL(KIND=dp), POINTER :: dx(:)
4235
TYPE(Matrix_t), POINTER :: A, mat_save
4236
TYPE(Variable_t), POINTER :: Var, SolverVar
4237
REAL(KIND=dp) :: LinTol, TotNorm, dxnorm, xnorm, Relax
4238
TYPE(ValueList_t), POINTER :: Params
4239
LOGICAL :: ScaleSystem, BlockScaling, Found
4240
4241
NoVar = TotMatrix % NoVar
4242
Params => Solver % Values
4243
SolverVar => Solver % Variable
4244
4245
BlockGS = ListGetLogical( Params,'Block Gauss-Seidel',Found)
4246
BlockOrder => ListGetIntegerArray( Params,'Block Order',GotBlockOrder)
4247
LinIter = ListGetInteger( Params,'Linear System Max Iterations',GotIt)
4248
MinIter = ListGetInteger( Params,'Linear System Min Iterations',GotIt)
4249
LinTol = ListGetConstReal( Params,'Linear System Convergence Tolerance',GotIt)
4250
BlockScaling = ListGetLogical( Params,'Block Scaling',GotIt)
4251
4252
CALL ListPushNamespace('block:')
4253
4254
! We don't want compute change externally
4255
CALL ListAddNewLogical( Params,'Skip compute nonlinear change',.TRUE.)
4256
4257
Relax = 1.0_dp
4258
4259
DO iter = 1, LinIter
4260
4261
! Store the iteration count
4262
TotMatrix % NoIters = iter
4263
4264
! In block Jacobi the r.h.s. is not updated during the iteration cycle
4265
!----------------------------------------------------------------------
4266
IF( BlockGS ) THEN
4267
WRITE( Message,'(A,I0)') 'Block Gauss-Seidel iteration: ',iter
4268
ELSE
4269
WRITE( Message,'(A,I0)') 'Block Jacobi iteration: ',iter
4270
CALL BlockUpdateRhs(TotMatrix)
4271
END IF
4272
CALL Info('BlockStandardIter',Message,Level=5)
4273
MaxChange = 0.0_dp
4274
TotNorm = 0.0_dp
4275
4276
IF( iter == 2 ) THEN
4277
CALL ListAddLogical( Params,'No Precondition Recompute',.TRUE.)
4278
END IF
4279
4280
DO i=1,NoVar
4281
IF( GotBlockOrder ) THEN
4282
RowVar = BlockOrder(i)
4283
ELSE
4284
RowVar = i
4285
END IF
4286
4287
! In gauss-seidel the partial update is immediately taken into account
4288
!---------------------------------------------------------------------
4289
IF( BlockGS ) THEN
4290
CALL BlockUpdateRhs(TotMatrix,RowVar)
4291
END IF
4292
4293
IF( ListGetLogical( Params,'Block Prec Reuse',GotIt) ) THEN
4294
DO j = 1, NoVar
4295
IF( j == RowVar ) CYCLE
4296
IF( CRS_CopyMatrixPrec( TotMatrix % Submatrix(j,j) % Mat, A ) ) EXIT
4297
END DO
4298
END IF
4299
4300
b => TotMatrix % SubVector(RowVar) % rhs
4301
4302
IF( InfoActive( 15 ) ) THEN
4303
PRINT *,'rhs'//I2S(i)//':',SQRT( SUM(b**2) ), MINVAL( b ), MAXVAL( b ), SUM( b )
4304
END IF
4305
4306
Var => TotMatrix % SubVector(RowVar) % Var
4307
Solver % Variable => Var
4308
4309
A => TotMatrix % Submatrix(i,i) % PrecMat
4310
IF( A % NumberOfRows == 0 ) THEN
4311
A => TotMatrix % Submatrix(i,i) % Mat
4312
ELSE
4313
CALL Info('BlockStandardIter','Using preconditioning block: '//I2S(i),Level=8)
4314
END IF
4315
4316
!Solver % Matrix => A
4317
4318
! Use the newly computed residual rather than original r.h.s. to solve the equation!!
4319
rhs_save => A % rhs ! Solver % Matrix % RHS
4320
A % RHS => b
4321
4322
! Solving the subsystem
4323
!-----------------------------------
4324
ALLOCATE( dx( SIZE( Var % Values ) ) )
4325
dx = 0.0_dp
4326
4327
CALL ListPushNamespace('block '//i2s(11*RowVar)//':')
4328
4329
IF( BlockScaling ) CALL DoBlockMatrixScaling(.TRUE.,i,i,b)
4330
4331
!IF( ListGetLogical( Solver % Values,'Linear System Complex', Found ) ) A % Complex = .TRUE.
4332
4333
!ScaleSystem = ListGetLogical( Solver % Values,'block: Linear System Scaling', Found )
4334
!IF(.NOT. Found) ScaleSystem = .TRUE.
4335
4336
4337
CALL SolveLinearSystem( A, b, dx, Var % Norm, Var % DOFs, Solver )
4338
4339
IF( BlockScaling ) CALL DoBlockMatrixScaling(.FALSE.,i,i,b)
4340
4341
CALL ListPopNamespace()
4342
4343
! Revert back to original r.h.s.
4344
A % RHS => rhs_save
4345
!Solver % Matrix => mat_save
4346
4347
IF( iter > 1 ) THEN
4348
Var % Values = Var % Values + Relax * dx
4349
ELSE
4350
Var % Values = Var % Values + dx
4351
END IF
4352
4353
dxnorm = CompNorm(dx,A % NumberOfRows, A=A)
4354
xnorm = CompNorm(Var % Values, A % NumberOfRows, A=A)
4355
4356
Var % Norm = xnorm
4357
Var % NonlinChange = dxnorm / xnorm
4358
4359
WRITE(Message,'(A,2ES12.3)') 'Block '//I2S(RowVar)//' norms: ',xnorm, dxnorm / xnorm
4360
CALL Info('BlockStandardIter',Message,Level=5)
4361
4362
IF( InfoActive( 20 ) ) THEN
4363
PRINT *,'dx'//I2S(i)//':',SQRT( SUM(dx**2) ), MINVAL( dx ), MAXVAL( dx ), SUM( dx ), SUM( ABS( dx ) )
4364
END IF
4365
4366
DEALLOCATE( dx )
4367
4368
TotNorm = TotNorm + Var % Norm
4369
MaxChange = MAX( MaxChange, Var % NonlinChange )
4370
END DO
4371
4372
WRITE(Message,'(A,2ES12.3)') 'Sum of norms: ',TotNorm, MaxChange
4373
CALL Info('BlockStandardIter',Message,Level=4)
4374
4375
IF( MaxChange < LinTol .AND. iter >= MinIter ) THEN
4376
CALL Info('BlockStandardIter','Converged after iterations: '//I2S(iter),Level=5)
4377
EXIT
4378
END IF
4379
4380
END DO
4381
CALL ListPopNamespace('block:')
4382
4383
CALL ListAddLogical( Params,'No Precondition Recompute',.FALSE.)
4384
4385
Solver % Variable => SolverVar
4386
4387
END SUBROUTINE BlockStandardIter
4388
4389
4390
!---------------------------------------------------------------------------
4391
!> This call takes care of the iterative Krylov methods for block systems
4392
!> which can still be preconditioned by block Jacobi or Gauss-Seidel methods
4393
!---------------------------------------------------------------------------
4394
SUBROUTINE BlockKrylovIter( Solver, MaxChange )
4395
4396
TYPE(Solver_t) :: Solver
4397
REAL(KIND=dp) :: MaxChange
4398
4399
INTEGER(KIND=AddrInt) :: AddrFunc
4400
EXTERNAL :: AddrFunc
4401
INTEGER(KIND=AddrInt) :: iterProc,precProc, mvProc,dotProc,nmrProc, zero=0
4402
REAL(KIND=dp) :: dpar(20), xnorm,prevxnorm
4403
REAL(KIND=dp), ALLOCATABLE :: x(:),b(:),r(:)
4404
4405
TYPE(Matrix_t), POINTER :: A
4406
TYPE(Variable_t), POINTER :: SVar
4407
TYPE(ValueList_t), POINTER :: Params
4408
INTEGER :: NoVar, ndim, maxsize
4409
LOGICAL :: Converged, Diverged
4410
INTEGER :: Rounds, OutputInterval, PolynomialDegree
4411
INTEGER, POINTER :: Offset(:),poffset(:),BlockStruct(:),ParPerm(:)
4412
INTEGER :: i,j,k,l,ia,ib,istat
4413
LOGICAL :: LS, BlockAV,Found, UseMono
4414
CHARACTER(:), ALLOCATABLE :: VarName
4415
CHARACTER(*), PARAMETER :: Caller = 'BlockKrylovIter'
4416
4417
4418
CALL Info(Caller,'Starting block system iteration',Level=8)
4419
4420
!CALL ListPushNameSpace('outer:')
4421
Params => Solver % Values
4422
4423
BlockAV = ListGetLogical(Params,'Block A-V System', Found)
4424
4425
ndim = TotMatrix % TotSize
4426
NoVar = TotMatrix % NoVar
4427
4428
TotMatrix % NoIters = 0
4429
4430
isParallel = (ParEnv % PEs > 1)
4431
offset => TotMatrix % Offset
4432
IF(isParallel) THEN
4433
poffset => TotMatrix % ParOffset
4434
ELSE
4435
poffset => offset
4436
END IF
4437
4438
! Just do some error checks
4439
DO i=1,NoVar
4440
IF( .NOT. ASSOCIATED( TotMatrix % Subvector(i) % Var ) ) THEN
4441
CALL Fatal(Caller,'Subvector '//I2S(i)//' not associated!')
4442
END IF
4443
A => TotMatrix % SubMatrix(i,i) % Mat
4444
IF( .NOT. ASSOCIATED( A ) ) THEN
4445
CALL Fatal(Caller,'Submatrix '//I2S(11*i)//' not associated!')
4446
END IF
4447
IF( .NOT. ASSOCIATED( A % Rhs ) ) THEN
4448
CALL Warn(Caller,'Submatrix rhs '//I2S(11*i)//' not associated!')
4449
END IF
4450
END DO
4451
4452
CALL Info(Caller,'Allocating temporal vectors for block system of size: '&
4453
//I2S(ndim),Level=15)
4454
4455
ALLOCATE(x(ndim), b(ndim),r(ndim),STAT=istat)
4456
IF( istat /= 0 ) THEN
4457
CALL Fatal(Caller,'Cannot allocate temporal vectors of size: '//I2S(ndim))
4458
END IF
4459
4460
x = 0.0_dp
4461
b = 0.0_dp
4462
r = 0.0_dp
4463
4464
IF (isParallel) THEN
4465
CALL Info(Caller,'Performing parallel initializations!',Level=18)
4466
DO i=1,NoVar
4467
A => TotMatrix % SubMatrix(i,i) % Mat
4468
! ParallelInitSolve expects full vectors
4469
CALL Info(Caller,'Initializing submatrix '//I2S(11*i),Level=20)
4470
IF (ASSOCIATED(A % ParMatrix % SplittedMatrix % InsideMatrix % PrecValues)) THEN
4471
IF (.NOT. ASSOCIATED(A % PrecValues)) &
4472
NULLIFY(A % ParMatrix % SplittedMatrix % InsideMatrix % PrecValues)
4473
END IF
4474
CALL ParallelInitSolve(A, TotMatrix % Subvector(i) % Var % Values, A % rhs, r )
4475
IF( ASSOCIATED(SolverMatrix)) THEN
4476
x(offset(i)+1:offset(i+1)) = TotMatrix % SubVector(i) % Var % Values
4477
IF(ASSOCIATED(A % rhs)) b(offset(i)+1:offset(i+1)) = A % rhs
4478
END IF
4479
CALL Info(Caller,'Done initializing submatrix '//I2S(11*i),Level=20)
4480
END DO
4481
DO i=1,NoVar
4482
DO j=1,NoVar
4483
A => TotMatrix % SubMatrix(i,j) % Mat
4484
IF(i==j) CYCLE
4485
CALL Info(Caller,'Initializing submatrix '//I2S(10*i+j),Level=20)
4486
IF(ASSOCIATED(A % ParMatrix)) CALL ParallelInitSolve(A,r,r,r)
4487
END DO
4488
END DO
4489
IF(ASSOCIATED(SolverMatrix)) THEN
4490
CALL Info(Caller,'Initializing SolverMatrix',Level=20)
4491
CALL ParallelInitSolve( SolverMatrix, x, b, r )
4492
x = 0.0_dp
4493
b = 0.0_dp
4494
END IF
4495
CALL Info(Caller,'Parallel initializations done!',Level=25)
4496
END IF
4497
4498
CALL Info(Caller,'Initializing monolithic system vectors',Level=18)
4499
4500
DO i=1,NoVar
4501
A => TotMatrix % SubMatrix(i,i) % Mat
4502
4503
IF (.NOT.isParallel) THEN
4504
x(offset(i)+1:offset(i+1)) = TotMatrix % SubVector(i) % Var % Values
4505
IF(ASSOCIATED(A % rhs)) b(offset(i)+1:offset(i+1)) = A % rhs
4506
4507
4508
4509
4510
4511
ELSE
4512
ParPerm => TotMatrix % SubMatrix(i,i) % ParPerm
4513
x(poffset(i)+1:poffset(i+1)) = TotMatrix % SubVector(i) % Var % Values(ParPerm)
4514
4515
! This is a little dirty as it uses internal stuff from the parallel structure directly.
4516
! However, only this r.h.s. vector seems to be up-to-date.
4517
IF(ASSOCIATED(A % rhs)) b(poffset(i)+1:poffset(i+1)) = A % rhs(ParPerm) !A % ParMatrix % SplittedMatrix % InsideMatrix % Rhs
4518
END IF
4519
END DO
4520
4521
! Parallel block system only solves for its own variables.
4522
IF (isParallel) THEN
4523
ndim = poffset(NoVar+1)
4524
END IF
4525
4526
!----------------------------------------------------------------------
4527
! Solve matrix equation solver with the redefined block matrix operations
4528
!----------------------------------------------------------------------
4529
CALL ListAddLogical(Params,'Linear System Free Factorization',.FALSE.)
4530
4531
precProc = AddrFunc(BlockMatrixPrec)
4532
4533
UseMono = ListGetLogical(Params,'Block MV Monolithic',Found )
4534
IF(isParallel .AND. .NOT. Found ) THEN
4535
! This is a little dangerous logic since it separates serial and parallel operation!
4536
UseMono = .NOT. ( ASSOCIATED(TotMatrix % SubMatrix(1,NoVar) % Mat % ParMatrix) .OR. &
4537
TotMatrix % SubMatrix(1,NoVar) % ParallelIsolatedMatrix )
4538
END IF
4539
4540
IF( UseMono ) THEN
4541
mvProc = AddrFunc(BlockMatrixVectorProdMono)
4542
ELSE
4543
mvProc = AddrFunc(BlockMatrixVectorProd)
4544
END IF
4545
4546
prevXnorm = CompNorm(b,ndim)
4547
WRITE( Message,'(A,ES12.5)') 'Rhs norm at start: ',PrevXnorm
4548
CALL Info(Caller,Message,Level=10)
4549
IF( PrevXNorm < EPSILON( PrevXNorm ) ) THEN
4550
CALL Warn(Caller,"With zero'ish r.h.s. it does not make sense to call the solver!")
4551
RETURN
4552
END IF
4553
4554
4555
prevXnorm = CompNorm(x,ndim)
4556
WRITE( Message,'(A,ES12.5)') 'Solution norm at start: ',PrevXnorm
4557
CALL Info(Caller,Message,Level=10)
4558
4559
CALL Info(Caller,'Start of blocks system iteration',Level=18)
4560
4561
! Always treat the block system as a real valued system and complex
4562
! arithmetics only at the inner level.
4563
CALL ListAddLogical( Params,'Linear System Skip Complex',.TRUE.)
4564
4565
IF(ASSOCIATED(SolverMatrix)) THEN
4566
A => SolverMatrix
4567
ELSE
4568
A => TotMatrix % SubMatrix(1,1) % Mat
4569
END IF
4570
4571
!IF( ListGetLogical( Solver % Values,'Linear System Complex', Found ) ) A % COMPLEX = .TRUE.
4572
4573
IF (isParallel) THEN
4574
! Note that at this stage we work with the packed vectors x and b
4575
A => A % ParMatrix % SplittedMatrix % InsideMatrix
4576
CALL IterSolver( A,x,b,&
4577
Solver,ndim=ndim,MatvecF=mvProc,PrecF=precProc,&
4578
DotF=AddrFunc(SParDotProd), NormF=AddrFunc(SParNorm))
4579
4580
DO i=1,NoVar
4581
TotMatrix % SubMatrix(i,i) % Mat % ParMatrix % SplittedMatrix % &
4582
TmpXvec = x(poffset(i)+1:poffset(i+1))
4583
END DO
4584
4585
! Communicate blockwise information.
4586
! After this the packed x is again a full vector with redundant shared dofs
4587
DO i=1,NoVar
4588
CALL ParallelUpdateResult(TotMatrix % SubMatrix(i,i) % Mat, &
4589
x(offset(i)+1:offset(i+1)), r )
4590
END DO
4591
ELSE
4592
IF( ListGetLogical( Params,'Linear System test',Found ) ) THEN
4593
CALL IterSolver( A,x,b,&
4594
Solver,ndim=ndim,MatvecF=mvProc,PrecF=precProc,&
4595
DotF=AddrFunc(PseudoZDotProd) )
4596
ELSE
4597
CALL IterSolver( A,x,b,&
4598
Solver,ndim=ndim,MatvecF=mvProc,PrecF=precProc)
4599
END IF
4600
END IF
4601
CALL info(Caller,'Finished block system iteration',Level=18)
4602
4603
CALL ListAddLogical(Params,'Linear System Refactorize',.TRUE.)
4604
CALL ListAddLogical(Params,'Linear System Free Factorization',.TRUE.)
4605
4606
!CALL ListPopNamespace()
4607
4608
Xnorm = CompNorm(x,ndim)
4609
WRITE( Message,'(A,ES12.5)') 'Solution norm: ',Xnorm
4610
CALL Info(Caller,Message,Level=8)
4611
4612
MaxChange = 2*ABS(Xnorm-PrevXnorm)/(Xnorm+PrevXnorm)
4613
PrevXNorm = Xnorm
4614
4615
WRITE( Message,'(A,ES12.5)') 'Relative change: ',MaxChange
4616
CALL Info(Caller,Message,Level=8)
4617
4618
DO i=1,NoVar
4619
TotMatrix % SubVector(i) % Var % Values(1:offset(i+1)-offset(i)) = &
4620
x(offset(i)+1:offset(i+1))
4621
END DO
4622
4623
! Copy values back since for nontrivial block-matrix structure the
4624
! components do not build the whole solution. If we have AddVector
4625
! then the last block will not be included.
4626
!-----------------------------------------------------------------
4627
IF( TotMatrix % GotBlockStruct ) THEN
4628
SVar => CurrentModel % Solver % Variable
4629
i = SIZE(SVar % Values)
4630
Svar % Values(TotMatrix % BlockPerm(1:i)) = x(1:i)
4631
ELSE IF (BlockAV ) THEN
4632
i = SIZE(SolverVar % Values)
4633
SolverVar % Values = x(1:i)
4634
END IF
4635
4636
j = SIZE(x)
4637
IF(j>i) THEN
4638
VarName = LagrangeMultiplierName( Solver )
4639
SVar => VariableGet( Solver % Mesh % Variables, VarName )
4640
IF(ASSOCIATED(SVar)) SVar % Values = x(i+1:j)
4641
END IF
4642
4643
CALL Info(Caller,'Finished block krylov iteration',Level=20)
4644
4645
END SUBROUTINE blockKrylovIter
4646
4647
4648
4649
!> This makes the system monolithic. If it was initially monolithic
4650
!> and then made block, it does not make any sense. However, for
4651
!> multiphysics coupled cases it may be a good strategy.
4652
!-----------------------------------------------------------------
4653
SUBROUTINE BlockMonolithicSolve( Solver, MaxChange )
4654
4655
TYPE(Solver_t) :: Solver
4656
REAL(KIND=dp) :: MaxChange
4657
4658
INTEGER :: i,j,k,m,n,nc,mc,c,NoVar,NoCol,NoRow,NoEigen,vdofs,comp
4659
INTEGER, POINTER :: BlockOrder(:)
4660
LOGICAL :: GotIt, DampedEigen
4661
REAL(KIND=dp), POINTER CONTIG :: rhs_save(:), b(:)
4662
REAL(KIND=dp), POINTER :: CollX(:), rhs(:)
4663
TYPE(Matrix_t), POINTER :: A, mat_save
4664
TYPE(Variable_t), POINTER :: Var, CompVar, SolverVar
4665
TYPE(Variable_t), TARGET :: MonolithicVar
4666
REAL(KIND=dp) :: TotNorm
4667
CHARACTER(:), ALLOCATABLE :: CompName
4668
TYPE(ValueList_t), POINTER :: Params
4669
TYPE(Matrix_t), POINTER :: CollMat
4670
LOGICAL :: Found, HaveMass, HaveDamp, SaveImag, Visited = .FALSE.
4671
CHARACTER(*), PARAMETER :: Caller = 'BlockMonolithicSolve'
4672
4673
SAVE Visited, CollMat, CollX, HaveMass, HaveDamp, SaveImag
4674
4675
CALL Info(Caller,'Solving block matrix as monolithic!',Level=6)
4676
4677
NoVar = TotMatrix % NoVar
4678
Params => Solver % Values
4679
SolverVar => Solver % Variable
4680
Solver % Variable => MonolithicVar
4681
4682
4683
IF(.NOT. Visited ) THEN
4684
n = 0
4685
m = 0
4686
4687
CollMat => AllocateMatrix()
4688
HaveMass = .FALSE.
4689
HaveDamp = .FALSE.
4690
4691
DO NoRow = 1,NoVar
4692
rhs => TotMatrix % SubVector(NoRow) % rhs
4693
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
4694
n = n + A % NumberOfRows
4695
4696
DO NoCol = 1,NoVar
4697
A => TotMatrix % SubMatrix( NoRow, NoCol ) % Mat
4698
IF(.NOT. ASSOCIATED(A) ) CYCLE
4699
IF(.NOT. ASSOCIATED(A % Values) ) CYCLE
4700
4701
IF(InfoActive(20)) THEN
4702
CALL VectorValuesRange(A % Values,SIZE(A % Values),&
4703
'A'//I2S(10*NoRow+NoCol),.TRUE.)
4704
IF( ASSOCIATED( A % MassValues ) ) THEN
4705
CALL VectorValuesRange(A % MassValues,SIZE(A % MassValues),&
4706
'M'//I2S(10*NoRow+NoCol),.TRUE.)
4707
END IF
4708
END IF
4709
4710
m = m + SIZE( A % Values )
4711
IF( ASSOCIATED( A % MassValues ) ) HaveMass = .TRUE.
4712
IF( ASSOCIATED( A % DampValues ) ) HaveDamp = .TRUE.
4713
END DO
4714
END DO
4715
4716
IF( HaveMass ) THEN
4717
DO NoRow = 1,NoVar
4718
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
4719
IF(.NOT. ASSOCIATED( A % MassValues ) ) THEN
4720
CALL Warn(Caller,'MassValues are missing for block: '//I2S(11*NoRow))
4721
END IF
4722
END DO
4723
CALL Info(Caller,'Treating MassValues of block matrix too!',Level=20)
4724
END IF
4725
4726
IF( HaveDamp ) THEN
4727
CALL Info(Caller,'Treating DampValues of block matrix too!',Level=20)
4728
END IF
4729
4730
NoEigen = Solver % NOFEigenValues
4731
4732
DampedEigen = ListGetLogical(Solver % Values,'Eigen System Complex',Found )
4733
IF( DampedEigen ) THEN
4734
CALL Info(Caller,'Creating complex system for eigen values!',Level=6)
4735
ELSE
4736
CALL Info(Caller,'Creating real valued system for eigen values!',Level=8)
4737
END IF
4738
4739
SaveImag = ListGetLogical(Solver % Values,'Pick Im Component',Found )
4740
4741
! The matrix sizes depend on whether we create a complex or real valued system.
4742
IF(DampedEigen) THEN
4743
nc = 2*n
4744
mc = 4*m
4745
ELSE
4746
nc = n
4747
mc = m
4748
END IF
4749
4750
4751
CollMat % NumberOfRows = nc
4752
CALL Info(Caller,'Size of monolithic matrix: '//I2S(nc),Level=7)
4753
CALL Info(Caller,'Estimated number of nonzeros in monolithic matrix: '//I2S(mc),Level=7)
4754
4755
ALLOCATE( CollMat % rhs(nc), CollMat % Diag(nc), CollMat % Rows(nc+1), CollX(nc) )
4756
CollMat % rhs = 0.0_dp
4757
CollMat % Diag = 0
4758
CollMat % Rows = 0
4759
CollX = 0.0_dp
4760
4761
CollMat % Complex = DampedEigen
4762
4763
ALLOCATE( CollMat % Values(mc), CollMat % Cols(mc+1) )
4764
CollMat % Values = 0.0_dp
4765
CollMat % Cols = 0
4766
4767
IF( HaveMass ) THEN
4768
ALLOCATE( CollMat % MassValues(mc) )
4769
CollMat % MassValues = 0.0_dp
4770
END IF
4771
IF( HaveDamp .AND. .NOT. DampedEigen ) THEN
4772
ALLOCATE( CollMat % DampValues(mc) )
4773
CollMat % DampValues = 0.0_dp
4774
END IF
4775
END IF
4776
4777
k = 0
4778
CollMat % Rows(1) = 1
4779
4780
4781
IF(DampedEigen) THEN
4782
DO NoRow = 1,NoVar
4783
n = TotMatrix % Offset(NoRow)
4784
4785
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
4786
m = A % NumberOfRows
4787
4788
DO i=1,m
4789
4790
! Loop over real and imaginary rows
4791
DO c=1,2
4792
4793
DO NoCol = 1,NoVar
4794
A => TotMatrix % SubMatrix( NoRow, NoCol ) % Mat
4795
IF( .NOT. ASSOCIATED( A ) ) CYCLE
4796
IF( .NOT. ASSOCIATED( A % Rows ) ) CYCLE
4797
4798
DO j=A % Rows(i),A % Rows(i+1)-1
4799
! If we have the imaginary row add the multiplier of imaginary value first
4800
IF( c == 2 ) THEN
4801
k = k + 1
4802
CollMat % Cols(k) = 2*TotMatrix % Offset(NoCol) + 2*A % Cols(j)-1
4803
IF( ASSOCIATED( A % DampValues) ) THEN
4804
CollMat % Values(k) = A % DampValues(j)
4805
END IF
4806
END IF
4807
4808
k = k + 1
4809
CollMat % Values(k) = A % Values(j)
4810
CollMat % Cols(k) = 2*TotMatrix % Offset(NoCol) + 2*(A % Cols(j)-1)+c
4811
IF( ASSOCIATED( A % MassValues ) ) THEN
4812
CollMat % MassValues(k) = A % MassValues(j)
4813
END IF
4814
4815
! If we have the real row add the multiplier of imaginary value last
4816
IF( c == 1 ) THEN
4817
k = k + 1
4818
CollMat % Cols(k) = 2*TotMatrix % Offset(NoCol) + 2*A % Cols(j)
4819
IF( ASSOCIATED( A % DampValues) ) THEN
4820
CollMat % Values(k) = -A % DampValues(j)
4821
END IF
4822
END IF
4823
END DO
4824
END DO
4825
IF(.NOT. Visited ) THEN
4826
CollMat % Rows(2*((n+i)-1)+c+1) = k+1
4827
END IF
4828
END DO
4829
END DO
4830
END DO
4831
4832
ELSE
4833
DO NoRow = 1,NoVar
4834
n = TotMatrix % Offset(NoRow)
4835
4836
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
4837
m = A % NumberOfRows
4838
4839
DO i=1,m
4840
DO NoCol = 1,NoVar
4841
A => TotMatrix % SubMatrix( NoRow, NoCol ) % Mat
4842
IF( .NOT. ASSOCIATED( A ) ) CYCLE
4843
IF( .NOT. ASSOCIATED( A % Rows ) ) CYCLE
4844
IF( SIZE(A % Rows) < i+1 ) CYCLE
4845
4846
DO j=A % Rows(i),A % Rows(i+1)-1
4847
k = k + 1
4848
CollMat % Values(k) = A % Values(j)
4849
IF(.NOT. Visited ) THEN
4850
CollMat % Cols(k) = TotMatrix % Offset(NoCol) + A % Cols(j)
4851
END IF
4852
IF( HaveMass ) THEN
4853
IF( ASSOCIATED( A % MassValues ) ) THEN
4854
CollMat % MassValues(k) = A % MassValues(j)
4855
END IF
4856
END IF
4857
IF( HaveDamp ) THEN
4858
IF( ASSOCIATED( A % DampValues ) ) THEN
4859
CollMat % DampValues(k) = A % DampValues(j)
4860
END IF
4861
END IF
4862
END DO
4863
IF( ASSOCIATED( A % rhs ) ) THEN
4864
CollMat % rhs(n+i) = A % rhs(i)
4865
END IF
4866
END DO
4867
IF(.NOT. Visited ) THEN
4868
CollMat % Rows(n+i+1) = k+1
4869
END IF
4870
END DO
4871
END DO
4872
END IF
4873
4874
4875
IF( ParEnv % PEs > 1 ) THEN
4876
IF( NoVar /= 2 ) THEN
4877
CALL Fatal(Caller,'Parallel operation currently assumes just 2x2 blocks!')
4878
END IF
4879
4880
CALL Info(Caller,'Merging parallel info of matrices')
4881
CALL ParallelMergeMatrix( Solver, CollMat, &
4882
TotMatrix % SubMatrix(1,1) % Mat, &
4883
TotMatrix % SubMatrix(2,2) % Mat )
4884
END IF
4885
4886
4887
IF(InfoActive(20)) THEN
4888
!CALL CRS_CheckSymmetricTopo(CollMat)
4889
!CALL CRS_CheckComplexTopo(CollMat)
4890
CALL VectorValuesRange(CollMat % Values,SIZE(CollMat % Values),'Atot',.TRUE.)
4891
IF( ASSOCIATED( CollMat % MassValues ) ) THEN
4892
CALL VectorValuesRange(CollMat % MassValues,SIZE(CollMat % MassValues),'Mtot',.TRUE.)
4893
END IF
4894
END IF
4895
4896
CALL Info(Caller,'True number of nonzeros in monolithic matrix: '//I2S(k),Level=7)
4897
4898
IF(.NOT. Visited ) THEN
4899
MonolithicVar % Name = '' ! Some name needed to avoid an uninitialised value error
4900
MonolithicVar % Values => CollX
4901
MonolithicVar % Dofs = 1
4902
MonolithicVar % Perm => NULL()
4903
4904
NoEigen = Solver % NOFEigenValues
4905
IF( NoEigen > 0 ) THEN
4906
n = CollMat % NumberOfRows
4907
ALLOCATE( MonolithicVar % EigenValues(NoEigen), MonolithicVar % EigenVectors(NoEigen,n) )
4908
MonolithicVar % EigenValues = 0.0_dp
4909
MonolithicVar % EigenVectors = 0.0_dp
4910
END IF
4911
Visited = .TRUE.
4912
END IF
4913
4914
IF(.NOT. DampedEigen) THEN
4915
CALL Info(Caller,'Copying block solution to monolithic vector',Level=12)
4916
DO i=1,NoVar
4917
Var => TotMatrix % SubVector(i) % Var
4918
n = SIZE( Var % Values )
4919
m = TotMatrix % Offset(i)
4920
CollX(m+1:m+n) = Var % Values(1:n)
4921
END DO
4922
END IF
4923
4924
4925
!IF( ListGetLogical( Solver % Values,'outer: Linear System Save',Found ) ) THEN
4926
! CALL SaveLinearSystem( Solver, CollMat,'CollMat')
4927
!END IF
4928
4929
! Solve monolithic matrix equation.
4930
CALL SolveLinearSystem( CollMat, CollMat % rhs, CollX, TotNorm, 1, Solver )
4931
4932
CALL Info(Caller,'Copying monolithic vector to block solutions',Level=12)
4933
4934
! Copy the 1st eigenmode because this will be used for norms etc.
4935
NoEigen = Solver % NOFEigenValues
4936
IF( NoEigen > 0 ) THEN
4937
MonolithicVar % Values = REAL( MonolithicVar % EigenVectors(1,:) )
4938
END IF
4939
4940
DO i=1,NoVar
4941
Var => TotMatrix % SubVector(i) % Var
4942
n = SIZE( Var % Values )
4943
m = TotMatrix % Offset(i)
4944
Var % Values(1:n) = CollX(m+1:m+n)
4945
4946
IF( NoEigen > 0 ) THEN
4947
IF(.NOT. ASSOCIATED( Var % EigenValues ) ) THEN
4948
IF( ASSOCIATED( Var % Solver ) ) THEN
4949
Var % Solver % NOFEigenValues = NoEigen
4950
END IF
4951
ALLOCATE( Var % EigenValues(NoEigen), Var % EigenVectors(NoEigen,n) )
4952
Var % EigenValues = 0.0_dp
4953
Var % EigenVectors = 0.0_dp
4954
4955
vdofs = Var % Dofs
4956
IF( vdofs > 1 ) THEN
4957
DO comp=1,vdofs
4958
CompName = ComponentName(Var % Name,comp)
4959
CompVar => VariableGet( Solver % Mesh % Variables, Compname )
4960
CompVar % EigenValues => Var % EigenValues
4961
CompVar % EigenVectors => Var % EigenVectors(:,comp::vdofs)
4962
END DO
4963
END IF
4964
END IF
4965
4966
DO k=1,NoEigen
4967
Var % EigenValues(k) = MonolithicVar % EigenValues(k)
4968
Var % EigenVectors(k,1:n) = MonolithicVar % EigenVectors(k,m+1:m+n)
4969
END DO
4970
4971
END IF
4972
END DO
4973
4974
Solver % Variable => SolverVar
4975
4976
END SUBROUTINE BlockMonolithicSolve
4977
4978
4979
!------------------------------------------------------------------------------
4980
!> An alternative handle for the block solvers to be used by the legacy matrix
4981
!> type.
4982
!------------------------------------------------------------------------------
4983
SUBROUTINE BlockSolveInt(A,x,b,Solver)
4984
!------------------------------------------------------------------------------
4985
TYPE(Matrix_t), POINTER :: A
4986
TYPE(Solver_t), TARGET :: Solver
4987
REAL(KIND=dp), TARGET :: x(:)
4988
REAL(KIND=dp), TARGET CONTIG :: b(:)
4989
!------------------------------------------------------------------------------
4990
TYPE(Solver_t), POINTER :: PSolver
4991
TYPE(Variable_t), POINTER :: Var
4992
INTEGER :: i,j,k,l,n
4993
LOGICAL :: GotIt, BlockPrec, BlockAV, &
4994
BlockHdiv, BlockReIm, BlockHcurl, BlockHorVer, BlockCart, BlockNodal, BlockDomain, &
4995
BlockDummy, BlockComplex, SkipPrec
4996
INTEGER :: ColVar, RowVar, NoVar, BlockDofs, VarDofs
4997
4998
REAL(KIND=dp) :: TotNorm, MaxChange
4999
REAL(KIND=dp), POINTER :: SaveValues(:)
5000
REAL(KIND=dp), POINTER CONTIG :: SaveRHS(:)
5001
LOGICAL :: BlockScaling, BlockMonolithic, Found
5002
INTEGER :: HaveConstraint, HaveAdd
5003
INTEGER, POINTER :: VarPerm(:)
5004
INTEGER, POINTER :: BlockPerm(:)
5005
INTEGER, POINTER :: SlaveSolvers(:)
5006
LOGICAL :: GotSlaveSolvers, DoMyOwnVars,OldMatrix
5007
5008
TYPE(Matrix_t), POINTER :: Amat, SaveCM
5009
TYPE(Mesh_t), POINTER :: Mesh
5010
TYPE(ValueList_t), POINTER :: Params
5011
5012
INTEGER, POINTER :: BlockIndex(:)
5013
5014
5015
CALL Info('BlockSolveInt','---------------------------------------',Level=5)
5016
5017
Params => Solver % Values
5018
Mesh => Solver % Mesh
5019
PSolver => Solver
5020
5021
SolverRef => Solver
5022
5023
isParallel = ParEnv % PEs > 1
5024
5025
OldMatrix = ASSOCIATED( Solver % BlockMatrix )
5026
IF( OldMatrix ) THEN
5027
CALL Info('BlockSolveInit','Using old block matrix structures!',Level=12)
5028
END IF
5029
5030
5031
! Determine some parameters related to the block strategy
5032
!------------------------------------------------------------------------------
5033
BlockPrec = ListGetLogical( Params,'Block Preconditioner',GotIt)
5034
IF(.NOT. GotIt) THEN
5035
CALL Info('BlockSolveInt','Using block preconditioning mode by default')
5036
BlockPrec = .TRUE.
5037
END IF
5038
5039
BlockMonolithic = ListGetLogical( Params,'Block Monolithic',GotIt)
5040
5041
BlockScaling = ListGetLogical( Params,'Block Scaling',GotIt)
5042
5043
! Different strategies on how to split the initial monolithic matrix into blocks
5044
BlockAV = ListGetLogical( Params,'Block A-V System', GotIt)
5045
BlockHcurl = ListGetLogical( Params,'Block Hcurl System', GotIt) .OR. &
5046
ListGetLogical( Params,'Block Quadratic Hcurl System', GotIt)
5047
BlockHdiv = ListGetLogical( Params,'Block Hdiv system',GotIt)
5048
BlockReIm = ListGetLogical( Params,'Block Re-Im system',GotIt)
5049
BlockNodal = ListGetLogical( Params,'Block Nodal System', GotIt)
5050
BlockHorVer = ListGetLogical( Params,'Block Hor-Ver System', GotIt)
5051
BlockCart = ListGetLogical( Params,'Block Cartesian System', GotIt)
5052
BlockDomain = ListGetLogical( Params,'Block Domain System',GotIt)
5053
BlockDummy = ListGetLogical( Params,'Block Nested System',GotIt)
5054
BlockComplex = ListGetLogical( Params,'Block Complex System',GotIt)
5055
5056
5057
DoMyOwnVars = .FALSE.
5058
5059
IF( BlockDomain .OR. BlockHdiv .OR. BlockReIm .OR. BlockHcurl .OR. &
5060
BlockAV .OR. BlockHorVer .OR. BlockCart .OR. BlockNodal ) THEN
5061
! These take monolithic splitting and only return the "BlockIndex" which tells to which
5062
! block each dof belongs to. Then the same routine can split the matrices for all.
5063
!-----------------------------------------------------------------------------------------------
5064
n = SIZE( Solver % Variable % Values)
5065
ALLOCATE( BlockIndex(n) )
5066
BlockIndex = 0
5067
BlockDofs = 0
5068
DoMyOwnVars = .TRUE.
5069
5070
IF( BlockDomain ) THEN
5071
CALL BlockPickDofsPhysical( PSolver, BlockIndex, BlockDofs )
5072
ELSE IF( BlockHdiv ) THEN
5073
CALL BlockPickHdiv( PSolver, BlockIndex, BlockDofs )
5074
ELSE IF( BlockReIm ) THEN
5075
CALL BlockPickReIm( PSolver, BlockIndex, BlockDofs )
5076
ELSE IF( BlockHCurl ) THEN
5077
CALL BlockPickMatrixHcurl( PSolver, BlockDofs, BlockComplex, BlockIndex )
5078
ELSE IF( BlockAV ) THEN
5079
CALL BlockPickAV( PSolver, BlockIndex, BlockDofs )
5080
ELSE IF( BlockNodal ) THEN
5081
CALL BlockPickMatrixNodal( PSolver, BlockDofs, BlockComplex, BlockIndex )
5082
ELSE IF(BlockHorVer .OR. BlockCart) THEN
5083
CALL BlockPickMatrixHorVer( PSolver, BlockDofs, BlockCart, BlockIndex )
5084
END IF
5085
GotSlaveSolvers = .FALSE.
5086
ELSE
5087
SlaveSolvers => ListGetIntegerArray( Params, &
5088
'Block Solvers', GotSlaveSolvers )
5089
IF( GotSlaveSolvers ) THEN
5090
BlockDofs = SIZE( SlaveSolvers )
5091
ELSE IF( BlockDummy ) THEN
5092
BlockDofs = 1
5093
ELSE
5094
BlockDofs = Solver % Variable % Dofs
5095
END IF
5096
END IF
5097
5098
VarDofs = BlockDofs
5099
5100
5101
HaveConstraint = 0
5102
IF ( ASSOCIATED(A % ConstraintMatrix) ) HaveConstraint = 1
5103
HaveConstraint = ParallelReduction(HaveConstraint)
5104
5105
HaveAdd = 0
5106
IF ( ASSOCIATED(A % AddMatrix) ) THEN
5107
IF ( A % AddMatrix % NumberOFRows > 0 ) HaveAdd = 1
5108
END IF
5109
HaveAdd = ParallelReduction(HaveAdd)
5110
5111
IF( HaveConstraint > 0 .AND. HaveAdd > 0 ) THEN
5112
CALL Fatal('BlockSolveInt','Cannot yet do both Constraint and Add matrix!')
5113
END IF
5114
5115
IF( HaveConstraint > 0 ) THEN
5116
i = 0
5117
IF ( ASSOCIATED(A % ConstraintMatrix) ) THEN
5118
i = A % ConstraintMatrix % NumberOfRows
5119
END IF
5120
CALL Info('BlockSolveInt','Block system has ConstraintMatrix with '//I2S(i)//' rows!',Level=10)
5121
BlockDofs = BlockDofs + 1
5122
IF (BlockAV) BlockDofs = BlockDofs + 1
5123
END IF
5124
5125
IF( HaveAdd > 0 ) THEN
5126
i = A % AddMatrix % NumberOfRows - A % NumberOfRows
5127
CALL Info('BlockSolveInt','Block system has AddMatrix with '//I2S(i)//' own rows!',Level=10)
5128
BlockDofs = BlockDofs + 1
5129
END IF
5130
5131
5132
IF(.NOT. OldMatrix ) THEN
5133
CALL BlockInitMatrix( Solver, TotMatrix, BlockDofs, VarDofs, DoMyOwnVars )
5134
END IF
5135
5136
5137
NoVar = TotMatrix % NoVar
5138
TotMatrix % Solver => Solver
5139
5140
SaveMatrix => Solver % Matrix
5141
SolverMatrix => A
5142
Solver % Matrix => A
5143
5144
SolverVar => Solver % Variable
5145
SaveValues => SolverVar % Values
5146
SolverVar % Values => x
5147
5148
SaveRHS => SolverMatrix % RHS
5149
SolverMatrix % RHS => b
5150
5151
5152
IF( .NOT. GotSlaveSolvers ) THEN
5153
CALL Info('BlockSolveInt','Splitting monolithic matrix into pieces',Level=10)
5154
IF( DoMyOwnVars ) THEN
5155
CALL BlockPickMatrixPerm( Solver, BlockIndex, VarDofs, HaveAdd > 0 )
5156
IF(ASSOCIATED(BlockIndex)) THEN
5157
CALL BlockInitVar( Solver, TotMatrix, BlockIndex )
5158
DEALLOCATE(BlockIndex)
5159
ELSE
5160
CALL BlockInitVar( Solver, TotMatrix )
5161
END IF
5162
ELSE IF( BlockDummy .OR. VarDofs == 1 ) THEN
5163
CALL Info('BlockSolveInt','Using the original matrix as the (1,1) block!',Level=10)
5164
TotMatrix % SubMatrix(1,1) % Mat => SolverMatrix
5165
TotMatrix % SubMatrix(1,1) % Mat % Complex = ListGetLogical(Params,'Linear System Complex',Found)
5166
ELSE
5167
! Default splitting of matrices.
5168
CALL BlockPickMatrix( Solver, NoVar )
5169
VarDofs = NoVar
5170
END IF
5171
CALL Info('BlockSolveInt','Block matrix system created',Level=12)
5172
END IF
5173
5174
5175
! Currently we cannot have both structure-structure and fluid-structure couplings!
5176
IF( ListGetLogical( Params,'Structure-Structure Coupling',Found ) ) THEN
5177
CALL StructureCouplingBlocks( Solver )
5178
ELSE
5179
CALL FsiCouplingBlocks( Solver )
5180
END IF
5181
5182
IF( HaveConstraint > 0 ) THEN
5183
! Do not try to create preconditioner if we have Schur operator requested.
5184
SkipPrec = ListCheckPrefix( Params,'Schur Operator' )
5185
SkipPrec = SkipPrec .OR. ListGetLogical( Params,'Skip Constraint Prec', Found )
5186
CALL BlockPickConstraint( Solver, VarDofs, SkipPrec )
5187
! Storing pointer to CM so that the SolverMatrix won't be treated with the constraints
5188
SaveCM => Solver % Matrix % ConstraintMatrix
5189
Solver % Matrix % ConstraintMatrix => NULL()
5190
END IF
5191
5192
! Create preconditioners for block matrices.
5193
CALL BlockPrecMatrix( Solver, NoVar )
5194
5195
IF( ListCheckSuffix(Params,': Linear System Save') ) THEN
5196
DO RowVar=1,NoVar
5197
DO ColVar=1,NoVar
5198
IF( ListGetLogical( Params,'block '//I2S(10*ColVar+RowVar)//': Linear System Save',Found ) ) THEN
5199
Amat => TotMatrix % SubMatrix(RowVar,ColVar) % Mat
5200
CALL SaveLinearSystem( Solver, Amat,'block'//I2S(10*ColVar+RowVar) )
5201
END IF
5202
END DO
5203
IF( ListGetLogical( Params,'prec '//I2S(11*RowVar)//': Linear System Save',Found ) ) THEN
5204
Amat => TotMatrix % SubMatrix(RowVar,RowVar) % PrecMat
5205
CALL SaveLinearSystem( Solver, Amat,'prec'//I2S(11*RowVar) )
5206
END IF
5207
END DO
5208
END IF
5209
5210
5211
Found = .FALSE.
5212
DO RowVar=1,NoVar
5213
Amat => TotMatrix % SubMatrix(RowVar,RowVar) % Mat
5214
Var => TotMatrix % SubVector(RowVar) % Var
5215
IF( ASSOCIATED( Var ) ) THEN
5216
IF(.NOT. ASSOCIATED(Var % Perm)) THEN
5217
CALL Info('BlockSolveInt','Block variable '//I2S(RowVar)//' ('&
5218
//TRIM(Var % Name)//') exists but not Perm!',Level=3)
5219
Found = .TRUE.
5220
END IF
5221
END IF
5222
END DO
5223
IF(Found) THEN
5224
IF( isParallel ) THEN
5225
CALL Fatal('BlockSolveInt','Cannot continue without Perm in parallel!')
5226
ELSE
5227
CALL Warn('BlockSolveInt','Could not continue without Perm in parallel!!')
5228
END IF
5229
END IF
5230
5231
IF (isParallel .AND. .NOT. OldMatrix ) THEN
5232
CALL Info('BlockSolveInt','Initializing parallel block matrices',Level=12)
5233
DO RowVar=1,NoVar
5234
DO ColVar=1,NoVar
5235
5236
Amat => TotMatrix % SubMatrix(RowVar,ColVar) % Mat
5237
5238
! It is reasonable that there is no parallel communication for parallel
5239
! matrix if some partition is not participating in the process.
5240
IF(Amat % NumberOfRows == 0) CYCLE
5241
5242
Amat % Comm = Solver % Matrix % Comm
5243
Parenv % ActiveComm = Amat % Comm
5244
Solver % Variable => TotMatrix % SubVector(ColVar) % Var
5245
5246
! This is a coupling matrix that should by construction not lie at the interface
5247
IF(TotMatrix % Submatrix(RowVar,ColVar) % ParallelIsolatedMatrix ) CYCLE
5248
5249
! The parallel solution and hence also initialization works only for
5250
! standard square matrices.
5251
GotIt = (Amat % NumberOfRows == MAXVAL(Amat % Cols))
5252
TotMatrix % Submatrix(RowVar,ColVar) % ParallelSquareMatrix = GotIt
5253
5254
IF(GotIt) THEN
5255
CALL Info('BlockSolverInt','Block matrix is square matrix',Level=20)
5256
IF (.NOT.ASSOCIATED(Amat % ParMatrix)) THEN
5257
CALL Info('BlockSolveInt','Initializing parallel matrix: '//I2S(10*RowVar+ColVar),Level=6)
5258
CALL ParallelInitMatrix(Solver,Amat)
5259
END IF
5260
IF(ASSOCIATED(Amat % ParMatrix )) THEN
5261
Amat % ParMatrix % ParEnv % ActiveComm = Amat % Comm
5262
ParEnv => Amat % ParMatrix % ParEnv
5263
END IF
5264
!CALL SParIterActiveBarrier()
5265
ELSE
5266
CALL Info('BlockSolverInt','Block matrix '//I2S(10*RowVar+ColVar)//&
5267
' is not square matrix - cannot initialize parallel structures!',Level=20)
5268
END IF
5269
END DO
5270
END DO
5271
5272
CALL ParallelShrinkPerm()
5273
5274
Solver % Variable => SolverVar
5275
CALL Info('BlockSolveInt','Initialization of block matrix finished',Level=20)
5276
END IF
5277
5278
5279
IF(InfoActive(25)) THEN
5280
CALL Info('BlockSolveInt','Initial Block matrix system information:')
5281
CALL BlockMatrixInfo()
5282
END IF
5283
5284
5285
5286
!------------------------------------------------------------------------------
5287
! Finally solve the system using 'outer: ' as the optional namespace
5288
! for the linear system setting.
5289
!------------------------------------------------------------------------------
5290
5291
TotNorm = 0.0_dp
5292
MaxChange = 0.0_dp
5293
5294
IF( BlockScaling ) THEN
5295
CALL CreateBlockMatrixScaling()
5296
CALL DoBlockMatrixScaling(.FALSE.)
5297
END IF
5298
5299
CALL ListPushNamespace('outer:')
5300
5301
IF (BlockScaling) THEN
5302
! This simplifies writing a consistent sif file:
5303
!CALL ListAddLogical(Solver % Values, 'Linear System Row Equilibration', .TRUE.)
5304
END IF
5305
5306
! The case with one block is mainly for testing and developing features
5307
! related to nonlinearity and assembly.
5308
!----------------------------------------------------------------------
5309
IF( NoVar == 1 .AND. .NOT. BlockDummy ) THEN
5310
CALL Info('BlockSolveInt','Solving in standard manner',Level=6)
5311
5312
Solver % Variable => TotMatrix % SubVector(1) % Var
5313
Solver % Matrix => TotMatrix % Submatrix(1,1) % Mat
5314
5315
IF (BlockScaling) THEN
5316
! This simplifies writing a consistent sif file:
5317
CALL ListAddLogical(Solver % Values, 'Linear System Row Equilibration', .TRUE.)
5318
END IF
5319
5320
TotNorm = DefaultSolve()
5321
MaxChange = Solver % Variable % NonlinChange
5322
ELSE IF( BlockMonolithic ) THEN
5323
CALL Info('BlockSolveInt','Using monolithic strategy for the block',Level=6)
5324
CALL BlockMonolithicSolve( Solver, MaxChange )
5325
ELSE IF( BlockPrec ) THEN
5326
CALL Info('BlockSolveInt','Using block preconditioning strategy',Level=6)
5327
CALL BlockKrylovIter( Solver, MaxChange )
5328
ELSE
5329
Solver % Variable => TotMatrix % SubVector(1) % Var
5330
Solver % Matrix => TotMatrix % Submatrix(1,1) % Mat
5331
5332
CALL Info('BlockSolveInt','Using block solution strategy',Level=6)
5333
CALL BlockStandardIter( Solver, MaxChange )
5334
END IF
5335
5336
CALL ListPopNamespace('outer:')
5337
5338
IF( BlockScaling ) THEN
5339
CALL DoBlockMatrixScaling(.TRUE.)
5340
CALL DestroyBlockMatrixScaling()
5341
END IF
5342
5343
! For legacy matrices do the backmapping
5344
!------------------------------------------
5345
SolverMatrix % RHS => SaveRHS
5346
Solver % Matrix => SaveMatrix
5347
Solver % Variable => SolverVar
5348
Solver % Variable % Values => SaveValues
5349
5350
IF( HaveConstraint > 0 ) THEN
5351
! Restore the pointer to the SolverMatrix
5352
Solver % Matrix % ConstraintMatrix => SaveCM
5353
END IF
5354
5355
IF( DoMyOwnVars ) THEN
5356
CALL BlockBackCopyVar( Solver, TotMatrix )
5357
END IF
5358
5359
IF( ListGetLogical( Solver % Values,'Block Save Iterations',Found ) ) THEN
5360
CALL ListAddInteger(CurrentModel % Simulation,'res: block iterations',TotMatrix % NoIters)
5361
END IF
5362
5363
CALL Info('BlockSolveInt','All done')
5364
CALL Info('BlockSolveInt','-------------------------------------------------',Level=5)
5365
5366
END SUBROUTINE BlockSolveInt
5367
5368
END MODULE BlockSolve
5369
5370
5371
!------------------------------------------------------------------------------
5372
!> Just a handle for SolveLinearSystem():
5373
!------------------------------------------------------------------------------
5374
SUBROUTINE BlockSolveExt(A,x,b,Solver)
5375
!------------------------------------------------------------------------------
5376
USE Types
5377
USE BlockSolve, ONLY: BlockSolveInt
5378
USE Lists, ONLY : ListGetLogical, ListAddLogical
5379
IMPLICIT NONE
5380
5381
TYPE(Matrix_t), POINTER :: A
5382
TYPE(Solver_t) :: Solver
5383
REAL(KIND=dp) :: x(:),b(:)
5384
!------------------------------------------------------------------------------
5385
LOGICAL :: Found, bm
5386
!------------------------------------------------------------------------------
5387
! Eliminate recursion for block solvers.
5388
bm = ListGetLogical( Solver % Values, 'Linear System Block Mode', Found)
5389
IF(Found) &
5390
CALL ListAddLogical(Solver % Values,'Linear System Block Mode',.FALSE.)
5391
5392
CALL BlockSolveInt(A,x,b,Solver)
5393
5394
IF(Found) &
5395
CALL ListAddLogical(Solver % Values,'Linear System Block Mode',bm )
5396
!------------------------------------------------------------------------------
5397
END SUBROUTINE BlockSolveExt
5398
!------------------------------------------------------------------------------
5399
5400
!> \}
5401
5402