MODULE BlockSolve
USE ParallelUtils
USE Integration
USE ListMatrix
USE ElementUtils, ONLY : FreeMatrix
USE MatrixAssembly, ONLY : AddToMatrixElement
USE IterativeMethods, ONLY : PseudoZDotProd
USE IterSolve, ONLY : IterSolver
USE ElementDescription, ONLY : ElementInfo, EdgeElementInfo
USE SolverUtils, ONLY : LagrangeMultiplierName, SolveLinearSystem, ScaleLinearSystem, &
BackScaleLinearSystem, AMGXMatrixVectorMultiply, AMGXSolver, DiagonalMatrixSumming, &
StructureCouplingAssembly, FSICouplingAssembly, SaveLinearSystem, &
MassMatrixAssembly, VectorValuesRange, LaplaceMatrixAssembly
USE MeshUtils, ONLY : SaveProjector
USE DefUtils, ONLY : DefaultSolve, GetElementDOFs, GetElementNodes, GetLogical
IMPLICIT NONE
TYPE(BlockMatrix_t), POINTER, SAVE :: TotMatrix
LOGICAL, PRIVATE :: isParallel=.FALSE.
TYPE(Solver_t), POINTER, SAVE :: SolverRef
TYPE(Variable_t), POINTER :: SolverVar => Null()
TYPE(Matrix_t), POINTER :: SolverMatrix => Null(), SaveMatrix
CONTAINS
FUNCTION CreateSchurApproximation(A,P,Q) RESULT ( S )
TYPE(Matrix_t), POINTER :: A, P, Q
TYPE(Matrix_t), POINTER :: S, R
INTEGER :: n, i, j, k, l, j2, k2
REAL(KIND=dp) :: val
LOGICAL :: Found
CALL Info('CreateSchurApproximation','Creating Shcur complement for preconditioning!',Level=20)
NULLIFY(S)
IF(.NOT. ASSOCIATED(P) .OR. .NOT. ASSOCIATED(Q)) THEN
CALL Info('CreateSchurApproximation','Constraint matrix not associated!')
RETURN
END IF
S => AllocateMatrix()
n = P % NumberOfRows
IF(n == 0) THEN
CALL Info('CreateSchurApproximation','No rows in Constraint matrix!')
RETURN
END IF
S % FORMAT = MATRIX_LIST
CALL List_AddToMatrixElement(S % ListMatrix, n, n, 0.0_dp )
DO i=1,n
DO j=P % Rows(i),P % Rows(i+1)-1
k = P % Cols(j)
val = P % Values(j) / A % Values(A % Diag(k))
DO j2= Q % Rows(k),Q % Rows(k+1)-1
k2 = Q % Cols(j2)
CALL List_AddToMatrixElement(S % ListMatrix, i, k2, -val * Q % Values(j2) )
END DO
END DO
END DO
CALL List_toCRSMatrix(S)
val = 1.0_dp * SIZE(S % Values) / SIZE(P % Values)
WRITE(Message,'(A,ES12.3)') 'Schur matrix increase factor: ',val
CALL Info('CreateSchurApproximation',Message)
IF( InfoActive(20) ) THEN
CALL VectorValuesRange(P % Values,SIZE(P % Values),'Constraint')
CALL VectorValuesRange(S % Values,SIZE(S % Values),'Schur')
END IF
END FUNCTION CreateSchurApproximation
FUNCTION CreateBlockVariable( Solver, VariableNo, VarName, ExtDofs, ExtPerm ) RESULT ( Var )
TYPE(Solver_t), POINTER :: Solver
INTEGER :: VariableNo
CHARACTER(LEN=*) :: VarName
INTEGER, OPTIONAL :: ExtDofs
INTEGER, POINTER, OPTIONAL :: ExtPerm(:)
TYPE(Variable_t), POINTER :: Var
TYPE(Solver_t), POINTER :: PSolver
TYPE(ValueList_t), POINTER :: Params
TYPE(Mesh_t), POINTER :: Mesh
TYPE(Element_t), POINTER :: Element
INTEGER :: i,j,t,n,ndeg,body_id,body_id_prev,eq_id,solver_id,Dofs,nsize
INTEGER, POINTER :: VarPerm(:), ActiveVariables(:)
INTEGER, ALLOCATABLE :: Indexes(:)
REAL(KIND=dp), POINTER :: Values(:)
LOGICAL :: Hit, GotIt
CHARACTER(:), ALLOCATABLE :: str
LOGICAL :: GlobalBubbles, Found
INTEGER :: MaxNDOFs, MaxDGDOFs, MaxEDOFs, MaxFDOFs, MaxBDOFs
CALL Info('CreateBlockVariable','Creating block variables',Level=8)
Mesh => Solver % Mesh
Params => Solver % Values
IF( PRESENT( ExtDofs ) ) THEN
Dofs = ExtDofs
ELSE
str = 'Variable '//I2S(VariableNo)//' Dofs'
Dofs = ListGetInteger( Params,str, GotIt )
IF(.NOT. GotIt) Dofs = 1
END IF
IF( PRESENT( ExtPerm ) ) THEN
nsize = MAXVAL( ExtPerm )
varPerm => ExtPerm
GOTO 100
END IF
Ndeg = 0
MaxNDOFs = 0
MaxBDOFs = 0
MaxDGDOFs = 0
DO i=1, Mesh % NumberOFBulkElements
Element => Mesh % Elements(i)
MaxNDOFs = MAX( MaxNDOFs, Element % NDOFs )
MaxBDOFs = MAX( MaxBDOFs, Element % BDOFs )
MaxDGDOFs = MAX( MaxDGDOFs, Element % DGDOFs )
END DO
MaxEDOFs = 0
DO i=1, Mesh % NumberOFEdges
Element => Solver % Mesh % Edges(i)
MaxEDOFs = MAX( MaxEDOFs, Element % BDOFs )
END DO
MaxFDOFs = 0
DO i=1, Mesh % NumberOFFaces
Element => Solver % Mesh % Faces(i)
MaxFDOFs = MAX( MaxFDOFs, Element % BDOFs )
END DO
GlobalBubbles = ListGetLogical( Params, 'Bubbles in Global System', Found )
IF (.NOT.Found) GlobalBubbles = .TRUE.
Ndeg = Ndeg + Mesh % NumberOfNodes
IF ( MaxEDOFs > 0 ) Ndeg = Ndeg + MaxEDOFs * Mesh % NumberOFEdges
IF ( MaxFDOFs > 0 ) Ndeg = Ndeg + MaxFDOFs * Mesh % NumberOFFaces
IF ( GlobalBubbles ) &
Ndeg = Ndeg + MaxBDOFs * Mesh % NumberOfBulkElements
IF ( ListGetLogical( Params, 'Discontinuous Galerkin', Found ) ) &
Ndeg = MAX( NDeg, MaxDGDOFs * ( Mesh % NumberOfBulkElements + &
Mesh % NumberOfBoundaryElements) )
ALLOCATE( VarPerm(ndeg) )
VarPerm = 0
solver_id = 0
DO i = 1, CurrentModel % NumberOfSolvers
PSolver => CurrentModel % Solvers(i)
IF( ASSOCIATED( Solver, PSolver ) ) THEN
solver_id = i
EXIT
END IF
END DO
ALLOCATE(Indexes(Mesh % MaxElementDOFs))
body_id_prev = -1
DO t=1,Mesh % NumberOfBulkElements + Mesh % NumberOFBoundaryElements
Element => Mesh % Elements(t)
CurrentModel % CurrentElement => Element
body_id = Element % BodyId
IF( body_id /= body_id_prev ) THEN
Hit = .FALSE.
body_id_prev = body_id
IF( body_id < 1 ) CYCLE
eq_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values,'Equation')
IF( eq_id < 1 ) CYCLE
str='Active Variables['//i2s(solver_id)//']'
ActiveVariables => ListGetIntegerArray(CurrentModel % Equations(eq_id) % Values, str)
IF(.NOT. ASSOCIATED(ActiveVariables)) THEN
ActiveVariables => ListGetIntegerArray( CurrentModel % Equations(eq_id) % Values, &
'Active Variables')
END IF
IF( .NOT. ASSOCIATED(ActiveVariables)) CYCLE
IF( .NOT. ANY(ActiveVariables == VariableNo) ) CYCLE
Hit = .TRUE.
END IF
IF( Hit ) THEN
n=GetElementDOFs(Indexes)
VarPerm(Indexes(1:n)) = 1
END IF
END DO
j = 0
DO i = 1, SIZE(VarPerm)
IF( VarPerm(i) > 0 ) THEN
j = j + 1
VarPerm(i) = j
END IF
END DO
nsize = j
100 IF( nsize == 0 ) THEN
CALL Info('CreateBlockVariable','Variable '//TRIM(VarName)//' of size zero.', Level=10 )
END IF
CALL Info('CreateBlockVariable','Creating variable: '//TRIM(VarName), Level=6 )
CALL VariableAddVector( Mesh % Variables, Mesh, Solver, &
TRIM(VarName), Dofs, Perm = VarPerm )
WRITE( Message,'(A,I0,A)') 'Creating variable '//TRIM(VarName)//' with ',Dofs,' dofs'
CALL Info('CreateBlockVariable', Message)
Var => VariableGet( Mesh % Variables, VarName )
END FUNCTION CreateBlockVariable
SUBROUTINE BlockInitMatrix( Solver, BlockMatrix, BlockDofs, FieldDofs, SkipVar )
IMPLICIT NONE
TYPE(Solver_t), TARGET :: Solver
INTEGER :: BlockDofs
TYPE(BlockMatrix_t), POINTER :: BlockMatrix
INTEGER, OPTIONAL :: FieldDofs
LOGICAL, OPTIONAL :: SkipVar
TYPE(Solver_t), POINTER :: PSolver
INTEGER, POINTER :: BlockStruct(:), SlaveSolvers(:)
LOGICAL :: GotBlockStruct, GotSlaveSolvers, Found
TYPE(Matrix_t), POINTER :: Amat
INTEGER :: i,j,k,n,Novar
TYPE(ValueList_t), POINTER :: Params
TYPE(Variable_t), POINTER :: Var
CHARACTER(:), ALLOCATABLE :: VarName, str
LOGICAL :: UseSolverMatrix, IsComplex
CHARACTER(*), PARAMETER :: Caller = 'BlockInitMatrix'
BlockMatrix => Solver % BlockMatrix
IF (ASSOCIATED(BlockMatrix)) THEN
CALL Info(Caller,'Using existing block matrix',Level=10)
RETURN
END IF
CALL Info(Caller,'Initializing block matrix',Level=10)
Params => Solver % Values
IsComplex = ListGetLogical( Params,'Linear System Complex',Found)
IF( IsComplex ) THEN
CALL Info(Caller,'Assuming block matrix to be complex!',Level=10)
ELSE
CALL Info(Caller,'Assuming block matrix to be real!',Level=10)
END IF
ALLOCATE(Solver % BlockMatrix)
BlockMatrix => Solver % BlockMatrix
BlockStruct => ListGetIntegerArray( Params,'Block Structure',GotBlockStruct)
BlockMatrix % GotBlockStruct = GotBlockStruct
IF( GotBlockStruct ) THEN
IF( SIZE( BlockStruct ) /= BlockDofs ) THEN
CALL Fatal(Caller,'Incompatible size of > Block Structure < given!')
END IF
IF( MINVAL( BlockStruct ) < 1 .OR. MAXVAL( BlockStruct ) > BlockDofs ) THEN
CALL Fatal(Caller,'Incompatible values in > Block Structure < given!')
END IF
NoVar = MAXVAL( BlockStruct )
CALL Info(Caller,'Using given block structure of size: '//I2S(SIZE( BlockStruct)),Level=8)
BlockMatrix % BlockStruct => BlockStruct
ALLOCATE( BlockMatrix % InvBlockStruct(NoVar) )
BlockMatrix % InvBlockStruct = 0
DO i=1,BlockDofs
j = BlockStruct(i)
IF( BlockMatrix % InvBlockStruct(j) == 0 ) THEN
BlockMatrix % InvBlockStruct(j) = i
ELSE
BlockMatrix % InvBlockStruct(j) = -1
END IF
END DO
ELSE
CALL Info(Caller,'Inheriting blocks from variable dofs',Level=8)
NoVar = BlockDofs
CALL Info(Caller,'Inheriting block count '//I2S(NoVar)//' from variable dofs',Level=8)
END IF
IF( BlockMatrix % NoVar == NoVar ) THEN
CALL Info(Caller,'Reusing existing blockmatrix structures!',Level=6)
RETURN
ELSE IF( BlockMatrix % Novar /= 0 ) THEN
CALL Fatal(Caller,'Previous blockmatrix was of different size?')
ELSE
CALL Info(Caller,'Block matrix will be of size '//I2S(NoVar),Level=6)
END IF
BlockMatrix % Solver => Solver
BlockMatrix % NoVar = NoVar
ALLOCATE( BlockMatrix % SubMatrix(NoVar,NoVar) )
CALL Info(Caller,'Allocating block matrix of size '//I2S(NoVar),Level=10)
DO i=1,NoVar
DO j=1,NoVar
DO k=1,2
Amat => NULL()
Amat => AllocateMatrix()
Amat % ListMatrix => NULL()
Amat % FORMAT = MATRIX_LIST
Amat % NumberOfRows = 0
AMat % COMPLEX = IsComplex
IF( k==1) THEN
BlockMatrix % Submatrix(i,j) % Mat => Amat
ELSE
BlockMatrix % Submatrix(i,j) % PrecMat => Amat
END IF
END DO
END DO
END DO
ALLOCATE( BlockMatrix % SubMatrixActive(NoVar,NoVar) )
BlockMatrix % SubMatrixActive = .FALSE.
ALLOCATE( BlockMatrix % SubVector(NoVar))
DO i=1,NoVar
BlockMatrix % Subvector(i) % Var => NULL()
END DO
ALLOCATE( BlockMatrix % Offset(NoVar+1))
BlockMatrix % Offset = 0
BlockMatrix % maxsize = 0
IF( PRESENT( SkipVar ) ) THEN
IF( SkipVar ) THEN
CALL Info(Caller,'Skipping creation of block variables for now',Level=10)
BlockMatrix % ParentMatrix => Solver % Matrix
RETURN
END IF
END IF
IF( PRESENT( FieldDofs ) ) THEN
CALL Info(Caller,'Number of field components: '//I2S(FieldDofs))
IF( Novar /= FieldDofs ) CALL Info(Caller,'Number of fields and blocks ('&
//I2S(NoVar)//') differ!')
IF(.NOT. GotBlockStruct ) NoVar = FieldDofs
END IF
UseSolverMatrix = (NoVar == 1 )
IF( UseSolverMatrix ) THEN
UseSolverMatrix = ASSOCIATED( Solver % Variable )
END IF
IF( UseSolverMatrix ) THEN
UseSolverMatrix = ASSOCIATED( Solver % Matrix )
END IF
IF( UseSolverMatrix ) THEN
BlockMatrix % SubVector(1) % Var => Solver % Variable
n = SIZE( Solver % Variable % Values )
BlockMatrix % Offset(1) = 0
BlockMatrix % Offset(2) = n
BlockMatrix % MaxSize = n
BlockMatrix % TotSize = n
CALL Info(Caller,'Using solver variable directly as block variable!',Level=10)
RETURN
END IF
SlaveSolvers => ListGetIntegerArray( Params, &
'Block Solvers', GotSlaveSolvers )
DO i = 1,NoVar
IF( GotSlaveSolvers ) THEN
IF(i==1) CALL Info(Caller,'Using slave solver variables as block variables!',Level=10)
j = SlaveSolvers(i)
CALL Info(Caller,'Associating block '//I2S(i)//' with solver: '//I2S(j),Level=10)
PSolver => CurrentModel % Solvers(j)
Var => PSolver % Variable
VarName = TRIM(Var % Name)
BlockMatrix % SubVector(i) % Solver => PSolver
BlockMatrix % SubMatrix(i,i) % Mat => PSolver % Matrix
ELSE
str = 'Variable '//I2S(i)
VarName = ListGetString( Params, str, Found )
IF(.NOT. Found ) THEN
IF( BlockMatrix % GotBlockStruct ) THEN
VarName = 'BlockVar '//I2S(i)
ELSE
VarName = ComponentName(Solver % Variable % Name,i)
END IF
END IF
Var => VariableGet( Solver % Mesh % Variables, VarName )
END IF
IF(ASSOCIATED( Var ) ) THEN
CALL Info(Caller,'Using existing variable > '//VarName//' <')
ELSE
PSolver => Solver
IF( BlockMatrix % GotBlockStruct ) THEN
CALL Info(Caller,'Variable > '//VarName//' < does not exist, creating from existing Perm')
j = COUNT( BlockMatrix % BlockStruct == i )
IF( j == 0 ) THEN
CALL Fatal(Caller,'Invalid > Block Structure < given!')
END IF
Var => CreateBlockVariable(PSolver, i, VarName, j, Solver % Variable % Perm )
ELSE
Var => CreateBlockVariable(PSolver, i, VarName )
END IF
CALL Info(Caller,'Variable > '//VarName//' < does not exist, creating')
END IF
BlockMatrix % SubVector(i) % Var => Var
n = SIZE(Var % Values)
BlockMatrix % Offset(i+1) = BlockMatrix % Offset(i) + n
BlockMatrix % MaxSize = MAX( BlockMatrix % MaxSize, n )
END DO
BlockMatrix % TotSize = BlockMatrix % Offset( NoVar + 1 )
CALL Info(Caller,'All done',Level=12)
END SUBROUTINE BlockInitMatrix
SUBROUTINE BlockInitVar( Solver, BlockMatrix, BlockIndex )
IMPLICIT NONE
TYPE(Solver_t), TARGET :: Solver
TYPE(BlockMatrix_t), POINTER :: BlockMatrix
INTEGER, POINTER, OPTIONAL :: BlockIndex(:)
TYPE(Solver_t), POINTER :: PSolver
TYPE(Matrix_t), POINTER :: Amat
INTEGER :: i,j,k,n,m,Novar
TYPE(ValueList_t), POINTER :: Params
TYPE(Variable_t), POINTER :: Var
CHARACTER(:), ALLOCATABLE :: VarName, str
TYPE(Mesh_t), POINTER :: Mesh
REAL(KIND=dp), POINTER :: Vals(:)
INTEGER, POINTER :: VarPerm(:)
TYPE(Matrix_t), POINTER :: B
LOGICAL :: AddVector
Params => Solver % Values
Mesh => Solver % Mesh
NoVar = BlockMatrix % NoVar
BlockMatrix % Offset = 0
DO i=1,NoVar
Amat => BlockMatrix % Submatrix(i,i) % Mat
n = Amat % NumberOfRows
IF(n == 0) THEN
CALL Info('BlockInitVar','Zero rows, skipping...')
END IF
BlockMatrix % Offset(i+1) = BlockMatrix % Offset(i) + n
BlockMatrix % MaxSize = MAX( BlockMatrix % MaxSize, n )
AddVector = BlockMatrix % Subvector(i) % AddVector
IF(AddVector) THEN
VarName = LagrangeMultiplierName( Solver )
ELSE
VarName = ComponentName("Block variable",i)
END IF
Var => VariableGet( Mesh % Variables, VarName )
IF(.NOT. ASSOCIATED( Var ) ) THEN
CALL Info('BlockInitVar','Variable > '//VarName//' < for size '&
//I2S(n)//' does not exist, creating')
PSolver => Solver
NULLIFY( Vals )
ALLOCATE( Vals(n) )
Vals = 0.0_dp
IF(AddVector) THEN
CALL VariableAddVector( Mesh % Variables,Mesh,PSolver,VarName,Solver % Variable % Dofs,Vals,&
Output = .FALSE. )
ELSE IF( PRESENT(BlockIndex) ) THEN
CALL Info('BlockInitVar','Using BlockIndex to pick variable and perm',Level=20)
NULLIFY(VarPerm)
m = SIZE(Solver % Variable % Values)
ALLOCATE(VarPerm(m))
VarPerm = 0
k = 0
DO j=1,SIZE(Solver % Variable % Values)
IF(BlockIndex(j) == i) THEN
k = k+1
VarPerm(j) = k
END IF
END DO
CALL VariableAdd( Mesh % Variables,Mesh,PSolver,VarName,1,Vals,&
Output = .FALSE., Perm = VarPerm )
ELSE
CALL VariableAdd( Mesh % Variables,Mesh,PSolver,VarName,1,Vals,&
Output = .FALSE. )
END IF
Var => VariableGet( Mesh % Variables, VarName )
ELSE
Var % Values = 0.0_dp
END IF
BlockMatrix % SubVector(i) % Var => Var
IF(AddVector) CYCLE
IF(PRESENT(BlockIndex)) THEN
B => BlockMatrix % SubMatrix(i,i) % Mat
IF( ParEnv % PEs == 1 ) THEN
IF(ASSOCIATED(B % InvPerm ) ) THEN
Var % Values = Solver % Variable % Values(B % InvPerm)
END IF
ELSE
IF(.NOT. ASSOCIATED(B % Perm) ) CALL Fatal('BlockInitVar','Perm not present for block '//I2S(11*i))
DO j=1,SIZE(B % Perm)
k = B % Perm(j)
IF(k==0) CYCLE
Var % Values(k) = Solver % Variable % Values(Solver % Matrix % Perm(j))
END DO
END IF
END IF
END DO
BlockMatrix % TotSize = BlockMatrix % Offset( NoVar + 1 )
CALL Info('BlockInitVar','Block variables initialized!',Level=12)
END SUBROUTINE BlockInitVar
SUBROUTINE BlockBackCopyVar( Solver, BlockMatrix )
IMPLICIT NONE
TYPE(Solver_t), TARGET :: Solver
TYPE(BlockMatrix_t), POINTER :: BlockMatrix
TYPE(Matrix_t), POINTER :: Amat
INTEGER :: i,j,k,n,m,Novar
TYPE(Variable_t), POINTER :: Var
CALL Info('BlockBackCopyVar','Copying values back to monolithic solution vector',Level=10)
NoVar = BlockMatrix % NoVar
m = SIZE( Solver % Variable % Values )
DO i=1,NoVar
IF(BlockMatrix % SubVector(i) % AddVector ) THEN
CALL Info('BlockBackCopyVar','Skipping AddVector '//I2S(i)//' that is not associcated to the original vector!',Level=20)
CYCLE
END IF
Amat => BlockMatrix % Submatrix(i,i) % Mat
n = Amat % NumberOfRows
Var => BlockMatrix % SubVector(i) % Var
IF(.NOT. ASSOCIATED(Amat % InvPerm) ) THEN
CALL Warn('BlockBackCopyVar','"Amat % InvPerm" not associated!')
CYCLE
END IF
IF(ASSOCIATED(Amat % Perm)) THEN
IF( ParEnv % PEs == 1 ) THEN
CALL Warn('BlockBackCopyVar','Why do we have Amat % Perm in serial?')
END IF
ELSE
IF( ParEnv % PEs > 1 ) THEN
CALL Warn('BlockBackCopyVar','Why do we not have Amat % Perm in parallel?')
END IF
END IF
IF( ParEnv % PEs > 1 ) THEN
DO j=1,SIZE(Amat % Perm)
k = Amat % Perm(j)
IF(k==0) CYCLE
Solver % Variable % Values(Solver % Matrix % Perm(j)) = Var % Values(k)
END DO
ELSE
WHERE(Amat % InvPerm > 0)
Solver % Variable % Values(Amat % InvPerm) = Var % Values
END WHERE
END IF
END DO
BlockMatrix % TotSize = BlockMatrix % Offset( NoVar + 1 )
CALL Info('BlockBackCopyVar','All done',Level=15)
END SUBROUTINE BlockBackCopyVar
SUBROUTINE BlockPickMatrix( Solver, NoVar )
TYPE(Solver_t) :: Solver
INTEGER :: Novar
INTEGER :: RowVar, ColVar
TYPE(Matrix_t), POINTER :: SolverMatrix
TYPE(Matrix_t), POINTER :: Amat
TYPE(ValueList_t), POINTER :: Params
LOGICAL :: ReuseMatrix, Found, EliminateZero
INTEGER::i,j,k,l,n
REAL(KIND=DP) :: SumAbsMat
CALL Info('BlockPickMatrix','Picking block matrix of size '//I2S(NoVar)//' from monolithic one',Level=10)
SolverMatrix => Solver % Matrix
Params => Solver % Values
ReuseMatrix = ListGetLogical( Params,'Block Matrix Reuse',Found)
EliminateZero = ListGetLogical( Params, &
'Block Eliminate Zero Submatrices', Found )
DO RowVar=1,NoVar
DO ColVar=1,NoVar
Amat => TotMatrix % Submatrix(RowVar,ColVar) % Mat
IF( TotMatrix % GotBlockStruct) THEN
CALL Info('BlockPickMatrix','Picking generic block matrix ('&
//I2S(RowVar)//','//I2S(ColVar)//')',Level=20)
CALL CRS_BlockMatrixPick2(SolverMatrix,Amat,TotMatrix % BlockStruct,RowVar,ColVar)
ELSE
IF( ReuseMatrix ) THEN
IF( RowVar + ColVar > 2 .AND. Amat % NumberOfRows == 0 ) THEN
CALL Info('BlockPickMatrix','Copying block matrix topology ('&
//I2S(RowVar)//','//I2S(ColVar)//')',Level=20)
CALL CRS_CopyMatrixTopology( TotMatrix % Submatrix(1,1) % Mat, Amat )
END IF
END IF
CALL Info('BlockPickMatrix','Picking simple block matrix ('&
//I2S(RowVar)//','//I2S(ColVar)//')',Level=20)
CALL CRS_BlockMatrixPick(SolverMatrix,Amat,NoVar,RowVar,ColVar,RowVar == ColVar )
IF( EliminateZero ) THEN
IF( Amat % NumberOfRows > 0 ) THEN
SumAbsMat = SUM( ABS( Amat % Values ) )
IF( SumAbsMat < SQRT( TINY( SumAbsMat ) ) ) THEN
CALL Info('BlockPickMatrix','Matrix is actually all zero, eliminating it!',Level=12)
DEALLOCATE( Amat % Values )
IF( .NOT. ReuseMatrix ) THEN
DEALLOCATE( Amat % Rows, Amat % Cols )
IF( RowVar == ColVar ) DEALLOCATE( Amat % Diag, Amat % rhs )
END IF
Amat % NumberOfRows = 0
END IF
END IF
END IF
END IF
END DO
END DO
BLOCK
INTEGER, POINTER :: BlockStruct(:),BlockPerm(:)
INTEGER :: nl,nk,nv,n0,nj
CALL Info('BlockPickMatrix','Creating permutation to map between block and mono vectors',Level=12)
n = SolverMatrix % NumberOfRows
IF(.NOT. ASSOCIATED( TotMatrix % BlockPerm ) ) THEN
ALLOCATE( TotMatrix % BlockPerm(n) )
END IF
BlockPerm => TotMatrix % BlockPerm
BlockPerm = 0
IF( TotMatrix % GotBlockStruct ) THEN
BlockStruct => TotMatrix % BlockStruct
nl = SIZE(BlockStruct)
nk = MAXVAL(BlockStruct)
nv = n / nl
DO k=1,nk
n0 = COUNT(BlockStruct < k )
nj = COUNT(BlockStruct == k )
j = 0
DO l=1,nl
IF(BlockStruct(l) /= k) CYCLE
j = j+1
DO i=1,nv
BlockPerm(nv*n0+nj*(i-1)+j) = nl*(i-1)+l
END DO
END DO
END DO
ELSE
nv = n/NoVar
DO j=1,NoVar
DO i=1,nv
BlockPerm((j-1)*nv+i) = Novar*(i-1) + j
END DO
END DO
END IF
END BLOCK
END SUBROUTINE BlockPickMatrix
SUBROUTINE BlockPickDofsPhysical( Solver, BlockIndex, NoVar )
TYPE(Solver_t), POINTER :: Solver
INTEGER, POINTER :: BlockIndex(:)
INTEGER :: Novar
INTEGER::i,j,k,t,n,MinBlock,MaxBlock,body_id,bf_id,bc_id,n_bf
TYPE(ValueList_t), POINTER :: List
TYPE(Mesh_t), POINTER :: Mesh
TYPE(Element_t), POINTER :: Element
LOGICAL :: Found
INTEGER :: ElemPerm(27)
INTEGER, POINTER :: Perm(:)
CALL Info('BlockPickDofsPhysical','Picking block matrix of size '&
//I2S(NoVar)//' from monolithic one',Level=10)
n_bf = CurrentModel % NumberOfBodyForces
MinBlock = HUGE(MinBlock)
MaxBlock = 0
DO i=1,n_bf + CurrentModel % NumberOfBCs
IF( i <= n_bf ) THEN
List => CurrentModel % BodyForces(i) % Values
ELSE
List => CurrentModel % BCs(i-n_bf) % Values
END IF
j = ListGetInteger( List,'Block Index',Found )
IF( Found ) THEN
MinBlock = MIN(j,MinBlock)
MaxBlock = MAX(j,MaxBlock)
END IF
END DO
IF( MaxBlock == 0 ) THEN
CALL Fatal('BlockPickDofsPhysical','Cannot create a physical block structure as no >Block Index< given!')
END IF
Mesh => Solver % Mesh
Perm => Solver % Variable % Perm
n = MAXVAL( Perm )
BlockIndex = 0
DO t=1, Mesh % NumberOfBulkElements + Mesh % NumberOfBoundaryElements
Element => Mesh % Elements(t)
IF( t <= Mesh % NumberOfBulkElements ) THEN
body_id = Element % BodyId
bf_id = ListGetInteger( CurrentModel % Bodies(body_id) % Values,'Body Force', Found )
IF( bf_id == 0 ) CYCLE
List => CurrentModel % BodyForces(bf_id) % Values
ELSE
IF(.NOT. ASSOCIATED( Element % BoundaryInfo ) ) CYCLE
DO bc_id=1,CurrentModel % NumberOfBCs
IF ( Element % BoundaryInfo % Constraint == CurrentModel % BCs(bc_id) % Tag ) EXIT
END DO
IF ( bc_id > CurrentModel % NumberOfBCs ) CYCLE
List => CurrentModel % BCs(bc_id) % Values
END IF
j = ListGetInteger( List,'Block Index',Found )
IF( .NOT. Found ) CYCLE
n = Element % Type % NumberOfNodes
ElemPerm(1:n) = Perm( Element % NodeIndexes(1:n) )
IF( ANY(ElemPerm(1:n) == 0 ) ) CYCLE
BlockIndex( ElemPerm(1:n) ) = j
END DO
n = COUNT( BlockIndex == 0 )
IF( n > 0 ) THEN
CALL Info('BlockPickDofsPhysical','Number of indexes without block matrix index: '//I2S(n),Level=7)
IF( MinBlock > 1 ) THEN
k = 1
ELSE
MaxBlock = MaxBlock + 1
k = MaxBlock
END IF
WHERE( BlockIndex == 0 ) BlockIndex = k
ELSE
CALL Info('BlockPickDofsPhysical','All physical domains given block index',Level=10)
END IF
MaxBlock = ParallelReduction(MaxBlock, 2 )
NoVar = MaxBlock
END SUBROUTINE BlockPickDofsPhysical
SUBROUTINE BlockPickHdiv( Solver, BlockIndex, NoVar )
TYPE(Solver_t), POINTER :: Solver
INTEGER, POINTER :: BlockIndex(:)
INTEGER :: Novar
INTEGER :: i,j,n,nn,ne,nf,nb,nnis,neis,nfis,nbis
INTEGER :: nncount,necount,nfcount,nbcount
TYPE(Mesh_t), POINTER :: Mesh
LOGICAL :: Found
INTEGER, POINTER :: Perm(:)
CALL Info('BlockPickHdiv','Picking block matrix for mixed hdiv solver',Level=10)
Mesh => Solver % Mesh
nn = Mesh % NumberOfNodes
ne = Mesh % NumberOfEdges
nf = Mesh % NumberOfFaces
nb = Mesh % NumberOfBulkElements
nnis = 0
neis = 0
nfis = 0
nbis = 0
nncount = 0
necount = 0
nfcount = 0
nbcount = 0
Perm => Solver % Variable % Perm
n = SIZE( Perm )
DO i=1,n
j = Perm(i)
IF( j == 0 ) CYCLE
IF( i <= nn ) THEN
nnis = 1
nncount = nncount + 1
BlockIndex(j) = 1
ELSE IF( i <= nn + ne ) THEN
neis = 1
necount = necount + 1
BlockIndex(j) = nnis + 1
ELSE IF( i <= nn + ne + nf ) THEN
nfis = 1
nfcount = nfcount + 1
BlockIndex(j) = nnis + neis + 1
ELSE
nbis = 1
nbcount = nbcount + 1
BlockIndex(j) = nnis + neis + nfis + 1
END IF
END DO
IF( nncount > 0 ) CALL Info('BlockPickHdiv','Number of nodal dofs: '//I2S(nncount),Level=8)
IF( necount > 0 ) CALL Info('BlockPickHdiv','Number of edge dofs: '//I2S(necount),Level=8)
IF( nfcount > 0 ) CALL Info('BlockPickHdiv','Number of face dofs: '//I2S(nfcount),Level=8)
IF( nbcount > 0 ) CALL Info('BlockPickHdiv','Number of elemental dofs: '//I2S(nbcount),Level=8)
NoVar = nnis + neis + nfis + nbis
CALL Info('BlockPickHdiv','Found dofs related to '//I2S(NoVar)//' groups',Level=6)
END SUBROUTINE BlockPickHdiv
SUBROUTINE BlockPickAV( Solver, BlockIndex, NoVar )
TYPE(Solver_t), POINTER :: Solver
INTEGER, POINTER :: BlockIndex(:)
INTEGER :: Novar
INTEGER :: i,j,n,nn,ne,nf,nb,ais,vis,pis,dofs
INTEGER :: vcount,acount,pcount
TYPE(Mesh_t), POINTER :: Mesh
LOGICAL :: Found, SplitComplex, SplitComplexHcurl, SplitPiola
INTEGER, POINTER :: Perm(:)
CALL Info('BlockPickAV','Picking block matrix for V and A dofs',Level=10)
SplitPiola = ListGetLogical( Solver % Values,'Block Split Piola',Found )
Mesh => Solver % Mesh
nn = Mesh % NumberOfNodes
ne = Mesh % NumberOfEdges
nf = Mesh % NumberOfFaces
nb = Mesh % NumberOfBulkElements
ais = 0
vis = 0
pis = 0
vcount = 0
acount = 0
pcount = 0
Perm => Solver % Variable % Perm
n = SIZE( Perm )
BlockIndex = 0
dofs = Solver % Variable % Dofs
IF(dofs > 2) THEN
CALL Fatal('BlockPickAV','Only implemented for 1 or 2 dofs: '//I2S(dofs))
END IF
DO i=1,n
j = Perm(i)
IF( j == 0 ) CYCLE
IF( i <= nn ) THEN
vis = 1
vcount = vcount + 1
BlockIndex(dofs*j) = 1
ELSE
IF(SplitPiola .AND. i > nn+ne ) THEN
pis = 1
pcount = pcount + 1
BlockIndex(dofs*j) = vis + ais + 1
ELSE
ais = 1
acount = acount + 1
BlockIndex(dofs*j) = vis + 1
END IF
END IF
END DO
IF( vcount > 0 ) CALL Info('BlockPickAV','Number of nodal dofs: '//I2S(vcount),Level=8)
IF( acount > 0 ) CALL Info('BlockPickAV','Number of edge dofs: '//I2S(acount),Level=8)
IF( pcount > 0 ) CALL Info('BlockPickAV','Number of piola edge dofs: '//I2S(pcount),Level=8)
NoVar = vis + ais + pis
IF(dofs > 1) THEN
SplitComplex = ListGetLogical( Solver % Values,'Block Split Complex',Found )
SplitComplexHcurl = ListGetLogical( Solver % Values,'Block Split Complex Hcurl', Found )
IF(SplitComplex .OR. SplitComplexHcurl ) THEN
CALL Info('BlockPickAV','Applying different block numbering to Re/Im dofs',Level=8)
BlockIndex = 2 * BlockIndex
BlockIndex(1::2) = BlockIndex(2::2)-1
NoVar = 2*NoVar
IF(SplitComplexHcurl) THEN
IF(vcount > 0) THEN
BlockIndex = MAX(1,BlockIndex - 1)
NoVar = NoVar-1
CALL Info('BlockPickAV','Moved nodal dofs to same block',Level=8)
END IF
END IF
ELSE
CALL Info('BlockPickAV','Applying same block numbering to Re/Im dofs',Level=8)
BlockIndex(1::2) = BlockIndex(2::2)
END IF
END IF
CALL Info('BlockPickAV','Found dofs related to '//I2S(NoVar)//' groups',Level=6)
END SUBROUTINE BlockPickAV
SUBROUTINE BlockPickReIm( Solver, BlockIndex, NoVar )
TYPE(Solver_t), POINTER :: Solver
INTEGER, POINTER :: BlockIndex(:)
INTEGER :: Novar
INTEGER :: dofs
CALL Info('BlockPickReIm','Picking block matrix for Re and Im dofs',Level=10)
dofs = Solver % Variable % Dofs
IF(MODULO(dofs,2) /= 0) THEN
CALL Fatal('BlockPickReIm','Cannot pick from odd number of dofs: '//I2S(dofs))
END IF
NoVar = 2
BlockIndex(1::2) = 1
BlockIndex(2::2) = 2
END SUBROUTINE BlockPickReIm
SUBROUTINE BlockPickMatrixPerm( Solver, BlockIndex, NoVar, DoAddMatrix )
TYPE(Solver_t) :: Solver
INTEGER, POINTER :: BlockIndex(:)
INTEGER :: Novar
LOGICAL :: DoAddMatrix
INTEGER :: bcol,brow,bi,bk,i,k,j,n,m,istat,NoBlock,dofs
TYPE(Matrix_t), POINTER :: A, B, C
INTEGER, ALLOCATABLE :: BlockNumbering(:), rowcount(:), offset(:)
LOGICAL :: SplitComplex, SplitComplexHCurl, CreatePermPar, GotDiag, Found
REAL(KIND=dp) :: Coeff, Coeff0
CALL Info('BlockPickMatrixPerm','Picking indexed block matrix from monolithic one',Level=10)
A => Solver % Matrix
n = A % NumberOfRows
IF(DoAddMatrix) THEN
NoBlock = NoVar + 1
n = Solver % Matrix % AddMatrix % NumberOfRows
ELSE
NoBlock = NoVar
n = Solver % Matrix % NumberOfRows
END IF
ALLOCATE( BlockNumbering( n ), rowcount(NoVar), offset(NoBlock+1), STAT=istat )
IF(istat /= 0) THEN
CALL Fatal('BlockPickMatrixPerm','Allocation error for BlockNumbering etc.')
END IF
BlockNumbering = 0
RowCount = 0
offset = 0
IF(.NOT. ASSOCIATED(TotMatrix % BlockPerm) ) THEN
ALLOCATE(TotMatrix % BlockPerm(n))
END IF
TotMatrix % BlockPerm = 0
n = Solver % Matrix % NumberOfRows
DO i=1,n
brow = BlockIndex(i)
rowcount(brow) = rowcount(brow) + 1
BlockNumbering(i) = rowcount(brow)
END DO
CreatePermPar = ASSOCIATED(A % InvPerm) .AND. ( ParEnv % PEs > 1 )
DO i = 1, NoVar
B => TotMatrix % SubMatrix(i,i) % Mat
n = rowcount(i)
IF(ASSOCIATED(B % rhs)) THEN
IF(SIZE(B % Rhs) /= n) DEALLOCATE( B % rhs)
END IF
IF(.NOT. ASSOCIATED(B % rhs)) THEN
ALLOCATE(B % Rhs(n))
END IF
B % rhs = 0.0_dp
IF( CreatePermPar ) THEN
m = SIZE( Solver % Variable % Perm ) * Solver % Variable % Dofs
IF(ASSOCIATED(B % Perm)) THEN
IF(SIZE(B % Perm) /= m) DEALLOCATE( B % Perm)
END IF
IF(.NOT. ASSOCIATED(B % Perm)) THEN
ALLOCATE(B % Perm(m))
END IF
B % Perm = 0
END IF
IF(ASSOCIATED(B % InvPerm)) THEN
IF(SIZE(B % InvPerm) /= n) DEALLOCATE( B % InvPerm)
END IF
IF(.NOT. ASSOCIATED(B % InvPerm)) THEN
ALLOCATE(B % InvPerm(n))
END IF
B % InvPerm = 0
offset(i+1) = offset(i) + n
END DO
DO i=1,NoVar
DO j=1,NoVar
B => TotMatrix % SubMatrix(i,j) % Mat
IF ( B % Format == MATRIX_CRS ) B % Values = 0
END DO
END DO
n = Solver % Matrix % NumberOfRows
DO i=1, A % NumberOfRows
brow = BlockIndex(i)
bi = BlockNumbering(i)
B => TotMatrix % SubMatrix(brow,brow) % Mat
B % Rhs(bi) = A % Rhs(i)
IF( CreatePermPar ) THEN
j = A % InvPerm(i)
IF(j<0 .OR. j>SIZE(B % Perm)) THEN
PRINT *,'Too big j:',j,SIZE(B % Perm),i,SIZE(A % Perm),SIZE(A % InvPerm)
STOP
END IF
B % Perm(j) = bi
B % InvPerm(bi) = j
ELSE
B % InvPerm(bi) = i
END IF
TotMatrix % BlockPerm(offset(brow)+bi) = i
DO j=A % Rows(i+1)-1,A % Rows(i),-1
k = A % Cols(j)
bcol = BlockIndex(k)
bk = BlockNumbering(k)
B => TotMatrix % SubMatrix(brow,bcol) % Mat
CALL AddToMatrixElement(B,bi,bk,A % Values(j))
END DO
END DO
IF( DoAddMatrix ) THEN
CALL Info('BlockPickMatrixPerm','Creating additional submatrices from AddMatrix block system!',Level=10)
C => Solver % Matrix % AddMatrix
i = NoBlock
B => TotMatrix % SubMatrix(i,i) % Mat
n = C % NumberOfRows - A % NumberOfRows
offset(i+1) = offset(i) + n
CALL Info('BlockPickMatrixPerm','Number of new rows from AddMatrix: '//I2S(n),Level=20)
TotMatrix % Subvector(i) % AddVector = .TRUE.
IF(ASSOCIATED(B % rhs)) THEN
IF(SIZE(B % Rhs) /= n) DEALLOCATE( B % rhs)
END IF
IF(.NOT. ASSOCIATED(B % rhs)) THEN
ALLOCATE(B % Rhs(n))
END IF
B % rhs = 0.0_dp
IF(ASSOCIATED(B % InvPerm)) THEN
IF(SIZE(B % InvPerm) /= n) DEALLOCATE( B % InvPerm)
END IF
IF(.NOT. ASSOCIATED(B % InvPerm)) THEN
ALLOCATE(B % InvPerm(n))
END IF
B % InvPerm = 0
DO i=1,C % NumberOfRows
IF(i <= A % NumberOfRows ) THEN
IF( A % ConstrainedDOF(i) ) CYCLE
brow = BlockIndex(i)
bi = BlockNumbering(i)
GotDiag = .TRUE.
ELSE
brow = NoBlock
bi = i-A % NumberOfRows
GotDiag = .FALSE.
END IF
B => TotMatrix % SubMatrix(brow,brow) % Mat
B % Rhs(bi) = B % Rhs(bi) + C % Rhs(i)
IF(i> A % NumberOfRows ) THEN
B % InvPerm(bi) = i
TotMatrix % BlockPerm(offset(brow)+bi) = i
END IF
DO j=C % Rows(i+1)-1,C % Rows(i),-1
k = C % Cols(j)
IF(k <= A % NumberOfRows ) THEN
bcol = BlockIndex(k)
bk = BlockNumbering(k)
ELSE
bcol = NoBlock
bk = k-A % NumberOfRows
IF(brow == bcol .AND. bi == bk) GotDiag = .TRUE.
END IF
B => TotMatrix % SubMatrix(brow,bcol) % Mat
CALL AddToMatrixElement(B,bi,bk,C % Values(j))
END DO
IF(.NOT. GotDiag ) THEN
B => TotMatrix % SubMatrix(brow,brow) % Mat
CALL AddToMatrixElement( B,bi,bi,0._dp )
IF( A % COMPLEX ) THEN
IF(MOD(bi,2)==0) THEN
CALL AddToMatrixElement( B,bi,bi-1,0._dp )
ELSE
CALL AddToMatrixElement( B,bi,bi+1,0._dp )
END IF
END IF
END IF
END DO
END IF
DO i = 1, NoBlock
DO j = 1, NoBlock
B => TotMatrix % SubMatrix(i,j) % Mat
IF( B % FORMAT == MATRIX_LIST ) THEN
CALL Info('BlockPickMatrixPerm','Transforming submatrix '//I2S(10*i+j)//' to CRS format',Level=12)
CALL List_toCRSMatrix(B)
END IF
IF( i==j .AND. ParEnv % PEs > 1 ) THEN
CALL ParallelInitMatrix( Solver, B )
END IF
END DO
END DO
IF( ASSOCIATED(A % PrecValues) ) THEN
CALL Info('BlockPickMatrixPerm','Creating preconditioning matrix from monolithic one!')
DO i = 1, NoVar
CALL CRS_CopyMatrixTopology( TotMatrix % Submatrix(i,i) % Mat, &
TotMatrix % Submatrix(i,i) % PrecMat )
END DO
SplitComplex = ListGetLogical( Solver % Values,'Block Split Complex',Found )
IF( SplitComplex ) THEN
SplitComplexHcurl = ListGetLogical( Solver % Values,'Block Split Complex Hcurl', Found )
IF(.NOT. SplitComplexHCurl ) THEN
IF( MODULO(NoVar,2) /= 0) THEN
CALL Fatal('BlockPickMatrixPerm','Requiring even number of blocks for the complex preconditioner!')
END IF
END IF
Coeff0 = ListGetCReal( Solver % Values,'Prec Matrix Complex Coeff',Found)
IF(.NOT. Found) Coeff0 = 1.0_dp
END IF
DO i=1,A % NumberOfRows
brow = BlockIndex(i)
bi = BlockNumbering(i)
DO j=A % Rows(i+1)-1,A % Rows(i),-1
k = A % Cols(j)
bcol = BlockIndex(k)
bk = BlockNumbering(k)
IF(bcol == brow ) THEN
B => TotMatrix % SubMatrix(brow,brow) % PrecMat
CALL AddToMatrixElement(B,bi,bk,A % PrecValues(j))
ELSE IF( SplitComplex .AND. ABS(bcol-brow)==1) THEN
IF(SplitComplexHcurl ) THEN
IF(brow == 2 .AND. bcol == 3) THEN
Coeff = Coeff0
ELSE IF(brow == 3 .AND. bcol == 2 ) THEN
Coeff = -Coeff0
ELSE
CYCLE
END IF
ELSE
IF( MODULO(brow,2) == 1 .AND. bcol == brow+1) THEN
Coeff = Coeff0
ELSE IF( MODULO(brow,2) == 0 .AND. bcol == brow-1) THEN
Coeff = -Coeff0
ELSE
CYCLE
END IF
END IF
B => TotMatrix % SubMatrix(brow,brow) % PrecMat
CALL AddToMatrixElement(B,bi,bk,Coeff*A % PrecValues(j))
END IF
END DO
END DO
END IF
END SUBROUTINE BlockPickMatrixPerm
#if 0
SUBROUTINE BlockPickMatrixAV( Solver, NoVar )
TYPE(Solver_t) :: Solver
INTEGER :: Novar
INTEGER :: RowVar, ColVar
TYPE(Matrix_t), POINTER :: SolverMatrix
TYPE(Matrix_t), POINTER :: Amat
INTEGER::i,j,k,i_aa,i_vv,i_av,i_va,n;
TYPE(Matrix_t), POINTER :: B_aa,B_av,B_va,B_vv,C_aa,C_vv,A,CM
REAL(KIND=DP) :: SumAbsMat
CALL Info('BlockPickMatrixAV','Picking block matrix from monolithic one',Level=8)
SolverMatrix => Solver % Matrix
A => SolverMatrix
i_aa=0; i_vv=0; i_av=0; i_va=0;
n = Solver % Mesh % NumberOfNodes
B_vv => TotMatrix % SubMatrix(1,1) % Mat
B_va => TotMatrix % SubMatrix(1,2) % Mat
B_av => TotMatrix % SubMatrix(2,1) % Mat
B_aa => TotMatrix % SubMatrix(2,2) % Mat
IF(ASSOCIATED(B_aa % Values)) B_aa % Values=0._dp
IF(ASSOCIATED(B_av % Values)) B_av % Values=0._dp
IF(ASSOCIATED(B_va % Values)) B_va % Values=0._dp
IF(ASSOCIATED(B_vv % Values)) B_vv % Values=0._dp
DO i=1,SIZE(Solver % Variable % Perm)
j = Solver % Variable % Perm(i)
IF(j<=0) CYCLE
IF (i<=n) THEN
i_vv=i_vv+1
ELSE
i_aa=i_aa+1
END IF
DO k=A % Rows(j+1)-1,A % Rows(j),-1
IF(i<=n.AND.A % Cols(k)<=n) THEN
CALL AddToMatrixElement(B_vv,i_vv,A % Cols(k),A % Values(k))
ELSE IF (i<=n.AND.A % Cols(k)>n) THEN
CALL AddToMatrixElement(B_va,i_vv,A % Cols(k)-n,A % Values(k))
ELSE IF (i>n.AND.A % Cols(k)<=n) THEN
CALL AddToMatrixElement(B_av,i_aa,A % Cols(k),A % Values(k))
ELSE
CALL AddToMatrixElement(B_aa,i_aa,A % Cols(k)-n,A % Values(k))
END IF
END DO
END DO
IF (B_aa % Format == MATRIX_LIST) THEN
CALL List_toCRSMatrix(B_aa)
CALL List_toCRSMatrix(B_av)
CALL List_toCRSMatrix(B_va)
CALL List_toCRSMatrix(B_vv)
END IF
IF(ASSOCIATED(B_aa % Rhs)) THEN
DEALLOCATE(B_aa % Rhs, B_vv % Rhs)
END IF
ALLOCATE(B_aa % Rhs(B_aa % NumberOfRows))
ALLOCATE(B_vv % Rhs(B_vv % NumberOfRows))
i_vv=0; i_aa=0
DO i=1,SIZE(Solver % Variable % Perm)
j = Solver % Variable % Perm(i)
IF(j<=0) CYCLE
IF (i<=n) THEN
i_vv=i_vv+1
B_vv % Rhs(i_vv) = A % Rhs(j)
ELSE
i_aa=i_aa+1
B_aa % Rhs(i_aa) = A % Rhs(j)
END IF
END DO
CM => A % ConstraintMatrix
IF( ASSOCIATED(CM) ) THEN
CALL Info('BlockPickMatrixAV','Adding constraint matrices to block AV system!',Level=10)
END IF
DO WHILE(ASSOCIATED(CM))
C_aa=>AllocateMatrix(); C_aa % Format=MATRIX_LIST
C_vv=>AllocateMatrix(); C_vv % Format=MATRIX_LIST
i_aa=0; i_vv=0;
DO i=1,CM % NumberOFRows
IF(CM % Cols(CM % Rows(i))<=n) THEN
i_vv=i_vv+1
ELSE
i_aa=i_aa+1
END IF
DO j=CM % Rows(i),CM % Rows(i+1)-1
IF (CM % Values(j)==0._dp) CYCLE
IF (CM % Cols(j)<=n) THEN
CALL AddToMatrixElement(C_vv,i_vv,CM % Cols(j),CM % Values(j))
ELSE
CALL AddToMatrixElement(C_aa,i_aa,CM % Cols(j)-n,CM % Values(j))
END IF
END DO
END DO
C_aa % ConstraintMatrix => Null()
B_aa % ConstraintMatrix => C_aa
C_vv % ConstraintMatrix => Null()
B_vv % ConstraintMatrix => C_vv
CALL List_toCRSMatrix(C_vv)
CALL List_toCRSMatrix(C_aa)
ALLOCATE(C_aa % Rhs(C_aa % NumberOfRows)); C_aa % Rhs=0._dp
ALLOCATE(C_vv % Rhs(C_vv % NumberOfRows)); C_vv % Rhs=0._dp
CM => CM % ConstraintMatrix
IF(c_vv%numberofrows<=0) b_vv%constraintmatrix=>null()
END DO
CALL Info('BlockPickMatrixAV','Finished picking block martrix!',Level=20)
END SUBROUTINE BlockPickMatrixAV
#endif
SUBROUTINE BlockPickMatrixHorVer( Solver, NoVar, Cart, DTag)
TYPE(Solver_t) :: Solver
INTEGER :: Novar
LOGICAL :: Cart
INTEGER :: DTag(:)
INTEGER::i,j,k,n,t,ne,dofs,nd,ni,nn,ndir(3),ic,kc
TYPE(Matrix_t), POINTER :: A,B
TYPE(Nodes_t), SAVE :: Nodes, EdgeNodes
INTEGER :: ActiveCoordinate
INTEGER, ALLOCATABLE :: DPerm(:)
INTEGER, POINTER :: Indexes(:)
TYPE(Mesh_t), POINTER :: Mesh
REAL(KIND=dp) :: Wlen, Wproj, Wtol, u, v, w, DetJ, Normal(3), MaxCoord, MinCoord
TYPE(GaussIntegrationPoints_t) :: IP
LOGICAL :: PiolaVersion, Found, Stat
TYPE(Element_t), POINTER :: Element, Edge
REAL(KIND=dp), POINTER :: Coord(:)
REAL(KIND=dp), ALLOCATABLE :: WBasis(:,:), RotWBasis(:,:)
REAL(KIND=dp), ALLOCATABLE :: Basis(:), dBasisdx(:,:)
n = 28
ALLOCATE( WBasis(n,3), RotWBasis(n,3), Basis(n), dBasisDx(n,3), Indexes(n) )
CALL Info('BlockPickMatrixHorVer','Dividing matrix into vertical and horizontal dofs',Level=10)
IF (Cart) THEN
NoVar = 3
ELSE
NoVar = 2
END IF
n = MAXVAL(Solver % Variable % Perm)
Mesh => Solver % Mesh
A => Solver % Matrix
dofs = Solver % Variable % Dofs
n = A % NumberOfRows / dofs
DTag = 0
PiolaVersion = ListGetLogical( Solver % Values,'Use Piola Transform', Found )
ActiveCoordinate = ListGetInteger( Solver % Values,'Active Coordinate',Found )
IF(.NOT. Found ) ActiveCoordinate = 3
Normal = 0.0_dp
Normal(ActiveCoordinate) = 1.0_dp
Wtol = 1.0e-3
DO t=1,Solver % NumberOfActiveElements
Element => Mesh % Elements( Solver % ActiveElements(t) )
nn = Element % TYPE % NumberOfNodes
nd = GetElementDOFs( Indexes, Element, Solver)
CALL GetElementNodes( Nodes, Element )
IF( Cart ) THEN
DO ActiveCoordinate = 1, 3
IF( ActiveCoordinate == 1 ) THEN
Coord => Nodes % x
ELSE IF( ActiveCoordinate == 2 ) THEN
Coord => Nodes % y
ELSE
Coord => Nodes % z
END IF
MinCoord = MINVAL( Coord(1:nn) )
MaxCoord = MAXVAL( Coord(1:nn) )
Wlen = MaxCoord - MinCoord
DO i=1,nd
j = Solver % Variable % Perm(Indexes(i))
IF( i <= Element % TYPE % NumberOfEdges ) THEN
Edge => Mesh % Edges( Element % EdgeIndexes(i) )
CALL GetElementNodes( EdgeNodes, Edge )
ne = Edge % TYPE % NumberOfNodes
IF( ActiveCoordinate == 1 ) THEN
Coord => EdgeNodes % x
ELSE IF( ActiveCoordinate == 2 ) THEN
Coord => EdgeNodes % y
ELSE
Coord => EdgeNodes % z
END IF
MinCoord = MINVAL( Coord(1:ne) )
MaxCoord = MAXVAL( Coord(1:ne) )
ELSE
CALL Fatal('BlockPickMatrixHorVer','Cannot do faces yet!')
END IF
Wproj = ( MaxCoord - MinCoord ) / Wlen
IF( WProj > 1.0_dp - Wtol ) DTag(j) = ActiveCoordinate
END DO
END DO
ELSE IF(.TRUE.) THEN
IF( ActiveCoordinate == 1 ) THEN
Coord => Nodes % x
ELSE IF( ActiveCoordinate == 2 ) THEN
Coord => Nodes % y
ELSE
Coord => Nodes % z
END IF
MinCoord = MINVAL( Coord(1:nn) )
MaxCoord = MAXVAL( Coord(1:nn) )
Wlen = MaxCoord - MinCoord
DO i=1,nd
j = Solver % Variable % Perm(Indexes(i))
IF( i <= Element % Type % NumberOfEdges ) THEN
Edge => Mesh % Edges( Element % EdgeIndexes(i) )
CALL GetElementNodes( EdgeNodes, Edge )
ne = Edge % Type % NumberOfNodes
IF( Indexes(i) /= Mesh % NumberOfNodes + Element % EdgeIndexes(i) ) THEN
PRINT *,'ind com:',Indexes(i), Mesh % NumberOfNodes + Element % EdgeIndexes(i), &
Mesh % NumberOfNodes
END IF
IF( ActiveCoordinate == 1 ) THEN
Coord => EdgeNodes % x
ELSE IF( ActiveCoordinate == 2 ) THEN
Coord => EdgeNodes % y
ELSE
Coord => EdgeNodes % z
END IF
MinCoord = MINVAL( Coord(1:ne) )
MaxCoord = MAXVAL( Coord(1:ne) )
ELSE
CALL Fatal('BlockPickMatrixHorVer','Cannot do faces yet!')
END IF
Wproj = ( MaxCoord - MinCoord ) / Wlen
IF( WProj > 1.0_dp - Wtol ) THEN
IF( dofs == 1 ) THEN
DTag(j) = 1
ELSE
DTag(2*j-1) = 1
DTag(2*j) = 1
END IF
ELSE IF( Wproj < Wtol ) THEN
IF( dofs == 1 ) THEN
DTag(j) = 2
ELSE
DTag(2*j-1) = 2
DTag(2*j) = 2
END IF
END IF
END DO
ELSE
IP = GaussPoints(Element, EdgeBasis=.TRUE., PReferenceElement=PiolaVersion)
u = SUM( IP % u ) / IP % n
v = SUM( IP % v ) / IP % n
w = IP % w(k)
IF (PiolaVersion) THEN
stat = EdgeElementInfo( Element, Nodes, u, v, w, &
DetF = DetJ, Basis = Basis, EdgeBasis = WBasis, &
RotBasis = RotWBasis, dBasisdx = dBasisdx, &
ApplyPiolaTransform = .TRUE.)
ELSE
stat = ElementInfo( Element, Nodes, u, v, w, &
detJ, Basis, dBasisdx )
CALL GetEdgeBasis(Element, WBasis, RotWBasis, Basis, dBasisdx)
END IF
DO i=1,nd
j = Solver % Variable % Perm(Indexes(i))
Wlen = SQRT( SUM( WBasis(i,:)**2 ) )
IF( Wlen < EPSILON( Wlen ) ) CYCLE
Wproj = ABS( SUM( WBasis(i,:) * Normal ) ) / Wlen
IF( WProj > 1.0_dp - Wtol ) THEN
IF( dofs == 1 ) THEN
DTag(j) = 1
ELSE
DTag(2*j-1) = 1
DTag(2*j) = 1
END IF
ELSE IF( Wproj < Wtol ) THEN
IF( dofs == 1 ) THEN
DTag(j) = 2
ELSE
DTag(2*j-1) = 2
DTag(2*j) = 2
END IF
ELSE
PRINT *,'Edge '//I2S(j)//' direction undefined: ',Wproj
END IF
END DO
END IF
END DO
IF( InfoActive(20) ) THEN
DO i=1,NoVar
j = COUNT(DTag==i)
CALL Info('BlockPickMatrixHorVer','There are '//I2S(j)//' dofs group '//I2S(i))
END DO
END IF
END SUBROUTINE BlockPickMatrixHorVer
SUBROUTINE BlockPickMatrixHcurl( Solver, NoVar, DoCmplx, BlockTag )
TYPE(Solver_t) :: Solver
INTEGER :: Novar
LOGICAL :: DoCmplx
INTEGER :: BlockTag(:)
INTEGER :: i,j,k,n,m,n0,dofs,ic,kc
TYPE(Matrix_t), POINTER :: A,B
TYPE(Mesh_t), POINTER :: Mesh
TYPE(Element_t), POINTER :: Element, Edge
LOGICAL :: Found
Mesh => Solver % Mesh
IF(.NOT. ASSOCIATED( Mesh % Edges ) ) THEN
CALL Fatal('BlockPickMatrixHcurl','This subroutine needs Edges!')
END IF
IF(.NOT. ASSOCIATED( Mesh % Faces ) ) THEN
CALL Fatal('BlockPickMatrixHcurl','This subroutine needs Faces!')
END IF
CALL Info('BlockPickMatrixHcurl','Arranging a quadratic H(curl) approximation into blocks',Level=10)
NoVar = 2
IF( ListGetLogical( Solver % Values,'Block Quadratic Hcurl Faces',Found ) ) NoVar = 3
IF(DoCmplx) THEN
NoVar = 2 * NoVar
IF( ListGetLogical( Solver % Values,'Block Quadratic Hcurl semicomplex',Found ) ) NoVar = 3
END IF
A => Solver % Matrix
dofs = Solver % Variable % Dofs
m = A % NumberOfRows
n = m
IF( DoCmplx ) THEN
BlockTag(1::2) = 3
BlockTag(2::2) = 4
ELSE
BlockTag = 2
END IF
n0 = Mesh % NumberOfNodes
DO i=1, Mesh % NumberOfEdges
j = n0 + 2*i-1
k = Solver % Variable % Perm(j)
IF(k==0) CYCLE
IF( dofs == 1 ) THEN
BlockTag(k) = 1
ELSE IF(dofs == 2 ) THEN
BlockTag(2*k-1) = 1
IF( DoCmplx ) THEN
BlockTag(2*k) = 2
ELSE
BlockTag(2*k) = 1
END IF
END IF
END DO
IF(NoVar == 3) THEN
IF( DoCmplx ) THEN
WHERE( BlockTag > 1 )
BlockTag = BlockTag - 1
END WHERE
ELSE
DO j = n0 + 2*Mesh % NumberOfEdges + 1, SIZE(Solver % Variable % Perm)
k = Solver % Variable % Perm(j)
IF(k==0) CYCLE
IF(dofs == 1 ) THEN
BlockTag(k) = 3
ELSE IF( dofs == 2 ) THEN
BlockTag(2*k-1) = 3
BlockTag(2*k) = 3
END IF
END DO
END IF
END IF
IF( InfoActive(20) ) THEN
DO i=1,NoVar
j = COUNT(BlockTag==i)
CALL Info('BlockMatrixHCurl','There are '//I2S(j)//' dofs group '//I2S(i))
END DO
END IF
END SUBROUTINE BlockPickMatrixHcurl
SUBROUTINE BlockPickMatrixNodal( Solver, NoVar, DoCmplx, BlockTag )
TYPE(Solver_t) :: Solver
INTEGER :: Novar
LOGICAL :: DoCmplx
INTEGER :: BlockTag(:)
INTEGER :: i,j,k,n,dofs
TYPE(Matrix_t), POINTER :: A
TYPE(Mesh_t), POINTER :: Mesh
LOGICAL :: Found
Mesh => Solver % Mesh
CALL Info('BlockPickMatrixNodal','Separates nodal and non-nodal dofs from each other',Level=10)
NoVar = 2
IF(DoCmplx) NoVar = 2 * NoVar
A => Solver % Matrix
dofs = Solver % Variable % Dofs
IF( DoCmplx ) THEN
BlockTag(1::2) = 3
BlockTag(2::2) = 4
ELSE
BlockTag = 2
END IF
DO i=1, Mesh % NumberOfNodes
k = Solver % Variable % Perm(j)
IF(k==0) CYCLE
IF( dofs == 1 ) THEN
BlockTag(k) = 1
ELSE IF(dofs == 2 ) THEN
BlockTag(2*k-1) = 1
IF( DoCmplx ) THEN
BlockTag(2*k) = 2
ELSE
BlockTag(2*k) = 1
END IF
END IF
END DO
IF( InfoActive(20) ) THEN
DO i=1,NoVar
j = COUNT(BlockTag==i)
CALL Info('BlockMatrixNodal','There are '//I2S(j)//' dofs group '//I2S(i))
END DO
END IF
END SUBROUTINE BlockPickMatrixNodal
SUBROUTINE BlockPickConstraint( Solver, NoVar, SkipPrec )
TYPE(Solver_t), TARGET :: Solver
INTEGER :: Novar
LOGICAL :: SkipPrec
INTEGER :: RowVar, ColVar
TYPE(Matrix_t), POINTER :: SolverMatrix
TYPE(Matrix_t), POINTER :: Amat
TYPE(ValueList_t), POINTER :: Params
LOGICAL :: Found
LOGICAL :: BlockAV
INTEGER::i,j,k,l,n,i1,i2,i3,rowi,colj,NoCon,rb,cb
TYPE(Matrix_t), POINTER :: A,CM,C1,C2,C3,C1prec,C2prec,C3prec,Tmat
REAL(KIND=dp) :: PrecCoeff,val
INTEGER, POINTER :: ConsPerm(:), ConsPerm2(:)
INTEGER :: DoPrec
CHARACTER(:), ALLOCATABLE :: VarName
TYPE(Variable_t), POINTER :: Var
TYPE(Solver_t), POINTER :: PSolver
LOGICAL :: InheritCM, PrecTrue
LOGICAL, ALLOCATABLE :: vflag(:)
INTEGER, ALLOCATABLE :: REdgePerm(:), RNodePerm(:), BlockNumbering(:), InvPerm(:)
CALL Info('BlockPickConstraint','Picking constraints to block matrix',Level=10)
SolverMatrix => Solver % Matrix
Params => Solver % Values
BlockAV = ListGetLogical( Params,'Block A-V System', Found)
BlockAV = BlockAV .OR. ListGetLogical( Params,'Block A-V System Old', Found)
A => SolverMatrix
n = Solver % Mesh % NumberOfNodes
PrecCoeff = ListGetConstReal( Params,'Block Diag Coeff',Found)
IF(.NOT. Found ) PrecCoeff = 1.0_dp
PrecTrue = ListGetLogical( Params,'Block Diag True',Found )
NoCon = 0
CM => A % ConstraintMatrix
DO WHILE(ASSOCIATED(CM))
NoCon = NoCon + 1
CM => CM % ConstraintMatrix
END DO
CALL Info('BlockPickConstraint','Number of constraint matrices: '//I2S(NoCon),Level=10)
InheritCM = (NoVar == 1 ) .AND. (NoCon == 1 )
IF( InheritCM ) THEN
CALL info('BlockPickConstraint','Inheriting constraint matrix',Level=20)
END IF
IF( NoVar == 1 ) THEN
IF( InheritCM ) THEN
C1 => A % ConstraintMatrix
TotMatrix % Submatrix(NoVar+1,1) % Mat => A % ConstraintMatrix
CALL Info('BlockPickConstraint',&
'Using constraint matrix ('//I2S(NoVar+1)//',1) as is!',Level=10)
i = A % ConstraintMatrix % NumberOfRows
CALL Info('BlockPickConstraint','Number of rows in matrix: '//I2S(i),Level=20)
IF( PrecTrue ) THEN
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % Mat
ELSE
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % PrecMat
END IF
ELSE
C1 => TotMatrix % Submatrix(NoVar+1,1) % Mat
IF( PrecTrue ) THEN
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % Mat
ELSE
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % PrecMat
END IF
END IF
ELSE IF(BlockAV) THEN
IF( PrecTrue ) THEN
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % Mat
C2prec => TotMatrix % Submatrix(NoVar+2,NoVar+2) % Mat
ELSE
C1prec => TotMatrix % Submatrix(NoVar+1,NoVar+1) % PrecMat
C2prec => TotMatrix % Submatrix(NoVar+2,NoVar+2) % PrecMat
END IF
C1 => TotMatrix % SubMatrix(NoVar+1,1) % Mat
C2 => TotMatrix % SubMatrix(NoVar+2,2) % Mat
ELSE
CALL Fatal('BlockPickConstraint','Not done for vectors!')
END IF
CM => A % ConstraintMatrix
n = Solver % Mesh % NumberOfNodes
DO WHILE(ASSOCIATED(CM))
IF(.NOT.BlockAV ) n = MAX( n, MAXVAL(MOD(CM % InvPerm-1,A % NumberOfRows)+1) )
CM => CM % ConstraintMatrix
END DO
CM => A % ConstraintMatrix
ALLOCATE( ConsPerm( A % NumberOfRows) )
ConsPerm = 0;
IF ( BlockAV ) THEN
ALLOCATE( ConsPerm2(A % NumberofRows) )
ConsPerm2 = 0
END IF
IF ( BlockAV ) THEN
ALLOCATE( InvPerm(MAXVAL(Solver % Variable % Perm)))
InvPerm = 0
DO i=1,SIZE(Solver % Variable % Perm)
j = Solver % Variable % Perm(i)
IF ( j>0 ) InvPerm(j) = i
END DO
j = CM % NumberOfRows
ALLOCATE( rEdgePerm(j), rNodePerm(j) )
rEdgePerm = 0
rNodePerm = 0
i1 = 0
i2 = 0
DO i=1,CM % NumberOFRows
j = CM % InvPerm(i)
j = MOD(j-1,A % NumberOfRows)+1
j = InvPerm(j)
IF ( j > n ) THEN
i2 = i2+1
rEdgePerm(i) = i2
ELSE IF ( j>0 .AND. j <= n ) THEN
i1 = i1 +1
rNodePerm(i) = i1
ELSE
stop 'cm invperm'
END IF
END DO
END IF
j = Solver % Matrix % NumberOfRows
ALLOCATE( vFlag(j), BlockNumbering(j) )
IF (BlockAV) THEN
i1 = 0; i2 = 0
k = SIZE(Solver % Variable % Perm)
DO i=1,k
j = Solver % variable % Perm(i)
IF ( j<= 0 ) CYCLE
vFlag(j) = i <= n
END DO
ELSE
vFlag = .TRUE.
END IF
k = Solver % Matrix % NumberOfRows
i1 = 0; i2=0
BlockNumbering = 0
DO i=1,k
IF ( vFlag(i) ) THEN
i1 = i1 + 1
BlockNumbering(i) = i1
ELSE
i2 = i2 + 1
BlockNumbering(i) = i2
END IF
END DO
IF ( .NOT. InheritCM ) THEN
IF ( C1 % Format == MATRIX_CRS ) THEN
C1 % Values = 0
IF ( ASSOCIATED(C1prec) ) THEN
IF ( ASSOCIATED(C1prec % Values) ) C1prec % Values = 0
END IF
END IF
IF ( BlockAV ) THEN
IF ( C2 % Format == MATRIX_CRS ) THEN
C2 % Values = 0
IF ( ASSOCIATED(C2prec) ) THEN
IF ( ASSOCIATED(C2prec % Values) ) C2prec % Values = 0
END IF
END IF
END IF
END IF
DO DoPrec = 0, 1
IF( DoPrec == 1 .AND. SkipPrec ) CYCLE
i1 = 0
i2 = 0
CM => A % ConstraintMatrix
DO WHILE(ASSOCIATED(CM))
DO i=1,CM % NumberOFRows
rowi = MOD(CM % InvPerm(i)-1, A % NumberOfRows)+1
rb = 1
i1 = i1 + 1
IF( BlockAV ) THEN
IF( rEdgePerm(i)>0 ) rb = 2
IF( rb == 1 ) THEN
i1 = rNodePerm(i)
ELSE
i2 = rEdgePerm(i)
END IF
END IF
IF( DoPrec == 0 ) THEN
IF ( rb == 1 ) THEN
ConsPerm(rowi) = i1
ELSE
ConsPerm2(rowi) = i2
END IF
END IF
DO j=CM % Rows(i),CM % Rows(i+1)-1
IF (CM % Values(j)==0._dp) CYCLE
colj = CM % Cols(j)
cb = 1
IF( BlockAV ) THEN
IF( .NOT. vFlag(colj) ) cb = 2
END IF
colj = BlockNumbering(colj)
val = CM % Values(j)
IF( DoPrec == 1 ) THEN
IF( ConsPerm( colj ) > 0 ) THEN
val = -PrecCoeff * val
IF ( cb == 1 ) THEN
CALL AddToMatrixElement(C1prec,i1,ConsPerm(colj),val)
ELSE
CALL AddToMatrixElement(C2prec,i2,ConsPerm2(colj),val)
END IF
END IF
ELSE IF( .NOT. InheritCM ) THEN
IF ( cb == 1 ) THEN
CALL AddToMatrixElement(C1,i1,colj,val)
ELSE
CALL AddToMatrixElement(C2,i2,colj,val)
END IF
END IF
END DO
END DO
CM => CM % ConstraintMatrix
END DO
#if 0
IF( DoPrec == 0 .AND. .NOT. SkipPrec ) THEN
CALL AddToMatrixElement(C1prec,i1,i1,0.0_dp)
END IF
#endif
END DO
CALL Info('BlockPickConstraint','Setting format of constraint blocks to CRS',Level=20)
IF(.NOT. InheritCM ) THEN
CALL List_toCRSMatrix(C1)
END IF
IF(.NOT. SkipPrec ) CALL List_toCRSMatrix(C1prec)
IF( BlockAV ) THEN
CALL List_toCRSMatrix(C2)
IF(.NOT. SkipPrec) CALL List_toCRSMatrix(C2prec)
END IF
IF( ListGetLogical( Solver % Values,'Save Prec Matrix', Found ) ) THEN
CALL SaveProjector(C1prec,.TRUE.,"CM")
END IF
VarName = "lambda_n"
Var => VariableGet( Solver % Mesh % Variables, VarName )
IF(ASSOCIATED( Var ) ) THEN
n = SIZE( Var % Values )
DEALLOCATE(ConsPerm)
CALL Info('BlockPickConstraint','Using existing variable > '//VarName//' <')
ELSE
CALL Info('BlockPickConstraint','Variable > '//VarName//' < does not exist, creating')
n = MAXVAL(ConsPerm)
PSolver => Solver
Var => CreateBlockVariable(PSolver, NoVar+1, VarName, 1, ConsPerm )
END IF
TotMatrix % SubVector(NoVar+1) % Var => Var
TotMatrix % Offset(NoVar+2) = TotMatrix % Offset(NoVar+1) + n
TotMatrix % MaxSize = MAX( TotMatrix % MaxSize, n )
TotMatrix % TotSize = TotMatrix % TotSize + n
TotMatrix % SubMatrix(NoVar+1,1) % Mat => C1
Tmat => TotMatrix % SubMatrix(1,NoVar+1) % Mat
IF ( ASSOCIATED(Tmat) ) CALL FreeMatrix(Tmat)
TotMatrix % SubMatrix(1,NoVar+1) % Mat => CRS_Transpose(C1)
TotMatrix % SubMatrix(1,NoVar+1) % ParallelIsolatedMatrix = &
TotMatrix % SubMatrix(NoVar+1,1) % ParallelIsolatedMatrix
IF ( BlockAV ) THEN
VarName = "lambda_a"
Var => VariableGet( Solver % Mesh % Variables, VarName )
IF(ASSOCIATED( Var ) ) THEN
n = SIZE( Var % Values )
DEALLOCATE(ConsPerm2)
CALL Info('BlockPickConstraint','Using existing variable > '//VarName//' <')
ELSE
CALL Info('BlockPickConstraint','Variable > '//VarName//' < does not exist, creating')
n = MAXVAL(ConsPerm2)
Var => CreateBlockVariable(PSolver, NoVar+2, VarName, 1, ConsPerm2 )
END IF
TotMatrix % SubVector(NoVar+2) % Var => Var
TotMatrix % Offset(NoVar+3) = TotMatrix % Offset(NoVar+2) + n
TotMatrix % MaxSize = MAX( TotMatrix % MaxSize, n )
TotMatrix % TotSize = TotMatrix % TotSize + n
TotMatrix % SubMatrix(NoVar+2,2) % Mat => C2
Tmat => TotMatrix % SubMatrix(2,NoVar+2) % Mat
IF ( ASSOCIATED(Tmat) ) CALL FreeMatrix(Tmat)
TotMatrix % SubMatrix(2,NoVar+2) % Mat => CRS_Transpose(C2)
TotMatrix % SubMatrixActive(2,NoVar+2) = .TRUE.
TotMatrix % SubMatrixActive(NoVar+2,2) = .TRUE.
TotMatrix % SubMatrix(2,NoVar+2) % ParallelIsolatedMatrix = &
TotMatrix % SubMatrix(NoVar+2,2) % ParallelIsolatedMatrix
END IF
END SUBROUTINE BlockPickConstraint
SUBROUTINE BlockPrecMatrix( Solver, NoVar )
TYPE(Solver_t) :: Solver
INTEGER :: Novar
INTEGER :: i, RowVar, ColVar, CopyVar
CHARACTER(:), ALLOCATABLE :: str
REAL(KIND=dp) :: Coeff, Coeff0
LOGICAL :: GotIt, GotIt2, DoIt
INTEGER, POINTER :: VarPerm(:)
TYPE(ValueList_t), POINTER :: Params
TYPE(Matrix_t), POINTER :: Amat, PMat
TYPE(Variable_t), POINTER :: AVar
LOGICAL :: SplitComplexHcurl
CALL Info('BlockPrecMatrix','Checking for tailored preconditioning matrices',Level=6)
Params => Solver % Values
SplitComplexHcurl = ListGetLogical( Params,'Block Split Complex Hcurl', GotIt )
DO RowVar=1,NoVar
i = TotMatrix % Submatrix(RowVar,RowVar) % PrecMat % NumberOfRows
IF( i > 0 ) CYCLE
str = 'Prec Matrix Diffusion '//I2S(RowVar)
Coeff = ListGetCReal( Params, str, GotIt)
str = 'Prec Matrix Density '//I2S(RowVar)
Coeff = ListGetCReal( Params, str, GotIt2)
IF( GotIt .OR. GotIt2 ) THEN
CALL CRS_CopyMatrixTopology( TotMatrix % Submatrix(RowVar,RowVar) % Mat, &
TotMatrix % Submatrix(RowVar,RowVar) % PrecMat )
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
VarPerm => TotMatrix % Subvector(RowVar) % Var % Perm
IF( GotIt ) THEN
CALL Info('BlockPrecMatrix','Creating simple preconditioning Laplace matrix',Level=8)
CALL LaplaceMatrixAssembly( Solver, VarPerm, Amat )
Amat % Values = Coeff * Amat % Values
ELSE
CALL Info('BlockPrecMatrix','Creating simple preconditioning mass matrix',Level=8)
CALL MassMatrixAssembly( Solver, VarPerm, Amat )
Amat % Values = Coeff * Amat % Values
END IF
Amat % ParallelInfo => TotMatrix % Submatrix(RowVar,RowVar) % Mat % ParallelInfo
END IF
str = 'Prec Matrix Complex Coeff '//I2S(RowVar)
Coeff = ListGetCReal( Params, str, GotIt )
IF(.NOT. GotIt) THEN
str = 'Prec Matrix Complex Coeff'
Coeff = ListGetCReal( Params, str, GotIt )
END IF
IF(.NOT. GotIt) THEN
GotIt = ListGetLogical( Params,'Block Split Complex', GotIt )
Coeff = 1.0_dp
END IF
Coeff0 = Coeff
IF( GotIt ) THEN
IF(ASSOCIATED(Solver % Matrix % PrecValues) ) THEN
CALL Info('BlockPermMatrix','Skipping adding off-diagonal prec values!')
GotIt = .FALSE.
END IF
END IF
IF(GotIt) THEN
CALL Info('BlockPrecMatrix','Creating preconditioning matrix from block sums',Level=8)
IF( SplitComplexHcurl ) THEN
IF( RowVar == 2 ) THEN
ColVar = RowVar + 1
Coeff = Coeff0
ELSE IF( RowVar == 3 ) THEN
ColVar = RowVar - 1
Coeff = -Coeff0
ELSE
CYCLE
END IF
ELSE
IF( MODULO(NoVar,2) /= 0) THEN
CALL Fatal('BlockPrecMatrix','Assuming even number of blocks for the complex preconditioner!')
END IF
IF( MODULO(RowVar,2) == 1 ) THEN
ColVar = RowVar + 1
Coeff = Coeff0
ELSE
ColVar = RowVar - 1
Coeff = -Coeff0
END IF
END IF
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
IF(Amat % NumberOfRows == 0 ) THEN
CALL CRS_CopyMatrixTopology( TotMatrix % Submatrix(RowVar,RowVar) % Mat, &
TotMatrix % Submatrix(RowVar,RowVar) % PrecMat )
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
END IF
IF( ASSOCIATED( TotMatrix % Submatrix(RowVar,RowVar) % Mat % PrecValues ) ) THEN
AMat % Values = TotMatrix % Submatrix(RowVar,RowVar) % Mat % PrecValues
DEALLOCATE( TotMatrix % Submatrix(RowVar,RowVar) % Mat % PrecValues )
ELSE
AMat % Values = TotMatrix % Submatrix(RowVar,RowVar) % Mat % Values
END IF
IF( SIZE( Amat % Values ) /= SIZE( TotMatrix % Submatrix(RowVar,ColVar) % Mat % Values ) ) THEN
CALL Fatal('BlockPrecMatrix','Mismatch in matrix size for block: '//I2S(10*RowVar+ColVar))
END IF
AMat % Values = Amat % Values + &
Coeff * TotMatrix % Submatrix(RowVar,ColVar) % Mat % Values
END IF
str = 'Prec Matrix Diagonal '//I2S(RowVar)
Coeff = ListGetCReal( Params, str, GotIt)
IF( GotIt ) THEN
CopyVar = NoVar+1 - RowVar
PMat => TotMatrix % Submatrix(RowVar,CopyVar) % Mat
Amat => TotMatrix % Submatrix(RowVar,RowVar) % PrecMat
CALL Info('BlockPrecMatrix','Creating preconditioner from matrix ('&
//I2S(RowVar)//','//I2S(CopyVar)//')',Level=6)
CALL DiagonalMatrixSumming( Solver, PMat, Amat )
Amat % Values = Coeff * Amat % Values
END IF
END DO
IF( ListGetLogical( Params,'Create Schur Matrix Approximation',GotIt ) ) THEN
CALL Info('BlockPrecMatrix','Generating block '//I2S(11*NoVar),Level=7)
IF(NoVar == 1) THEN
CALL Fatal('BlockPrecMatrix','We should have more than one block')
END IF
IF ( NoVar == 4 ) THEN
Pmat => TotMatrix % Submatrix(3,3) % PrecMat
IF ( ASSOCIATED(Pmat) ) CALL FreeMatrix(Pmat)
Pmat => TotMatrix % Submatrix(4,4) % PrecMat
IF ( ASSOCIATED(Pmat) ) CALL FreeMatrix(Pmat)
Pmat => CreateSchurApproximation( &
TotMatrix % Submatrix(1,1) % Mat, &
TotMatrix % Submatrix(3,1) % Mat, &
TotMatrix % Submatrix(1,3) % Mat )
TotMatrix % Submatrix(3,3) % PrecMat => Pmat
Pmat => CreateSchurApproximation( &
TotMatrix % Submatrix(2,2) % Mat, &
TotMatrix % Submatrix(4,2) % Mat, &
TotMatrix % Submatrix(2,4) % Mat )
TotMatrix % Submatrix(4,4) % PrecMat => Pmat
ELSE
Pmat => TotMatrix % Submatrix(2,2) % PrecMat
IF ( ASSOCIATED(Pmat) ) CALL FreeMatrix(Pmat)
Pmat => CreateSchurApproximation( &
TotMatrix % Submatrix(1,1) % Mat, &
TotMatrix % Submatrix(2,1) % Mat, &
TotMatrix % Submatrix(1,2) % Mat )
TotMatrix % Submatrix(2,2) % PrecMat => Pmat
END IF
NULLIFY(Pmat)
END IF
str = ListGetString( Params,'Block Matrix Schur Variable', GotIt)
IF( GotIt ) THEN
AVAr => VariableGet( Solver % Mesh % Variables, str )
IF( .NOT. ASSOCIATED( AVar ) ) THEN
CALL Fatal('BlockPrecMatrix','Schur variable does not exist: '//str)
END IF
IF( .NOT. ASSOCIATED( AVar % Solver ) ) THEN
CALL Fatal('BlockPrecMatrix','Schur solver does not exist for: '//str)
END IF
IF( .NOT. ASSOCIATED( AVar % Solver % Matrix ) ) THEN
CALL Fatal('BlockPrecMatrix','Schur matrix does not exist for: '//str)
END IF
CALL Info('BlockPrecMatrix','Using Schur matrix to precondition block '//I2S(NoVar))
TotMatrix % Submatrix(NoVar,NoVar) % PrecMat => AVar % Solver % Matrix
END IF
IF(ListGetLogical( Params,'Block Nested System',GotIt ) ) THEN
Amat => TotMatrix % Submatrix(1,1) % Mat
IF( ASSOCIATED( Amat % PrecValues ) ) THEN
PMat => TotMatrix % Submatrix(1,1) % PrecMat
IF (.NOT. ASSOCIATED(PMat % Values)) THEN
CALL Info('BlockPrecMatrix','Moving PrecValues to PrecMat!')
CALL CRS_CopyMatrixTopology( AMat, PMat )
ELSE
IF (.NOT. ASSOCIATED(AMat % Rows, PMat % Rows)) &
CALL Fatal('BlockPrecMatrix', 'Inconsistent matrix structures')
END IF
PMat % Values => Amat % PrecValues
NULLIFY(Amat % PrecValues)
END IF
END IF
END SUBROUTINE BlockPrecMatrix
FUNCTION CheckParallelCoupling( A, B, C ) RESULT ( Coupled )
TYPE(Matrix_t), POINTER :: A, B, C
LOGICAL :: Coupled
LOGICAL :: Acoupled, Bcoupled
INTEGER :: i,j,k
REAL(KIND=dp) :: Eps
Coupled = .FALSE.
IF(.NOT. ASSOCIATED( A % ParallelInfo ) ) THEN
CALL Fatal('CheckParallelCoupling','Matrix A does not have ParallelInfo!')
END IF
IF(.NOT. ASSOCIATED( B % ParallelInfo ) ) THEN
CALL Fatal('CheckParallelCoupling','Matrix B does not have ParallelInfo!')
END IF
DO i=1,C % NumberOfRows
DO j=C % Rows(i), C % Rows(i+1)-1
k = C % Cols(j)
IF( ABS( C % Values(j) ) < EPSILON( Eps ) ) CYCLE
IF ( ASSOCIATED(A % ParallelInfo % NeighbourList(i) % Neighbours) ) THEN
IF ( SIZE(A % ParallelInfo % NeighbourList(i) % Neighbours) > 1 ) Coupled = .TRUE.
END IF
IF ( ASSOCIATED(B % ParallelInfo % NeighbourList(k) % Neighbours) ) THEN
IF ( SIZE(B % ParallelInfo % NeighbourList(k) % Neighbours) > 1 ) Coupled = .TRUE.
END IF
IF( Coupled ) EXIT
END DO
END DO
IF( Coupled ) THEN
CALL Info('CheckParallelCoupling','Coupling matrix has parallel connections!',Level=10)
ELSE
CALL Info('CheckParallelCoupling','Coupling matrix does not have parallel connections!',Level=10)
END IF
END FUNCTION CheckParallelCoupling
SUBROUTINE FsiCouplingBlocks( Solver )
TYPE(Solver_t) :: Solver
INTEGER :: i, j, k, Novar
TYPE(ValueList_t), POINTER :: Params
TYPE(Matrix_t), POINTER :: A_fs, A_sf, A_s, A_f
TYPE(Variable_t), POINTER :: FVar, SVar
INTEGER, POINTER :: ConstituentSolvers(:)
LOGICAL :: Found
LOGICAL :: IsPlate, IsShell, IsNs, IsPres
CHARACTER(*), PARAMETER :: Caller = 'FsiCouplingBlocks'
Params => Solver % Values
ConstituentSolvers => ListGetIntegerArray(Params, 'Block Solvers', Found)
IsPlate = .FALSE.
IsShell = .FALSE.
IsNS = .FALSE.
IsPres = .FALSE.
i = ListGetInteger( Params,'Structure Solver Index',Found)
IF ( Found ) THEN
IsPlate = ListGetLogical( CurrentModel % Solvers(i) % Values,&
'Plate Solver', Found )
IsShell = ListGetLogical( CurrentModel % Solvers(i) % Values,&
'Shell Solver', Found )
ELSE
i = ListGetInteger( Params,'Plate Solver Index',IsPlate)
IF(.NOT. IsPlate ) THEN
i = ListGetInteger( Params,'Shell Solver Index',IsShell)
END IF
END IF
IF (i > 0) THEN
Found = .FALSE.
DO k=1,SIZE(ConstituentSolvers)
IF (i == ConstituentSolvers(k)) THEN
Found = .TRUE.
EXIT
END IF
END DO
IF (.NOT. Found) THEN
CALL Fatal(Caller, &
'Structure/Plate/Shell Solver Index is not an entry in the Block Solvers array')
ELSE
i = k
END IF
END IF
IF (i > 2) CALL Fatal(Caller, &
'Use the first two entries of Block Solvers to define FSI coupling')
j = ListGetInteger( Params,'Fluid Solver Index',Found)
IF(.NOT. Found ) THEN
j = ListGetInteger( Params,'NS Solver Index', IsNs )
IF( .NOT. IsNs ) THEN
j = ListGetInteger( Params,'Pressure Solver Index',IsPres)
END IF
END IF
IF (j > 0) THEN
Found = .FALSE.
DO k=1,SIZE(ConstituentSolvers)
IF (j == ConstituentSolvers(k)) THEN
Found = .TRUE.
EXIT
END IF
END DO
IF (.NOT. Found) THEN
CALL Fatal(Caller, &
'Fluid/NS/Pressure Solver Index is not an entry in the Block Solvers array')
ELSE
j = k
END IF
END IF
IF (j > 2) CALL Fatal(Caller, &
'Use the first two entries of Block Solvers to define FSI coupling')
IF( j == 0 ) THEN
IF( i > 1 .AND. TotMatrix % NoVar == 2 ) j = 3 - i
END IF
IF( i == 0 ) THEN
IF( j > 1 .AND. TotMatrix % NoVar == 2 ) i = 3 - j
END IF
IF(i<=0 .OR. j<=0) THEN
IF( i > 0 ) CALL Warn(Caller,'Structure solver given but not fluid!')
IF( j > 0 ) CALL Warn(Caller,'Fluid solver given but not structure!')
RETURN
END IF
A_fs => TotMatrix % Submatrix(j,i) % Mat
A_sf => TotMatrix % Submatrix(i,j) % Mat
IF(.NOT. ASSOCIATED( A_fs ) ) THEN
CALL Fatal(Caller,'Fluid-structure coupling matrix not allocated!')
END IF
IF(.NOT. ASSOCIATED( A_sf ) ) THEN
CALL Fatal(Caller,'Structure-fluid coupling matrix not allocated!')
END IF
SVar => TotMatrix % Subvector(i) % Var
FVar => TotMatrix % Subvector(j) % Var
A_s => TotMatrix % Submatrix(i,i) % Mat
A_f => TotMatrix % Submatrix(j,j) % Mat
IF(.NOT. ASSOCIATED( FVar ) ) THEN
CALL Fatal(Caller,'Fluid variable not present!')
END IF
IF(.NOT. ASSOCIATED( FVar ) ) THEN
CALL Fatal(Caller,'Structure variable not present!')
END IF
IF(.NOT. (IsNs .OR. IsPres ) ) THEN
IsPres = ( FVar % Dofs <= 2 )
IsNs = .NOT. IsPres
END IF
CALL FsiCouplingAssembly( Solver, FVar, SVar, A_f, A_s, A_fs, A_sf, &
IsPlate, IsShell, IsNS )
IF( ParEnv % PEs > 1 ) THEN
TotMatrix % Submatrix(i,j) % ParallelSquareMatrix = .FALSE.
TotMatrix % Submatrix(j,i) % ParallelSquareMatrix = .FALSE.
TotMatrix % Submatrix(i,j) % ParallelIsolatedMatrix = &
.NOT. CheckParallelCoupling(A_s, A_f, A_sf )
TotMatrix % Submatrix(j,i) % ParallelIsolatedMatrix = &
.NOT. CheckParallelCoupling(A_f, A_s, A_fs )
END IF
END SUBROUTINE FsiCouplingBlocks
SUBROUTINE StructureCouplingBlocks( Solver )
TYPE(Solver_t) :: Solver
INTEGER :: i,j,k,ind1,ind2,Novar,Nsol
INTEGER, POINTER :: ConstituentSolvers(:)
LOGICAL :: Found
TYPE(ValueList_t), POINTER :: Params, ShellParams
TYPE(Matrix_t), POINTER :: A_fs, A_sf, A_s, A_f
TYPE(Variable_t), POINTER :: FVar, SVar
LOGICAL :: IsPlate, IsShell, IsBeam, IsSolid, GotBlockSolvers
LOGICAL :: DrillingDOFs
TYPE(Solver_t), POINTER :: PSol
CHARACTER(*), PARAMETER :: Caller = 'StructureCouplingBlocks'
Params => Solver % Values
ConstituentSolvers => ListGetIntegerArray(Params, 'Block Solvers', GotBlockSolvers)
IF(.NOT. GotBlockSolvers ) THEN
CALL Fatal(Caller,'We need "Block Solvers" defined!')
END IF
i = 1
SVar => TotMatrix % Subvector(i) % Var
IF(.NOT. ASSOCIATED( SVar ) ) THEN
CALL Fatal(Caller,'Master structure variable not present!')
END IF
A_s => TotMatrix % Submatrix(i,i) % Mat
Nsol = SIZE( ConstituentSolvers )
DO j = 1, Nsol
IF(j==1) CYCLE
IF (j > size(ConstituentSolvers)) CALL Fatal(Caller, &
'Solid/Plate/Shell/Beam Solver Index larger than Block Solvers array')
k = ConstituentSolvers(j)
PSol => CurrentModel % Solvers(k)
IsSolid = ListGetLogical( Psol % Values,'Solid Solver',IsSolid)
IsPlate = ListGetLogical( Psol % Values,'Plate Solver',IsPlate)
IsShell = ListGetLogical( Psol % Values,'Shell Solver',IsShell)
IsBeam = ListGetLogical( Psol % Values,'Beam Solver',IsBeam)
ind1 = ConstituentSolvers(i)
ind2 = ConstituentSolvers(j)
CALL Info(Caller,'Generating coupling between solvers '&
//I2S(ind1)//' and '//I2S(ind2))
A_fs => TotMatrix % Submatrix(j,i) % Mat
A_sf => TotMatrix % Submatrix(i,j) % Mat
FVar => TotMatrix % Subvector(j) % Var
IF(.NOT. ASSOCIATED( FVar ) ) THEN
CALL Fatal(Caller,'Slave structure variable not present!')
END IF
A_f => TotMatrix % Submatrix(j,j) % Mat
IF (IsShell) THEN
ShellParams => Fvar % Solver % Values
DrillingDOFs = GetLogical(ShellParams, 'Drilling DOFs', Found)
ELSE
DrillingDOFs = .FALSE.
END IF
CALL StructureCouplingAssembly( Solver, FVar, SVar, A_f, A_s, A_fs, A_sf, &
IsSolid, IsPlate, IsShell, IsBeam, DrillingDOFs)
IF( ParEnv % PEs > 1 ) THEN
TotMatrix % Submatrix(i,j) % ParallelSquareMatrix = .FALSE.
TotMatrix % Submatrix(j,i) % ParallelSquareMatrix = .FALSE.
TotMatrix % Submatrix(i,j) % ParallelIsolatedMatrix = &
.NOT. CheckParallelCoupling(A_s, A_f, A_sf )
TotMatrix % Submatrix(j,i) % ParallelIsolatedMatrix = &
.NOT. CheckParallelCoupling(A_f, A_s, A_fs )
END IF
END DO
END SUBROUTINE StructureCouplingBlocks
FUNCTION CompNorm( x, n, npar, A) RESULT ( nrm )
REAL(KIND=dp) :: x(:)
INTEGER :: n
INTEGER, OPTIONAL :: npar
TYPE(Matrix_t), POINTER, OPTIONAL :: A
REAL(KIND=dp) :: nrm
INTEGER :: i,m
REAL(KIND=dp) :: s,stot,ntot
IF( ParEnv % PEs > 1 .AND. PRESENT( A ) ) THEN
m = 0
s = 0.0_dp
DO i=1,A % NumberOfRows
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(i) % Neighbours(1)) CYCLE
m = m+1
s = s + x(i)**2
END DO
ELSE
IF( ParEnv % PEs > 1 .AND. PRESENT( npar ) ) THEN
m = npar
ELSE
m = n
END IF
s = SUM(x(1:m)**2)
END IF
stot = ParallelReduction(s)
ntot = ParallelReduction(m)
nrm = SQRT( stot / ntot )
END FUNCTION CompNorm
SUBROUTINE BlockUpdateRhs( BlockMatrix, ThisRow )
TYPE(BlockMatrix_t), TARGET :: BlockMatrix
INTEGER, OPTIONAL :: ThisRow
TYPE(Matrix_t), POINTER :: A
INTEGER :: n, NoRow,NoCol, NoVar
REAL(KIND=dp), POINTER :: x(:),rtmp(:),rhs(:)
REAL(KIND=dp) :: bnorm
TYPE(Variable_t), POINTER :: Var
CALL Info('BlockUpdateRhs','Computing block r.h.s',Level=8)
NoVar = BlockMatrix % NoVar
ALLOCATE( rtmp(BlockMatrix % MaxSize) )
DO NoRow = 1,NoVar
IF( PRESENT( ThisRow ) ) THEN
IF( NoRow /= ThisRow ) CYCLE
END IF
Var => BlockMatrix % SubVector(NoRow) % Var
x => Var % Values
n = SIZE( x )
IF(.NOT. ALLOCATED( BlockMatrix % SubVector(NoRow) % rhs )) THEN
ALLOCATE( BlockMatrix % SubVector(NoRow) % rhs(n) )
CALL Info('BlockUpdateRhs','Creating rhs for component: '//I2S(NoRow),Level=12)
END IF
rhs => BlockMatrix % SubVector(NoRow) % rhs
rhs = 0.0_dp
A => BlockMatrix % SubMatrix( NoRow, NoRow ) % Mat
IF( ASSOCIATED( A ) ) THEN
IF( ASSOCIATED( A % rhs ) ) rhs = A % rhs
END IF
DO NoCol = 1,NoVar
IF( NoCol == NoRow ) CYCLE
Var => BlockMatrix % SubVector(NoCol) % Var
x => Var % Values
A => BlockMatrix % SubMatrix( NoRow, NoCol ) % Mat
IF( A % NumberOfRows == 0 ) CYCLE
CALL CRS_MatrixVectorMultiply( A, x, rtmp)
rhs(1:n) = rhs(1:n) - rtmp(1:n)
END DO
bnorm = CompNorm(rhs,n)
BlockMatrix % SubVector(NoRow) % bnorm = bnorm
NoCol = NoRow
Var => BlockMatrix % SubVector(NoCol) % Var
x => Var % Values
A => BlockMatrix % SubMatrix( NoRow, NoCol ) % Mat
IF( A % NumberOfRows > 0 ) THEN
CALL CRS_MatrixVectorMultiply( A, x, rtmp)
rhs(1:n) = rhs(1:n) - rtmp(1:n)
END IF
END DO
DEALLOCATE( rtmp )
END SUBROUTINE BlockUpdateRhs
SUBROUTINE BlockMatrixVectorProd( u,v,ipar )
REAL(KIND=dp), INTENT(in) :: u(*)
REAL(KIND=dp), INTENT(out) :: v(*)
INTEGER, INTENT(in) :: ipar(*)
INTEGER :: n,i,j,k,NoVar,i1,i2,j1,j2,ll,kk
REAL(KIND=dp), ALLOCATABLE :: s(:)
INTEGER :: maxsize,ndofs
INTEGER, POINTER :: Offset(:)
REAL(KIND=dp) :: nrm
TYPE(Matrix_t), POINTER :: A
REAL(KIND=dp), POINTER :: b(:)
LOGICAL :: Isolated
LOGICAL :: DoSum , DoAMGXMV, Found
DoAMGXMV = ListGetLogical( SolverRef % Values, 'Block AMGX M-V', Found)
CALL Info('BlockMatrixVectorProd','Starting block matrix multiplication',Level=20)
NoVar = TotMatrix % NoVar
MaxSize = TotMatrix % MaxSize
ALLOCATE( s(MaxSize) )
IF( isParallel ) THEN
Offset => TotMatrix % ParOffset
ELSE
Offset => TotMatrix % Offset
END IF
v(1:offset(NoVar+1)) = 0
DO i=1,NoVar
DO j=1,NoVar
s = 0._dp
j1 = offset(j)+1
j2 = offset(j+1)
IF ( ListGetLogical(SolverRef % Values, 'Dummy block'//I2S(i), Found) ) CYCLE
A => TotMatrix % SubMatrix(i,j) % Mat
IF ( .NOT. ASSOCIATED(A) ) CYCLE
IF ( A % NumberOfRows == 0) CYCLE
Isolated = TotMatrix % SubMatrix(i,j) % ParallelIsolatedMatrix
CALL Info('BlockMatrixVectorProd','Multiplying with submatrix ('&
//I2S(i)//','//I2S(j)//')',Level=15)
IF (isParallel) THEN
IF( ASSOCIATED( A % ParMatrix ) ) THEN
CALL ParallelMatrixVector( A, u(j1:j2), s )
ELSE IF( Isolated ) THEN
CALL CRS_MatrixVectorMultiply( A, u(j1:j2), s )
ELSE
CALL Fatal('BlockMatrixVectorProd','Cannot make the matric-vector product in parallel!')
END IF
ELSE
IF ( DoAMGXMV ) THEN
CALL AMGXMatrixVectorMultiply(A, u(j1:j2), s, SolverRef )
ELSE
CALL CRS_MatrixVectorMultiply( A, u(j1:j2), s )
END IF
END IF
IF( InfoActive( 25 ) ) THEN
PRINT *,'MatVecProdNorm u:',i,j,&
SQRT(SUM(u(j1:j2)**2)),SUM( u(j1:j2) ), MINVAL( u(j1:j2) ), MAXVAL( u(j1:j2) )
PRINT *,'MatVecProdNorm s:',i,j,&
SQRT(SUM(s**2)), SUM( s ), MINVAL( s ), MAXVAL( s )
END IF
v(offset(i)+1:offset(i+1)) = v(offset(i)+1:offset(i+1)) + s(1:offset(i+1)-offset(i))
END DO
IF( InfoActive( 25 ) ) THEN
i1 = offset(i)+1
i2 = offset(i+1)
b => TotMatrix % Submatrix(i,i) % Mat % Rhs
IF( ASSOCIATED( b ) ) THEN
PRINT *,'MatVecProdNorm b:',i,&
SQRT(SUM(b**2)),SUM( b ), MINVAL( b ), MAXVAL( b )
END IF
PRINT *,'MatVecProdNorm v:',i,&
SQRT(SUM(v(i1:i2)**2)), SUM( v(i1:i2) ), MINVAL( v(i1:i2) ), MAXVAL( v(i1:i2) )
END IF
END DO
IF( InfoActive( 25 ) ) THEN
n = offset(NoVar+1)
nrm = CompNorm(v(1:n),n)
WRITE( Message,'(A,ES12.5)') 'Mv result norm: ',nrm
CALL Info('BlockMatrixVectorProd',Message )
END IF
CALL Info('BlockMatrixVectorProd','Finished block matrix multiplication',Level=20)
END SUBROUTINE BlockMatrixVectorProd
SUBROUTINE ParallelShrinkPerm()
TYPE(Matrix_t), POINTER :: A, Adiag
INTEGER, POINTER :: BlockPerm(:), ParBlockPerm(:), ParPerm(:)
INTEGER :: i,j,k,l,n,m
INTEGER, ALLOCATABLE :: ShrinkPerm(:),RenumPerm(:)
LOGICAL :: Halt
n = TotMatrix % TotSize
Halt = .FALSE.
A => TotMatrix % ParentMatrix
IF(.NOt. ASSOCIATED(A) ) A => SolverMatrix
IF( ASSOCIATED( A ) ) THEN
CALL Info('ParallelShrinkPerm','Using the monolithic matrix to deduce permutation',Level=6)
ELSE
CALL Info('ParallelShrinkPerm','Using the block matrix to deduce permutation',Level=6)
END IF
ALLOCATE(ShrinkPerm(n))
DO j=1,TotMatrix % Novar
Adiag => TotMatrix % Submatrix(j,j) % Mat
IF(.NOT. ASSOCIATED( Adiag % ParallelInfo ) ) CYCLE
k = 0
l = 0
m = 0
ShrinkPerm(1:Adiag % NumberOfRows) = 0
DO i=1,Adiag % NumberOfRows
k = k + 1
IF (Parenv % MyPE /= Adiag % ParallelInfo % NeighbourList(i) % Neighbours(1)) THEN
m = m+1
CYCLE
END IF
l = l+1
ShrinkPerm(k) = l
END DO
IF(ASSOCIATED(TotMatrix % Submatrix(j,j) % ParPerm )) THEN
k = SIZE(TotMatrix % SubMatrix(j,j) % ParPerm)
IF(k /= l) THEN
CALL Warn('ParallelShrinkPerm','Different size for ParPerm '&
//I2S(l)//': '//I2S(k)//' vs. '//I2S(l))
PRINT *,'ParBlockPerm skipped1',ParEnv % MyPe, m, j
DEALLOCATE(TotMatrix % SubMatrix(j,j) % ParPerm )
Halt = .TRUE.
END IF
END IF
IF(.NOT. ASSOCIATED(TotMatrix % Submatrix(j,j) % ParPerm ) ) THEN
ALLOCATE( TotMatrix % Submatrix(j,j) % ParPerm(l) )
END IF
ParPerm => TotMatrix % Submatrix(j,j) % ParPerm
ParPerm = 0
DO i=1,Adiag % NumberOfRows
k = ShrinkPerm(i)
IF(k==0) CYCLE
ParPerm(k) = i
END DO
END DO
m = 0
ShrinkPerm = 0
IF( ASSOCIATED( A ) ) THEN
l = 0
DO i=1,A % NumberOfRows
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(i) % Neighbours(1)) THEN
m = m+1
CYCLE
END IF
l = l+1
ShrinkPerm(i) = l
END DO
END IF
IF(.NOT. ASSOCIATED(TotMatrix % ParPerm) ) THEN
ALLOCATE( TotMatrix % ParPerm(l) )
END IF
ParPerm => TotMatrix % ParPerm
ParPerm = 0
DO i=1,n
j = ShrinkPerm(i)
IF(j==0) CYCLE
ParPerm(j) = i
END DO
IF(.NOT. ASSOCIATED(TotMatrix % ParOffset) ) THEN
ALLOCATE( TotMatrix % ParOffset(TotMatrix % NoVar+1))
END IF
TotMatrix % ParOffset = 0
k = 0
l = 0
DO j=1,TotMatrix % Novar
m = 0
A => TotMatrix % Submatrix(j,j) % Mat
DO i=1,A % NumberOfRows
k = k + 1
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(i) % Neighbours(1)) THEN
m = m+1
CYCLE
END IF
l = l+1
END DO
TotMatrix % ParOffset(j+1) = l
END DO
CALL Info('ParallelShrinkPerm','Number of parallel dofs in this partition: '// &
I2S(l)//' / '//I2S(n), Level=6)
BlockPerm => TotMatrix % BlockPerm
IF(.NOT. ASSOCIATED(BlockPerm) ) THEN
IF(Halt) STOP
RETURN
END IF
ALLOCATE(RenumPerm(n))
RenumPerm = 1
DO i=1,n
j = BlockPerm(i)
IF( ShrinkPerm(j) == 0 ) RenumPerm(i) = 0
END DO
l = 0
DO i=1,n
IF(RenumPerm(i) > 0) THEN
l=l+1
RenumPerm(i) = l
END IF
END DO
IF(ASSOCIATED(TotMatrix % ParBlockPerm)) THEN
k = SIZE(TotMatrix % ParBlockPerm)
IF(k /= l) THEN
CALL Warn('ParallelShrinkPerm','Different size for ParBlockPerm: '//I2S(k)//' vs. '//I2S(l))
PRINT *,'ParBlockPerm skipped2',ParEnv % MyPe, m
DEALLOCATE(TotMatrix % ParBlockPerm)
Halt = .TRUE.
END IF
END IF
IF(.NOT. ASSOCIATED(TotMatrix % ParBlockPerm) ) THEN
ALLOCATE(TotMatrix % ParBlockPerm(l))
END IF
ParBlockPerm => TotMatrix % ParBlockPerm
ParBlockPerm = 0
DO i=1,n
IF(RenumPerm(i)==0) CYCLE
ParBlockPerm(RenumPerm(i)) = ShrinkPerm(BlockPerm(i))
END DO
IF(Halt) STOP
END SUBROUTINE ParallelShrinkPerm
SUBROUTINE BlockMatrixVectorProdMono( u,v,ipar )
REAL(KIND=dp), INTENT(in) :: u(*)
REAL(KIND=dp), INTENT(out) :: v(*)
INTEGER, INTENT(in) :: ipar(*)
INTEGER :: n,m,i,j,k,NoVar,i1,i2,j1,j2
REAL(KIND=dp), ALLOCATABLE :: s(:)
INTEGER :: maxsize,ndofs
INTEGER, POINTER :: Offset(:)
REAL(KIND=dp) :: nrm
TYPE(Matrix_t), POINTER :: A
REAL(KIND=dp), POINTER :: b(:)
LOGICAL :: DoSum, GotBlockStruct
REAL(KIND=dp), POINTER :: utmp(:),vtmp(:)
INTEGER, POINTER :: BlockPerm(:)
CALL Info('BlockMatrixVectorProdMono','Starting monolithic matrix multiplication',Level=20)
IF(.NOT.ASSOCIATED(SolverMatrix)) THEN
CALL Fatal('BlockMatrixVectorProdMono','No matrix to apply.')
END IF
NoVar = TotMatrix % NoVar
MaxSize = TotMatrix % MaxSize
GotBlockStruct = TotMatrix % GotBlockStruct
n = ipar(3)
IF(isParallel) THEN
BlockPerm => TotMatrix % ParBlockPerm
IF(.NOT. ASSOCIATED( BlockPerm ) ) THEN
BlockPerm => TotMatrix % ParPerm
END IF
IF(.NOT. ASSOCIATED(BlockPerm) ) THEN
CALL Fatal('BlockMatrixVectorProdMono','How come there is no permutation in parallel?')
END IF
Offset => TotMatrix % ParOffset
ELSE
BlockPerm => TotMatrix % BlockPerm
Offset => TotMatrix % Offset
END IF
IF( ASSOCIATED( BlockPerm ) ) THEN
IF(InfoActive(20)) THEN
i = MAXVAL( BlockPerm )
j = MINVAL( BlockPerm )
IF( j <= 0 .OR. i > n ) THEN
CALL Fatal('BlockMatrixVectorProdMono','Invalid sizes: '&
//I2S(i)//' '//I2S(j)//' '//I2S(n)//' '//I2S(SIZE(BlockPerm)))
END IF
CALL Info('BlockMatrixVectorProdMono','BlockPermSizes: '//I2S(i)//' '//I2S(j)//' '//I2S(n))
END IF
END IF
IF(isParallel) THEN
m = SolverMatrix % NumberOfRows
ALLOCATE(utmp(m),vtmp(m))
utmp(1:m) = 0.0_dp
utmp(BlockPerm(1:n)) = u(1:n)
CALL ParallelMatrixVector(SolverMatrix, utmp(1:m), vtmp(1:m) )
v(1:n) = vtmp(BlockPerm(1:n))
DEALLOCATE(utmp,vtmp)
ELSE
IF( ASSOCIATED( BlockPerm ) ) THEN
ALLOCATE(utmp(n))
utmp(BlockPerm(1:n)) = u(1:n)
CALL CRS_MatrixVectorMultiply( SolverMatrix, utmp, v )
v(1:n) = v(BlockPerm(1:n))
ELSE
CALL CRS_MatrixVectorMultiply( SolverMatrix, u(1:n), v(1:n) )
END IF
END IF
IF( InfoActive( 25 ) ) THEN
nrm = CompNorm(v(1:n),n)
WRITE( Message,'(A,ES12.5)') 'Mv result norm: ',nrm
CALL Info('BlockMatrixVectorProdMono',Message )
END IF
CALL Info('BlockMatrixVectorProdMono','Finished block matrix multiplication',Level=20)
END SUBROUTINE BlockMatrixVectorProdMono
SUBROUTINE CreateBlockMatrixScaling( )
IMPLICIT NONE
INTEGER :: i,j,k,l,n,m,NoVar,istat
REAL(KIND=dp) :: nrm, tmp, blocknrm
TYPE(Matrix_t), POINTER :: A
REAL(KIND=dp), POINTER :: b(:), Diag(:), Values(:)
LOGICAL :: ComplexMatrix, GotIt, DiagOnly, PrecScale
INTEGER, POINTER :: Rows(:), Cols(:)
LOGICAL :: Found
TYPE(ValueList_t), POINTER :: Params
TYPE(Variable_t), POINTER :: SolverVar
CHARACTER(*), PARAMETER :: Caller = 'CreateBlockMatrixScaling'
CALL Info(Caller,'Starting block matrix row equilibration',Level=20)
NoVar = TotMatrix % NoVar
Params => CurrentModel % Solver % Values
DiagOnly = ListGetLogical( Params,'Block Scaling Diagonal',Found )
IF( DiagOnly ) THEN
CALL Info(Caller,'Considering only diagonal matrices in scaling',Level=20)
END IF
PrecScale = ListGetLogical( Params,'Block Scaling PrecMatrix',Found )
m = 0
DO k=1,NoVar
A => TotMatrix % SubMatrix(k,k) % Mat
n = A % NumberOfRows
IF(.NOT. ASSOCIATED(TotMatrix % Subvector )) THEN
CALL Fatal(Caller,'Subvector not associated!')
END IF
IF( ASSOCIATED(TotMatrix % Subvector(k) % Var) ) THEN
n = MAX(n, SIZE(TotMatrix % SubVector(k) % Var % Values) )
END IF
IF( .NOT. ALLOCATED( Totmatrix % SubVector(k) % DiagScaling ) ) THEN
m = m + 1
ALLOCATE( TotMatrix % SubVector(k) % DiagScaling(n), STAT=istat )
IF( istat /= 0 ) THEN
CALL Fatal(Caller,'Cannot allocate scaling vectors '//I2S(k)//' of size: '//I2S(n))
END IF
CALL Info(Caller,'Allocated scaling vector of size '//I2S(n)//' to block '//I2S(k),Level=20)
END IF
END DO
IF( m > 0 ) THEN
CALL Info(Caller,'Allocated '//I2S(m)//' scaling vectors for rhs!',Level=8)
END IF
GotIt = .FALSE.
blocknrm = 0.0_dp
ComplexMatrix = .FALSE.
DO k=1,NoVar
A => TotMatrix % SubMatrix(k,k) % Mat
IF( ASSOCIATED( A ) ) THEN
IF( A % NumberOfRows > 0 .AND. .NOT. GotIt) THEN
GotIt = .TRUE.
ComplexMatrix = A % COMPLEX
IF( ComplexMatrix ) THEN
m = 2
CALL Info(Caller,'Assuming complex block matrix in scaling!',Level=20)
ELSE
m = 1
CALL Info(Caller,'Assuming real valued block matrix in scaling!',Level=20)
END IF
END IF
END IF
IF(.NOT. GotIt) CALL Warn(Caller,'Improve complex matrix detection!')
Diag => TotMatrix % SubVector(k) % DiagScaling
Diag = 0.0_dp
DO l=1,NoVar
IF( DiagOnly ) THEN
IF( k /= l ) CYCLE
END IF
Found = .FALSE.
IF(k==l .AND. PrecScale ) THEN
A => TotMatrix % Submatrix(k,k) % PrecMat
Found = ( A % NumberOfRows > 0 )
IF(Found) THEN
CALL Info(Caller,'Using PrecMat to define the scaling of block row '//I2S(k),Level=20)
END IF
END IF
IF(.NOT.Found) THEN
A => TotMatrix % Submatrix(k,l) % Mat
END IF
IF(.NOT. ASSOCIATED( A ) ) CYCLE
n = A % NumberOfRows
IF( n == 0 ) CYCLE
Rows => A % Rows
Cols => A % Cols
Values => A % Values
DO i=1,n,m
tmp = 0.0_dp
IF( ComplexMatrix ) THEN
DO j=Rows(i),Rows(i+1)-1,2
tmp = tmp + SQRT( Values(j)**2 + Values(j+1)**2 )
END DO
ELSE
DO j=Rows(i),Rows(i+1)-1
tmp = tmp + ABS(Values(j))
END DO
END IF
Diag(i) = Diag(i) + tmp
END DO
END DO
IF (ParEnv % PEs > 1) THEN
A => TotMatrix % SubMatrix(k,k) % Mat
IF( A % NumberOfRows > 0 ) THEN
CALL ParallelSumVector(A, Diag)
END IF
END IF
n = SIZE(Diag)
nrm = MAXVAL(Diag(1:n))
IF( ParEnv % PEs > 1 ) THEN
nrm = ParallelReduction(nrm,2)
END IF
blocknrm = MAX(blocknrm,nrm)
DO i=1,n,m
IF (Diag(i) > EPSILON( nrm ) ) THEN
Diag(i) = 1.0_dp / Diag(i)
ELSE
Diag(i) = 1.0_dp
END IF
END DO
IF( ComplexMatrix ) Diag(2::2) = Diag(1::2)
WRITE( Message,'(A,ES12.5)') 'Unscaled matrix norm for block '//I2S(k)//': ', nrm
CALL Info(Caller, Message, Level=10 )
END DO
WRITE( Message,'(A,ES12.5)') 'Unscaled matrix norm: ', blocknrm
CALL Info(Caller, Message, Level=7 )
END SUBROUTINE CreateBlockMatrixScaling
SUBROUTINE BlockMatrixInfo()
IMPLICIT NONE
INTEGER :: i,j,k,l,n,m,NoVar
INTEGER(KIND=8) :: ll
REAL(KIND=dp) :: nrm, tmp, blocknrm
TYPE(Matrix_t), POINTER :: A
REAL(KIND=dp), POINTER :: b(:), Diag(:), Values(:)
LOGICAL :: ComplexMatrix, GotIt, DiagOnly
INTEGER, POINTER :: Rows(:), Cols(:)
LOGICAL :: Found
CHARACTER(:), ALLOCATABLE :: pre
CALL Info('BlockMatrixInfo','')
CALL Info('BlockMatrixInfo','Showing some ranges of block matrix stuff',Level=10)
NoVar = TotMatrix % NoVar
m = 0
pre = 'BlockInfo'//I2S(ParEnv % MyPe)//': '
PRINT *,pre,NoVar, ParEnv % Mype
DO k=1,NoVar
DO l=1,NoVar
A => TotMatrix % SubMatrix(k,l) % Mat
IF( .NOT. ASSOCIATED( A ) ) CYCLE
IF( A % NumberOfRows == 0 ) CYCLE
n = 0
m = 0
IF( ASSOCIATED( TotMatrix % Offset ) ) THEN
n = TotMatrix % offset(k+1) - TotMatrix % offset(k)
END IF
IF(isParallel ) THEN
IF( ASSOCIATED( TotMatrix % ParOffset ) ) THEN
m = TotMatrix % ParOffset(k+1) -TotMatrix % ParOffset(k)
END IF
END IF
PRINT *,TRIM(pre)//' size',k,l,A % NumberOfRows, n, m, A % COMPLEX
Rows => A % Rows
Cols => A % Cols
Values => A % Values
PRINT *,pre,'A'//I2S(10*k+l)//' range',SUM( Values ), SUM( ABS( Values ) ), &
MINVAL( Values ), MAXVAL( Values )
A => TotMatrix % SubMatrix(k,k) % PrecMat
IF( .NOT. ASSOCIATED( A ) ) CYCLE
IF( A % NumberOfRows == 0 ) CYCLE
Values => A % Values
PRINT *,TRIM(pre),'B'//I2S(11*k)//' range',SUM( Values ), SUM( ABS( Values ) ), &
MINVAL( Values ), MAXVAL( Values )
END DO
END DO
DO k=1,NoVar
PRINT *,'BlockInfo rhs:',k
A => TotMatrix % SubMatrix(k,k) % Mat
IF( ASSOCIATED( A ) ) THEN
b => A % rhs
IF(ASSOCIATED(b)) THEN
PRINT *,pre, 'A rhs range',k,SUM( b ), SUM( ABS( b ) ), &
MINVAL( b ), MAXVAL( b )
END IF
END IF
b => TotMatrix % SubVector(k) % rhs
IF(ASSOCIATED(b)) THEN
PRINT *,pre,'b range',k,SUM( b ), SUM( ABS( b ) ), &
MINVAL( b ), MAXVAL( b )
END IF
END DO
IF(isParallel) THEN
DO k=1,NoVar
PRINT *,'BlockInfo ParallelInfo'//I2S(k)
A => TotMatrix % SubMatrix(k,k) % Mat
IF(.NOT. ASSOCIATED(A % ParallelInfo) ) THEN
PRINT *,pre,'No ParallelInfo associated', k
CYCLE
END IF
n = A % NumberOfRows
j = 0
ll = 0
IF( ASSOCIATED(A % ParallelInfo % NeighbourList ) ) THEN
i = SIZE( A % ParallelInfo % NeighbourList)
DO l=1,i
j = j+SIZE(A % ParallelInfo % NeighbourList(l) % Neighbours)
ll = ll+SUM(A % ParallelInfo % NeighbourList(l) % Neighbours)
END DO
PRINT *,pre,'BlockInfo NeighbourList:',n,i,j,ll
END IF
IF( ASSOCIATED(A % ParallelInfo % GInterface) ) THEN
i = SIZE( A % ParallelInfo % Ginterface)
j = COUNT(A % ParallelInfo % GInterface)
PRINT *,pre,'BlockInfo GInterface', n,i,j
END IF
IF( ASSOCIATED(A % ParallelInfo % GlobalDOFs) ) THEN
i = SIZE( A % ParallelInfo % GlobalDOFs)
ll = SUM(A % ParallelInfo % GlobalDOFs)
PRINT *,pre,'BlockInfo GlobalDofs', n,i,ll
END IF
END DO
END IF
END SUBROUTINE BlockMatrixInfo
SUBROUTINE DoBlockMatrixScaling( reverse, blockrow, blockcol, bext, SkipMatrixScale )
IMPLICIT NONE
LOGICAL, OPTIONAL :: reverse
INTEGER, OPTIONAL :: blockrow, blockcol
REAL(KIND=dp), POINTER, OPTIONAL :: bext(:)
LOGICAL, OPTIONAL :: SkipMatrixScale
INTEGER :: i,j,k,l,n,m,NoVar
REAL(KIND=dp) :: nrm, tmp
TYPE(Matrix_t), POINTER :: A
REAL(KIND=dp), POINTER :: b(:), Diag(:), Values(:)
INTEGER, POINTER :: Rows(:), Cols(:)
LOGICAL :: backscale
CHARACTER(*), PARAMETER :: Caller = 'DoBlockMatrixScaling'
IF( PRESENT( Reverse ) ) THEN
BackScale = Reverse
ELSE
BackScale = .FALSE.
END IF
IF( BackScale ) THEN
Message = 'Performing block matrix reverse row equilibration'
ELSE
Message = 'Performing block matrix row equilibration'
END IF
IF(PRESENT(blockrow)) THEN
Message = TRIM(Message)//' for block '//I2S(blockrow)
END IF
CALL Info(Caller,Message,Level=12)
NoVar = TotMatrix % NoVar
DO k=1,NoVar
IF( PRESENT( blockrow ) ) THEN
IF( blockrow /= k ) CYCLE
END IF
Diag => TotMatrix % SubVector(k) % DiagScaling
IF( .NOT. ASSOCIATED( Diag ) ) THEN
CALL Fatal(Caller,'Diag for scaling not associated!')
END IF
IF( BackScale ) Diag = 1.0_dp / Diag
DO l=1,NoVar
IF( PRESENT( blockcol ) ) THEN
IF( blockcol /= l ) CYCLE
END IF
IF( PRESENT( SkipMatrixScale ) ) THEN
IF( SkipMatrixScale ) THEN
CALL Info(Caller,'Skipping preconditioning matrix for block '//I2S(l),Level=20)
CYCLE
END IF
END IF
A => TotMatrix % SubMatrix(k,l) % Mat
n = A % NumberOfRows
IF( n == 0 ) CYCLE
Rows => A % Rows
Cols => A % Cols
Values => A % Values
DO i=1,n
DO j=Rows(i),Rows(i+1)-1
Values(j) = Values(j) * Diag(i)
END DO
END DO
#if 0
A => TotMatrix % SubMatrix(k,l) % PrecMat
IF( A % NumberOfRows == 0 ) CYCLE
DO i=1,n
DO j=A % Rows(i),A % Rows(i+1)-1
A % Values(j) = A % Values(j) * Diag(i)
END DO
END DO
#endif
END DO
IF( PRESENT( bext ) ) THEN
b => bext
ELSE
b => TotMatrix % Submatrix(k,k) % Mat % Rhs
END IF
IF( ASSOCIATED( b ) ) THEN
n = SIZE(Diag)
b(1:n) = Diag(1:n) * b(1:n)
END IF
IF( BackScale ) Diag = 1.0_dp / Diag
END DO
IF( BackScale ) THEN
CALL Info(Caller,'Finished block matrix reverse row equilibration',Level=25)
ELSE
CALL Info(Caller,'Finished block matrix row equilibration',Level=25)
END IF
END SUBROUTINE DoBlockMatrixScaling
SUBROUTINE DestroyBlockMatrixScaling()
INTEGER :: k,NoVar
CALL Info('DestroyBlockMatrixScaling','Deallocating the vectors for block system scaling',Level=10)
NoVar = TotMatrix % NoVar
DO k=1,NoVar
IF( ALLOCATED( TotMatrix % SubVector(k) % DiagScaling ) ) THEN
DEALLOCATE( TotMatrix % SubVector(k) % DiagScaling )
END IF
END DO
END SUBROUTINE DestroyBlockMatrixScaling
SUBROUTINE BlockMatrixPrec( u,v,ipar )
IMPLICIT NONE
REAL(KIND=dp), TARGET, INTENT(out) :: u(*)
REAL(KIND=dp), TARGET, INTENT(in) :: v(*)
INTEGER :: ipar(*)
REAL(KIND=dp), POINTER :: rtmp(:),vtmp(:),xtmp(:),btmp(:),diagtmp(:),b(:),x(:), a_rhs_save(:)
REAL(KIND=dp), POINTER CONTIG :: rhs_save(:)
INTEGER :: i,j,k,l,n,m,NoVar,nc,kk,ll,istat
TYPE(Solver_t), POINTER :: Solver, Solver_save, ASolver
INTEGER, POINTER :: Offset(:), BlockPerm(:),ParPerm(:)
TYPE(ValueList_t), POINTER :: Params
INTEGER, POINTER :: BlockOrder(:)
TYPE(Matrix_t), POINTER :: A, Aij, mat_save
TYPE(Variable_t), POINTER :: Var, Var_save
REAL(KIND=dp) :: nrm
LOGICAL :: GotOrder, BlockGS, Found, NS, ScaleSystem, DoSum, &
IsComplex, BlockScaling, DoDiagScaling, DoPrecScaling, UsePrecMat, &
Isolated, NoNestedScaling, DoAMGXmv, CalcLoads, BlockSch
CHARACTER(:), ALLOCATABLE :: str
INTEGER(KIND=AddrInt) :: AddrFunc
EXTERNAL :: AddrFunc
CALL Info('BlockMatrixPrec','Starting block matrix preconditioning',Level=8)
DoAMGXMV = ListGetLogical( SolverRef % Values, 'Block AMGX M-V', Found)
n = ipar(3)
IF( InfoActive(25) ) THEN
nrm = CompNorm(v(1:n),n)
WRITE( Message,'(A,ES12.5)') 'V start norm: ',nrm
CALL Info('BlockMatrixPrec',Message,Level=10)
END IF
Solver => CurrentModel % Solver
Params => Solver % Values
NoVar = TotMatrix % NoVar
Solver => TotMatrix % Solver
TotMatrix % NoIters = TotMatrix % NoIters + 1
BlockOrder => ListGetIntegerArray( Params,'Block Order',GotOrder)
IF(GotOrder) THEN
IF(SIZE(BlockOrder) /= NoVar) THEN
CALL Fatal('BlockMatrixPrec','Block Order size should be '//I2S(NoVar))
END IF
END IF
BlockGS = ListGetLogical( Params,'Block Gauss-Seidel',Found)
BlockSch = ListGetLogical( Params,'Block Schur',Found)
IF( isParallel ) THEN
offset => TotMatrix % ParOffset
ELSE
offset => TotMatrix % Offset
END IF
IF( n /= Offset(NoVar+1) ) THEN
CALL Warn('BlockMatrixPrec','There is a mismatch between sizes: '&
//I2S(n)//' vs. '//I2S(Offset(NoVar+1)))
END IF
solver_save => Solver
var_save => Solver % Variable
mat_save => Solver % Matrix
rhs_save => Solver % Matrix % RHS
BlockScaling = ListGetLogical( Params,'Block Scaling',Found )
DoDiagScaling = .FALSE.
IF( ASSOCIATED( Solver % Matrix ) ) THEN
DoDiagScaling = ASSOCIATED( Solver % Matrix % diagscaling )
END IF
IF( DoDiagScaling ) THEN
CALL Info('BlockMatrixPrec','External diagonal scaling is active!',Level=20)
ELSE
CALL Info('BlockMatrixPrec','External diagonal scaling is not active!',Level=30)
END IF
IF( BlockScaling ) THEN
CALL Info('BlockMatrixPrec','Block matrix scaling is active!',Level=20)
ELSE
CALL Info('BlockMatrixPrec','Block matrix scaling is not active!',Level=30)
END IF
IF(DoDiagscaling) THEN
NoNestedScaling = ListGetLogical( Params,'Eliminate Nested Scaling',Found )
IF(.NOT. Found) NoNestedScaling = .TRUE.
ELSE
NoNestedScaling = .FALSE.
END IF
CALL ListAddLogical( Params,'Linear System Skip Complex',.FALSE.)
CALL ListAddLogical( Params,'Linear System Skip Loads',.TRUE.)
IF (isParallel) THEN
ALLOCATE( x(TotMatrix % MaxSize), b(TotMatrix % MaxSize) )
END IF
u(1:n) = 0.0_dp
BlockSch = ListCheckPrefix( Params,'Schur Operator' )
IF( BlockGS .OR. BlockSch ) THEN
ALLOCATE( vtmp(n), rtmp(n), xtmp(n),STAT=istat)
IF ( istat /= 0 ) CALL Fatal('BlockMatrixPrec','Memory allocation error for wrk space!')
vtmp(1:n) = v(1:n)
END IF
CALL ListPushNameSpace('block:')
DO j=1,NoVar
IF( GotOrder ) THEN
i = BlockOrder(j)
ELSE
i = j
END IF
WRITE(Message,'(A,I0)') 'Solving block: ',i
CALL Info('BlockMatrixPrec',Message,Level=8)
IF ( ListGetLogical( Solver % Values, 'Dymmy block '//I2S(i), Found) ) THEN
u(offset(i)+1:offset(i+1)) = v(offset(i)+1:offset(i+1)); cycle
end if
CALL ListAddLogical( Params,'Skip Advance Nonlinear iter',.TRUE.)
CALL ListAddLogical( Params,'Skip Compute Nonlinear Change',.TRUE.)
Var => TotMatrix % SubVector(i) % Var
UsePrecMat = .FALSE.
IF( ASSOCIATED( TotMatrix % Subvector(i) % Solver ) ) THEN
ASolver => TotMatrix % SubVector(i) % Solver
A => ASolver % Matrix
ELSE
A => TotMatrix % Submatrix(i,i) % PrecMat
IF( A % NumberOfRows == 0 ) THEN
A => TotMatrix % Submatrix(i,i) % Mat
ELSE
UsePrecMat = .TRUE.
CALL Info('BlockMatrixPrec','Using specialized (Schur) preconditioning block',Level=9)
END IF
ASolver => Solver
END IF
IF ( A % NumberOfRows == 0 ) CYCLE
IF (isParallel) THEN
x = 0.0_dp
b = 0.0_dp
ParPerm => TotMatrix % Submatrix(i,i) % ParPerm
x(ParPerm) = u(offset(i)+1:offset(i+1))
IF( BlockGS ) THEN
b(ParPerm) = vtmp(offset(i)+1:offset(i+1))
ELSE
b(ParPerm) = v(offset(i)+1:offset(i+1))
END IF
ELSE
x => u(offset(i)+1:offset(i+1))
IF( BlockGS ) THEN
b => vtmp(offset(i)+1:offset(i+1))
ELSE
b => v(offset(i)+1:offset(i+1))
END IF
END IF
IF( InfoActive(25) ) THEN
nrm = CompNorm(b,offset(i+1)-offset(i))
WRITE( Message,'(A,ES12.5)') 'Rhs '//I2S(i)//' norm: ',nrm
CALL Info('BlockMatrixPrec',Message,Level=10)
END IF
IF( ListGetLogical( Params,'Block Prec Reuse',Found) ) THEN
DO k = 1, NoVar
IF( k == i ) CYCLE
IF( CRS_CopyMatrixPrec( TotMatrix % Submatrix(k,k) % Mat, A ) ) EXIT
END DO
END IF
IF( BlockScaling ) CALL DoBlockMatrixScaling(.TRUE.,i,i,b,UsePrecMat)
DoPrecScaling = DoDiagScaling .AND. UsePrecMat
IF( DoPrecScaling ) THEN
n = A % NumberOfRows
ALLOCATE( btmp(n), diagtmp(n), STAT=istat)
IF ( istat /= 0 ) CALL Fatal('BlockMatrixPrec',&
'Memory allocation error for scaling wrk space!')
IF( TotMatrix % GotBlockStruct ) THEN
k = TotMatrix % InvBlockStruct(i)
IF( k <= 0 ) THEN
CALL Fatal('BlockMatrixPrec','Cannot define the originating block '&
//I2S(i)//' for scaling!')
ELSE
CALL Info('BlockMatrixPrec','Using initial block '//I2S(k)//&
' in scaling of prec matrix '//I2S(i),Level=12)
END IF
ELSE
k = i
END IF
l = Solver % Variable % DOFs
diagtmp(1:n) = Solver % Matrix % DiagScaling(k::l)
x(1:n) = x(1:n) * diagtmp(1:n) * Solver % Matrix % RhsScaling
btmp(1:n) = b(1:n) / diagtmp(1:n) * Solver % Matrix % RhsScaling
ELSE
btmp => b
IF( NoNestedScaling ) THEN
CALL Info('BlockMatrixPrec','Eliminating scaling for block as outer scaling already done!',Level=25)
CALL ListAddLogical( Params,'Linear System Skip Scaling',.TRUE.)
END IF
END IF
IF( InfoActive( 25 ) ) THEN
CALL BlockMatrixInfo()
END IF
IF( A % COMPLEX ) THEN
nc = 2
ELSE
nc = 1
END IF
k = ListGetInteger( Params,'Schur Operator '//I2S(i),Found )
IF( k > 0 ) THEN
CALL Info('BlockMatrixPrec','Perform Schur complement operation for block '//I2S(i), Level=7 )
Aij => TotMatrix % SubMatrix(i,k) % Mat
IF( Aij % NumberOfRows == 0) CYCLE
Aij => TotMatrix % Submatrix(k,i) % Mat
IF( BlockGS ) THEN
b => vtmp(offset(i)+1:offset(i+1))
ELSE
b => v(offset(i)+1:offset(i+1))
END IF
IF(DoAMGXMV) THEN
CALL AMGXMatrixVectorMultiply(Aij,b,rtmp,SolverRef )
ELSE
CALL CRS_MatrixVectorMultiply(Aij,b,rtmp )
END IF
CALL ListPushNameSpace('block '//i2s(11*k)//':')
Aij => TotMatrix % Submatrix(k,k) % Mat
Isolated = TotMatrix % SubMatrix(k,k) % ParallelIsolatedMatrix
IF(DoAMGXMv) THEN
ScaleSystem = ListGetLogical( Params,'Linear System Scaling', Found )
IF(.NOT. Found) ScaleSystem = .TRUE.
IF ( ScaleSystem ) CALL ScaleLinearSystem(ASolver, Aij,btmp,xtmp )
CALL AMGXSolver( Aij, xtmp, btmp, ASolver )
IF( ScaleSystem ) CALL BackScaleLinearSystem(ASolver,Aij,btmp,xtmp)
ELSE
CALL SolveLinearSystem( Aij, rtmp, xtmp, Var % Norm, Var % DOFs, ASolver )
END IF
rtmp = 0.0_dp
Aij => TotMatrix % Submatrix(i,k) % Mat
IF(DoAMGXMV) THEN
CALL AMGXMatrixVectorMultiply(Aij,xtmp,rtmp,SolverRef )
ELSE
CALL CRS_MatrixVectorMultiply(Aij,xtmp,rtmp )
END IF
BLOCK
REAL(KIND=dp) :: cmult
cmult = ListGetCReal( Params,'Schur Multiplier '//I2S(i),Found, DefValue=1.0_dp )
u(offset(i)+1:offset(i+1)) = u(offset(i)+1:offset(i+1)) &
- cmult * rtmp(1:offset(i+1)-offset(i))
END BLOCK
CALL ListPopNameSpace()
CYCLE
ELSE
CALL ListPushNameSpace('block '//i2s(11*i)//':')
IF(DoAMGXMv) THEN
ScaleSystem = ListGetLogical( Params,'Linear System Scaling', Found )
IF(.NOT. Found) ScaleSystem = .TRUE.
IF ( ScaleSystem ) CALL ScaleLinearSystem(ASolver, A,btmp,x )
CALL AMGXSolver( A, x, btmp, ASolver )
IF( ScaleSystem ) CALL BackScaleLinearSystem(ASolver,A,btmp,x)
ELSE
CALL SolveLinearSystem( A, btmp, x, Var % Norm, Var % DOFs, ASolver )
END IF
END IF
IF( DoPrecScaling ) THEN
x(1:n) = x(1:n) / diagtmp(1:n)
DEALLOCATE( btmp, diagtmp )
ELSE IF( NoNestedScaling ) THEN
CALL ListAddLogical( Params,'Linear System Skip Scaling',.FALSE.)
END IF
IF( InfoActive(20) ) THEN
nrm = CompNorm(x,offset(i+1)-offset(i),A=A)
WRITE( Message,'(A,ES12.5)') 'Linear system '//I2S(i)//' norm: ',nrm
CALL Info('BlockMatrixPrec',Message)
END IF
IF( BlockScaling ) CALL DoBlockMatrixScaling(.FALSE.,i,i,b,UsePrecMat)
IF (isParallel) THEN
x(1:offset(i+1)-offset(i)) = x(ParPerm)
u(offset(i)+1:offset(i+1)) = x(1:offset(i+1)-offset(i))
END IF
IF( BlockGS ) THEN
CALL Info('BlockMatrixPrec','Updating block r.h.s',Level=9)
DO l=j+1,NoVar
IF( GotOrder ) THEN
k = BlockOrder(l)
ELSE
k = l
END IF
str = 'Block Gauss-Seidel Passive '//I2S(k)//I2S(i)
IF( ListGetLogical( Params, str, Found ) ) CYCLE
CALL Info('BlockMatrixPrec','Updating r.h.s for component '//I2S(k),Level=15)
Aij => TotMatrix % SubMatrix(k,i) % Mat
IF( Aij % NumberOfRows == 0) CYCLE
Isolated = TotMatrix % SubMatrix(k,i) % ParallelIsolatedMatrix
IF (isParallel) THEN
IF(ASSOCIATED(Aij % ParMatrix)) THEN
CALL ParallelMatrixVector(Aij,x,rtmp )
ELSE IF( Isolated ) THEN
CALL CRS_MatrixVectorMultiply(Aij,x,rtmp)
ParPerm => TotMatrix % Submatrix(i,i) % ParPerm
#if 0
rtmp(1:offset(i+1)-offset(i)) = rtmp(ParPerm)
#else
ll = 0
DO kk=1,A % NumberofRows
IF (Parenv % MyPE /= A % ParallelInfo % NeighbourList(kk) % Neighbours(1)) CYCLE
ll = ll+1
rtmp(ll) = rtmp(kk)
IF(parperm(ll) /= kk) PRINT *,'Problem:',ll,kk,parperm(ll)
END DO
#endif
ELSE IF (ASSOCIATED(SolverMatrix)) THEN
xtmp = 0.0_dp
xtmp(offset(i)+1:offset(i+1)) = x(offset(i)+1:offset(i+1))
BlockPerm => TotMatrix % ParBlockPerm
xtmp(BlockPerm(1:n)) = xtmp(1:n)
CALL ParallelMatrixVector(SolverMatrix,xtmp,rtmp)
rtmp(1:n) = rtmp(BlockPerm(1:n))
rtmp(1:offset(k+1)-offset(k)) = rtmp(offset(k)+1:offset(k+1))
ELSE
CALL Fatal('BlockMatrixPrec','Do not know how to apply parallel matrix!')
END IF
ELSE
Aij => TotMatrix % Submatrix(k,i) % Mat
IF(DoAMGXMV) THEN
CALL AMGXMatrixVectorMultiply(Aij, x, rtmp, SolverRef )
ELSE
CALL CRS_MatrixVectorMultiply(Aij,x,rtmp )
END IF
END IF
vtmp(offset(k)+1:offset(k+1)) = vtmp(offset(k)+1:offset(k+1)) &
- rtmp(1:offset(k+1)-offset(k))
END DO
END IF
CALL ListPopNameSpace()
END DO
IF (isParallel) DEALLOCATE(x,b)
CALL ListPopNameSpace('block:')
CALL ListAddLogical( Params,'Linear System Refactorize',.FALSE. )
CALL ListAddLogical( Params,'Skip Advance Nonlinear iter',.FALSE.)
CALL ListAddLogical( Params,'Skip Compute Nonlinear Change',.FALSE.)
CALL ListAddLogical( Params,'Linear System Skip Loads',.FALSE.)
Solver => Solver_save
Solver % Matrix => mat_save
Solver % Matrix % RHS => rhs_save
Solver % Variable => Var_save
IF( BlockGS .OR. BlockSch ) THEN
DEALLOCATE( vtmp, rtmp, xtmp )
END IF
IF( InfoActive(20) ) THEN
nrm = CompNorm(v(1:n),n)
WRITE( Message,'(A,ES12.5)') 'V fin norm: ',nrm
CALL Info('BlockMatrixPrec',Message,Level=10)
nrm = CompNorm(u(1:n),n)
WRITE( Message,'(A,ES12.5)') 'U fin norm: ',nrm
CALL Info('BlockMatrixPrec',Message,Level=10)
END IF
CALL Info('BlockMatrixPrec','Finished block matrix preconditioning',Level=8)
END SUBROUTINE BlockMatrixPrec
SUBROUTINE BlockStandardIter( Solver, MaxChange )
TYPE(Solver_t) :: Solver
REAL(KIND=dp) :: MaxChange
INTEGER :: i,j,NoVar,RowVar,iter,LinIter,MinIter
INTEGER, POINTER :: BlockOrder(:)
LOGICAL :: GotIt, GotBlockOrder, BlockGS
REAL(KIND=dp), POINTER CONTIG :: rhs_save(:), b(:)
REAL(KIND=dp), POINTER :: dx(:)
TYPE(Matrix_t), POINTER :: A, mat_save
TYPE(Variable_t), POINTER :: Var, SolverVar
REAL(KIND=dp) :: LinTol, TotNorm, dxnorm, xnorm, Relax
TYPE(ValueList_t), POINTER :: Params
LOGICAL :: ScaleSystem, BlockScaling, Found
NoVar = TotMatrix % NoVar
Params => Solver % Values
SolverVar => Solver % Variable
BlockGS = ListGetLogical( Params,'Block Gauss-Seidel',Found)
BlockOrder => ListGetIntegerArray( Params,'Block Order',GotBlockOrder)
LinIter = ListGetInteger( Params,'Linear System Max Iterations',GotIt)
MinIter = ListGetInteger( Params,'Linear System Min Iterations',GotIt)
LinTol = ListGetConstReal( Params,'Linear System Convergence Tolerance',GotIt)
BlockScaling = ListGetLogical( Params,'Block Scaling',GotIt)
CALL ListPushNamespace('block:')
CALL ListAddNewLogical( Params,'Skip compute nonlinear change',.TRUE.)
Relax = 1.0_dp
DO iter = 1, LinIter
TotMatrix % NoIters = iter
IF( BlockGS ) THEN
WRITE( Message,'(A,I0)') 'Block Gauss-Seidel iteration: ',iter
ELSE
WRITE( Message,'(A,I0)') 'Block Jacobi iteration: ',iter
CALL BlockUpdateRhs(TotMatrix)
END IF
CALL Info('BlockStandardIter',Message,Level=5)
MaxChange = 0.0_dp
TotNorm = 0.0_dp
IF( iter == 2 ) THEN
CALL ListAddLogical( Params,'No Precondition Recompute',.TRUE.)
END IF
DO i=1,NoVar
IF( GotBlockOrder ) THEN
RowVar = BlockOrder(i)
ELSE
RowVar = i
END IF
IF( BlockGS ) THEN
CALL BlockUpdateRhs(TotMatrix,RowVar)
END IF
IF( ListGetLogical( Params,'Block Prec Reuse',GotIt) ) THEN
DO j = 1, NoVar
IF( j == RowVar ) CYCLE
IF( CRS_CopyMatrixPrec( TotMatrix % Submatrix(j,j) % Mat, A ) ) EXIT
END DO
END IF
b => TotMatrix % SubVector(RowVar) % rhs
IF( InfoActive( 15 ) ) THEN
PRINT *,'rhs'//I2S(i)//':',SQRT( SUM(b**2) ), MINVAL( b ), MAXVAL( b ), SUM( b )
END IF
Var => TotMatrix % SubVector(RowVar) % Var
Solver % Variable => Var
A => TotMatrix % Submatrix(i,i) % PrecMat
IF( A % NumberOfRows == 0 ) THEN
A => TotMatrix % Submatrix(i,i) % Mat
ELSE
CALL Info('BlockStandardIter','Using preconditioning block: '//I2S(i),Level=8)
END IF
rhs_save => A % rhs
A % RHS => b
ALLOCATE( dx( SIZE( Var % Values ) ) )
dx = 0.0_dp
CALL ListPushNamespace('block '//i2s(11*RowVar)//':')
IF( BlockScaling ) CALL DoBlockMatrixScaling(.TRUE.,i,i,b)
CALL SolveLinearSystem( A, b, dx, Var % Norm, Var % DOFs, Solver )
IF( BlockScaling ) CALL DoBlockMatrixScaling(.FALSE.,i,i,b)
CALL ListPopNamespace()
A % RHS => rhs_save
IF( iter > 1 ) THEN
Var % Values = Var % Values + Relax * dx
ELSE
Var % Values = Var % Values + dx
END IF
dxnorm = CompNorm(dx,A % NumberOfRows, A=A)
xnorm = CompNorm(Var % Values, A % NumberOfRows, A=A)
Var % Norm = xnorm
Var % NonlinChange = dxnorm / xnorm
WRITE(Message,'(A,2ES12.3)') 'Block '//I2S(RowVar)//' norms: ',xnorm, dxnorm / xnorm
CALL Info('BlockStandardIter',Message,Level=5)
IF( InfoActive( 20 ) ) THEN
PRINT *,'dx'//I2S(i)//':',SQRT( SUM(dx**2) ), MINVAL( dx ), MAXVAL( dx ), SUM( dx ), SUM( ABS( dx ) )
END IF
DEALLOCATE( dx )
TotNorm = TotNorm + Var % Norm
MaxChange = MAX( MaxChange, Var % NonlinChange )
END DO
WRITE(Message,'(A,2ES12.3)') 'Sum of norms: ',TotNorm, MaxChange
CALL Info('BlockStandardIter',Message,Level=4)
IF( MaxChange < LinTol .AND. iter >= MinIter ) THEN
CALL Info('BlockStandardIter','Converged after iterations: '//I2S(iter),Level=5)
EXIT
END IF
END DO
CALL ListPopNamespace('block:')
CALL ListAddLogical( Params,'No Precondition Recompute',.FALSE.)
Solver % Variable => SolverVar
END SUBROUTINE BlockStandardIter
SUBROUTINE BlockKrylovIter( Solver, MaxChange )
TYPE(Solver_t) :: Solver
REAL(KIND=dp) :: MaxChange
INTEGER(KIND=AddrInt) :: AddrFunc
EXTERNAL :: AddrFunc
INTEGER(KIND=AddrInt) :: iterProc,precProc, mvProc,dotProc,nmrProc, zero=0
REAL(KIND=dp) :: dpar(20), xnorm,prevxnorm
REAL(KIND=dp), ALLOCATABLE :: x(:),b(:),r(:)
TYPE(Matrix_t), POINTER :: A
TYPE(Variable_t), POINTER :: SVar
TYPE(ValueList_t), POINTER :: Params
INTEGER :: NoVar, ndim, maxsize
LOGICAL :: Converged, Diverged
INTEGER :: Rounds, OutputInterval, PolynomialDegree
INTEGER, POINTER :: Offset(:),poffset(:),BlockStruct(:),ParPerm(:)
INTEGER :: i,j,k,l,ia,ib,istat
LOGICAL :: LS, BlockAV,Found, UseMono
CHARACTER(:), ALLOCATABLE :: VarName
CHARACTER(*), PARAMETER :: Caller = 'BlockKrylovIter'
CALL Info(Caller,'Starting block system iteration',Level=8)
Params => Solver % Values
BlockAV = ListGetLogical(Params,'Block A-V System', Found)
ndim = TotMatrix % TotSize
NoVar = TotMatrix % NoVar
TotMatrix % NoIters = 0
isParallel = (ParEnv % PEs > 1)
offset => TotMatrix % Offset
IF(isParallel) THEN
poffset => TotMatrix % ParOffset
ELSE
poffset => offset
END IF
DO i=1,NoVar
IF( .NOT. ASSOCIATED( TotMatrix % Subvector(i) % Var ) ) THEN
CALL Fatal(Caller,'Subvector '//I2S(i)//' not associated!')
END IF
A => TotMatrix % SubMatrix(i,i) % Mat
IF( .NOT. ASSOCIATED( A ) ) THEN
CALL Fatal(Caller,'Submatrix '//I2S(11*i)//' not associated!')
END IF
IF( .NOT. ASSOCIATED( A % Rhs ) ) THEN
CALL Warn(Caller,'Submatrix rhs '//I2S(11*i)//' not associated!')
END IF
END DO
CALL Info(Caller,'Allocating temporal vectors for block system of size: '&
//I2S(ndim),Level=15)
ALLOCATE(x(ndim), b(ndim),r(ndim),STAT=istat)
IF( istat /= 0 ) THEN
CALL Fatal(Caller,'Cannot allocate temporal vectors of size: '//I2S(ndim))
END IF
x = 0.0_dp
b = 0.0_dp
r = 0.0_dp
IF (isParallel) THEN
CALL Info(Caller,'Performing parallel initializations!',Level=18)
DO i=1,NoVar
A => TotMatrix % SubMatrix(i,i) % Mat
CALL Info(Caller,'Initializing submatrix '//I2S(11*i),Level=20)
IF (ASSOCIATED(A % ParMatrix % SplittedMatrix % InsideMatrix % PrecValues)) THEN
IF (.NOT. ASSOCIATED(A % PrecValues)) &
NULLIFY(A % ParMatrix % SplittedMatrix % InsideMatrix % PrecValues)
END IF
CALL ParallelInitSolve(A, TotMatrix % Subvector(i) % Var % Values, A % rhs, r )
IF( ASSOCIATED(SolverMatrix)) THEN
x(offset(i)+1:offset(i+1)) = TotMatrix % SubVector(i) % Var % Values
IF(ASSOCIATED(A % rhs)) b(offset(i)+1:offset(i+1)) = A % rhs
END IF
CALL Info(Caller,'Done initializing submatrix '//I2S(11*i),Level=20)
END DO
DO i=1,NoVar
DO j=1,NoVar
A => TotMatrix % SubMatrix(i,j) % Mat
IF(i==j) CYCLE
CALL Info(Caller,'Initializing submatrix '//I2S(10*i+j),Level=20)
IF(ASSOCIATED(A % ParMatrix)) CALL ParallelInitSolve(A,r,r,r)
END DO
END DO
IF(ASSOCIATED(SolverMatrix)) THEN
CALL Info(Caller,'Initializing SolverMatrix',Level=20)
CALL ParallelInitSolve( SolverMatrix, x, b, r )
x = 0.0_dp
b = 0.0_dp
END IF
CALL Info(Caller,'Parallel initializations done!',Level=25)
END IF
CALL Info(Caller,'Initializing monolithic system vectors',Level=18)
DO i=1,NoVar
A => TotMatrix % SubMatrix(i,i) % Mat
IF (.NOT.isParallel) THEN
x(offset(i)+1:offset(i+1)) = TotMatrix % SubVector(i) % Var % Values
IF(ASSOCIATED(A % rhs)) b(offset(i)+1:offset(i+1)) = A % rhs
ELSE
ParPerm => TotMatrix % SubMatrix(i,i) % ParPerm
x(poffset(i)+1:poffset(i+1)) = TotMatrix % SubVector(i) % Var % Values(ParPerm)
IF(ASSOCIATED(A % rhs)) b(poffset(i)+1:poffset(i+1)) = A % rhs(ParPerm)
END IF
END DO
IF (isParallel) THEN
ndim = poffset(NoVar+1)
END IF
CALL ListAddLogical(Params,'Linear System Free Factorization',.FALSE.)
precProc = AddrFunc(BlockMatrixPrec)
UseMono = ListGetLogical(Params,'Block MV Monolithic',Found )
IF(isParallel .AND. .NOT. Found ) THEN
UseMono = .NOT. ( ASSOCIATED(TotMatrix % SubMatrix(1,NoVar) % Mat % ParMatrix) .OR. &
TotMatrix % SubMatrix(1,NoVar) % ParallelIsolatedMatrix )
END IF
IF( UseMono ) THEN
mvProc = AddrFunc(BlockMatrixVectorProdMono)
ELSE
mvProc = AddrFunc(BlockMatrixVectorProd)
END IF
prevXnorm = CompNorm(b,ndim)
WRITE( Message,'(A,ES12.5)') 'Rhs norm at start: ',PrevXnorm
CALL Info(Caller,Message,Level=10)
IF( PrevXNorm < EPSILON( PrevXNorm ) ) THEN
CALL Warn(Caller,"With zero'ish r.h.s. it does not make sense to call the solver!")
RETURN
END IF
prevXnorm = CompNorm(x,ndim)
WRITE( Message,'(A,ES12.5)') 'Solution norm at start: ',PrevXnorm
CALL Info(Caller,Message,Level=10)
CALL Info(Caller,'Start of blocks system iteration',Level=18)
CALL ListAddLogical( Params,'Linear System Skip Complex',.TRUE.)
IF(ASSOCIATED(SolverMatrix)) THEN
A => SolverMatrix
ELSE
A => TotMatrix % SubMatrix(1,1) % Mat
END IF
IF (isParallel) THEN
A => A % ParMatrix % SplittedMatrix % InsideMatrix
CALL IterSolver( A,x,b,&
Solver,ndim=ndim,MatvecF=mvProc,PrecF=precProc,&
DotF=AddrFunc(SParDotProd), NormF=AddrFunc(SParNorm))
DO i=1,NoVar
TotMatrix % SubMatrix(i,i) % Mat % ParMatrix % SplittedMatrix % &
TmpXvec = x(poffset(i)+1:poffset(i+1))
END DO
DO i=1,NoVar
CALL ParallelUpdateResult(TotMatrix % SubMatrix(i,i) % Mat, &
x(offset(i)+1:offset(i+1)), r )
END DO
ELSE
IF( ListGetLogical( Params,'Linear System test',Found ) ) THEN
CALL IterSolver( A,x,b,&
Solver,ndim=ndim,MatvecF=mvProc,PrecF=precProc,&
DotF=AddrFunc(PseudoZDotProd) )
ELSE
CALL IterSolver( A,x,b,&
Solver,ndim=ndim,MatvecF=mvProc,PrecF=precProc)
END IF
END IF
CALL info(Caller,'Finished block system iteration',Level=18)
CALL ListAddLogical(Params,'Linear System Refactorize',.TRUE.)
CALL ListAddLogical(Params,'Linear System Free Factorization',.TRUE.)
Xnorm = CompNorm(x,ndim)
WRITE( Message,'(A,ES12.5)') 'Solution norm: ',Xnorm
CALL Info(Caller,Message,Level=8)
MaxChange = 2*ABS(Xnorm-PrevXnorm)/(Xnorm+PrevXnorm)
PrevXNorm = Xnorm
WRITE( Message,'(A,ES12.5)') 'Relative change: ',MaxChange
CALL Info(Caller,Message,Level=8)
DO i=1,NoVar
TotMatrix % SubVector(i) % Var % Values(1:offset(i+1)-offset(i)) = &
x(offset(i)+1:offset(i+1))
END DO
IF( TotMatrix % GotBlockStruct ) THEN
SVar => CurrentModel % Solver % Variable
i = SIZE(SVar % Values)
Svar % Values(TotMatrix % BlockPerm(1:i)) = x(1:i)
ELSE IF (BlockAV ) THEN
i = SIZE(SolverVar % Values)
SolverVar % Values = x(1:i)
END IF
j = SIZE(x)
IF(j>i) THEN
VarName = LagrangeMultiplierName( Solver )
SVar => VariableGet( Solver % Mesh % Variables, VarName )
IF(ASSOCIATED(SVar)) SVar % Values = x(i+1:j)
END IF
CALL Info(Caller,'Finished block krylov iteration',Level=20)
END SUBROUTINE blockKrylovIter
SUBROUTINE BlockMonolithicSolve( Solver, MaxChange )
TYPE(Solver_t) :: Solver
REAL(KIND=dp) :: MaxChange
INTEGER :: i,j,k,m,n,nc,mc,c,NoVar,NoCol,NoRow,NoEigen,vdofs,comp
INTEGER, POINTER :: BlockOrder(:)
LOGICAL :: GotIt, DampedEigen
REAL(KIND=dp), POINTER CONTIG :: rhs_save(:), b(:)
REAL(KIND=dp), POINTER :: CollX(:), rhs(:)
TYPE(Matrix_t), POINTER :: A, mat_save
TYPE(Variable_t), POINTER :: Var, CompVar, SolverVar
TYPE(Variable_t), TARGET :: MonolithicVar
REAL(KIND=dp) :: TotNorm
CHARACTER(:), ALLOCATABLE :: CompName
TYPE(ValueList_t), POINTER :: Params
TYPE(Matrix_t), POINTER :: CollMat
LOGICAL :: Found, HaveMass, HaveDamp, SaveImag, Visited = .FALSE.
CHARACTER(*), PARAMETER :: Caller = 'BlockMonolithicSolve'
SAVE Visited, CollMat, CollX, HaveMass, HaveDamp, SaveImag
CALL Info(Caller,'Solving block matrix as monolithic!',Level=6)
NoVar = TotMatrix % NoVar
Params => Solver % Values
SolverVar => Solver % Variable
Solver % Variable => MonolithicVar
IF(.NOT. Visited ) THEN
n = 0
m = 0
CollMat => AllocateMatrix()
HaveMass = .FALSE.
HaveDamp = .FALSE.
DO NoRow = 1,NoVar
rhs => TotMatrix % SubVector(NoRow) % rhs
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
n = n + A % NumberOfRows
DO NoCol = 1,NoVar
A => TotMatrix % SubMatrix( NoRow, NoCol ) % Mat
IF(.NOT. ASSOCIATED(A) ) CYCLE
IF(.NOT. ASSOCIATED(A % Values) ) CYCLE
IF(InfoActive(20)) THEN
CALL VectorValuesRange(A % Values,SIZE(A % Values),&
'A'//I2S(10*NoRow+NoCol),.TRUE.)
IF( ASSOCIATED( A % MassValues ) ) THEN
CALL VectorValuesRange(A % MassValues,SIZE(A % MassValues),&
'M'//I2S(10*NoRow+NoCol),.TRUE.)
END IF
END IF
m = m + SIZE( A % Values )
IF( ASSOCIATED( A % MassValues ) ) HaveMass = .TRUE.
IF( ASSOCIATED( A % DampValues ) ) HaveDamp = .TRUE.
END DO
END DO
IF( HaveMass ) THEN
DO NoRow = 1,NoVar
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
IF(.NOT. ASSOCIATED( A % MassValues ) ) THEN
CALL Warn(Caller,'MassValues are missing for block: '//I2S(11*NoRow))
END IF
END DO
CALL Info(Caller,'Treating MassValues of block matrix too!',Level=20)
END IF
IF( HaveDamp ) THEN
CALL Info(Caller,'Treating DampValues of block matrix too!',Level=20)
END IF
NoEigen = Solver % NOFEigenValues
DampedEigen = ListGetLogical(Solver % Values,'Eigen System Complex',Found )
IF( DampedEigen ) THEN
CALL Info(Caller,'Creating complex system for eigen values!',Level=6)
ELSE
CALL Info(Caller,'Creating real valued system for eigen values!',Level=8)
END IF
SaveImag = ListGetLogical(Solver % Values,'Pick Im Component',Found )
IF(DampedEigen) THEN
nc = 2*n
mc = 4*m
ELSE
nc = n
mc = m
END IF
CollMat % NumberOfRows = nc
CALL Info(Caller,'Size of monolithic matrix: '//I2S(nc),Level=7)
CALL Info(Caller,'Estimated number of nonzeros in monolithic matrix: '//I2S(mc),Level=7)
ALLOCATE( CollMat % rhs(nc), CollMat % Diag(nc), CollMat % Rows(nc+1), CollX(nc) )
CollMat % rhs = 0.0_dp
CollMat % Diag = 0
CollMat % Rows = 0
CollX = 0.0_dp
CollMat % Complex = DampedEigen
ALLOCATE( CollMat % Values(mc), CollMat % Cols(mc+1) )
CollMat % Values = 0.0_dp
CollMat % Cols = 0
IF( HaveMass ) THEN
ALLOCATE( CollMat % MassValues(mc) )
CollMat % MassValues = 0.0_dp
END IF
IF( HaveDamp .AND. .NOT. DampedEigen ) THEN
ALLOCATE( CollMat % DampValues(mc) )
CollMat % DampValues = 0.0_dp
END IF
END IF
k = 0
CollMat % Rows(1) = 1
IF(DampedEigen) THEN
DO NoRow = 1,NoVar
n = TotMatrix % Offset(NoRow)
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
m = A % NumberOfRows
DO i=1,m
DO c=1,2
DO NoCol = 1,NoVar
A => TotMatrix % SubMatrix( NoRow, NoCol ) % Mat
IF( .NOT. ASSOCIATED( A ) ) CYCLE
IF( .NOT. ASSOCIATED( A % Rows ) ) CYCLE
DO j=A % Rows(i),A % Rows(i+1)-1
IF( c == 2 ) THEN
k = k + 1
CollMat % Cols(k) = 2*TotMatrix % Offset(NoCol) + 2*A % Cols(j)-1
IF( ASSOCIATED( A % DampValues) ) THEN
CollMat % Values(k) = A % DampValues(j)
END IF
END IF
k = k + 1
CollMat % Values(k) = A % Values(j)
CollMat % Cols(k) = 2*TotMatrix % Offset(NoCol) + 2*(A % Cols(j)-1)+c
IF( ASSOCIATED( A % MassValues ) ) THEN
CollMat % MassValues(k) = A % MassValues(j)
END IF
IF( c == 1 ) THEN
k = k + 1
CollMat % Cols(k) = 2*TotMatrix % Offset(NoCol) + 2*A % Cols(j)
IF( ASSOCIATED( A % DampValues) ) THEN
CollMat % Values(k) = -A % DampValues(j)
END IF
END IF
END DO
END DO
IF(.NOT. Visited ) THEN
CollMat % Rows(2*((n+i)-1)+c+1) = k+1
END IF
END DO
END DO
END DO
ELSE
DO NoRow = 1,NoVar
n = TotMatrix % Offset(NoRow)
A => TotMatrix % SubMatrix( NoRow, NoRow ) % Mat
m = A % NumberOfRows
DO i=1,m
DO NoCol = 1,NoVar
A => TotMatrix % SubMatrix( NoRow, NoCol ) % Mat
IF( .NOT. ASSOCIATED( A ) ) CYCLE
IF( .NOT. ASSOCIATED( A % Rows ) ) CYCLE
IF( SIZE(A % Rows) < i+1 ) CYCLE
DO j=A % Rows(i),A % Rows(i+1)-1
k = k + 1
CollMat % Values(k) = A % Values(j)
IF(.NOT. Visited ) THEN
CollMat % Cols(k) = TotMatrix % Offset(NoCol) + A % Cols(j)
END IF
IF( HaveMass ) THEN
IF( ASSOCIATED( A % MassValues ) ) THEN
CollMat % MassValues(k) = A % MassValues(j)
END IF
END IF
IF( HaveDamp ) THEN
IF( ASSOCIATED( A % DampValues ) ) THEN
CollMat % DampValues(k) = A % DampValues(j)
END IF
END IF
END DO
IF( ASSOCIATED( A % rhs ) ) THEN
CollMat % rhs(n+i) = A % rhs(i)
END IF
END DO
IF(.NOT. Visited ) THEN
CollMat % Rows(n+i+1) = k+1
END IF
END DO
END DO
END IF
IF( ParEnv % PEs > 1 ) THEN
IF( NoVar /= 2 ) THEN
CALL Fatal(Caller,'Parallel operation currently assumes just 2x2 blocks!')
END IF
CALL Info(Caller,'Merging parallel info of matrices')
CALL ParallelMergeMatrix( Solver, CollMat, &
TotMatrix % SubMatrix(1,1) % Mat, &
TotMatrix % SubMatrix(2,2) % Mat )
END IF
IF(InfoActive(20)) THEN
CALL VectorValuesRange(CollMat % Values,SIZE(CollMat % Values),'Atot',.TRUE.)
IF( ASSOCIATED( CollMat % MassValues ) ) THEN
CALL VectorValuesRange(CollMat % MassValues,SIZE(CollMat % MassValues),'Mtot',.TRUE.)
END IF
END IF
CALL Info(Caller,'True number of nonzeros in monolithic matrix: '//I2S(k),Level=7)
IF(.NOT. Visited ) THEN
MonolithicVar % Name = ''
MonolithicVar % Values => CollX
MonolithicVar % Dofs = 1
MonolithicVar % Perm => NULL()
NoEigen = Solver % NOFEigenValues
IF( NoEigen > 0 ) THEN
n = CollMat % NumberOfRows
ALLOCATE( MonolithicVar % EigenValues(NoEigen), MonolithicVar % EigenVectors(NoEigen,n) )
MonolithicVar % EigenValues = 0.0_dp
MonolithicVar % EigenVectors = 0.0_dp
END IF
Visited = .TRUE.
END IF
IF(.NOT. DampedEigen) THEN
CALL Info(Caller,'Copying block solution to monolithic vector',Level=12)
DO i=1,NoVar
Var => TotMatrix % SubVector(i) % Var
n = SIZE( Var % Values )
m = TotMatrix % Offset(i)
CollX(m+1:m+n) = Var % Values(1:n)
END DO
END IF
CALL SolveLinearSystem( CollMat, CollMat % rhs, CollX, TotNorm, 1, Solver )
CALL Info(Caller,'Copying monolithic vector to block solutions',Level=12)
NoEigen = Solver % NOFEigenValues
IF( NoEigen > 0 ) THEN
MonolithicVar % Values = REAL( MonolithicVar % EigenVectors(1,:) )
END IF
DO i=1,NoVar
Var => TotMatrix % SubVector(i) % Var
n = SIZE( Var % Values )
m = TotMatrix % Offset(i)
Var % Values(1:n) = CollX(m+1:m+n)
IF( NoEigen > 0 ) THEN
IF(.NOT. ASSOCIATED( Var % EigenValues ) ) THEN
IF( ASSOCIATED( Var % Solver ) ) THEN
Var % Solver % NOFEigenValues = NoEigen
END IF
ALLOCATE( Var % EigenValues(NoEigen), Var % EigenVectors(NoEigen,n) )
Var % EigenValues = 0.0_dp
Var % EigenVectors = 0.0_dp
vdofs = Var % Dofs
IF( vdofs > 1 ) THEN
DO comp=1,vdofs
CompName = ComponentName(Var % Name,comp)
CompVar => VariableGet( Solver % Mesh % Variables, Compname )
CompVar % EigenValues => Var % EigenValues
CompVar % EigenVectors => Var % EigenVectors(:,comp::vdofs)
END DO
END IF
END IF
DO k=1,NoEigen
Var % EigenValues(k) = MonolithicVar % EigenValues(k)
Var % EigenVectors(k,1:n) = MonolithicVar % EigenVectors(k,m+1:m+n)
END DO
END IF
END DO
Solver % Variable => SolverVar
END SUBROUTINE BlockMonolithicSolve
SUBROUTINE BlockSolveInt(A,x,b,Solver)
TYPE(Matrix_t), POINTER :: A
TYPE(Solver_t), TARGET :: Solver
REAL(KIND=dp), TARGET :: x(:)
REAL(KIND=dp), TARGET CONTIG :: b(:)
TYPE(Solver_t), POINTER :: PSolver
TYPE(Variable_t), POINTER :: Var
INTEGER :: i,j,k,l,n
LOGICAL :: GotIt, BlockPrec, BlockAV, &
BlockHdiv, BlockReIm, BlockHcurl, BlockHorVer, BlockCart, BlockNodal, BlockDomain, &
BlockDummy, BlockComplex, SkipPrec
INTEGER :: ColVar, RowVar, NoVar, BlockDofs, VarDofs
REAL(KIND=dp) :: TotNorm, MaxChange
REAL(KIND=dp), POINTER :: SaveValues(:)
REAL(KIND=dp), POINTER CONTIG :: SaveRHS(:)
LOGICAL :: BlockScaling, BlockMonolithic, Found
INTEGER :: HaveConstraint, HaveAdd
INTEGER, POINTER :: VarPerm(:)
INTEGER, POINTER :: BlockPerm(:)
INTEGER, POINTER :: SlaveSolvers(:)
LOGICAL :: GotSlaveSolvers, DoMyOwnVars,OldMatrix
TYPE(Matrix_t), POINTER :: Amat, SaveCM
TYPE(Mesh_t), POINTER :: Mesh
TYPE(ValueList_t), POINTER :: Params
INTEGER, POINTER :: BlockIndex(:)
CALL Info('BlockSolveInt','---------------------------------------',Level=5)
Params => Solver % Values
Mesh => Solver % Mesh
PSolver => Solver
SolverRef => Solver
isParallel = ParEnv % PEs > 1
OldMatrix = ASSOCIATED( Solver % BlockMatrix )
IF( OldMatrix ) THEN
CALL Info('BlockSolveInit','Using old block matrix structures!',Level=12)
END IF
BlockPrec = ListGetLogical( Params,'Block Preconditioner',GotIt)
IF(.NOT. GotIt) THEN
CALL Info('BlockSolveInt','Using block preconditioning mode by default')
BlockPrec = .TRUE.
END IF
BlockMonolithic = ListGetLogical( Params,'Block Monolithic',GotIt)
BlockScaling = ListGetLogical( Params,'Block Scaling',GotIt)
BlockAV = ListGetLogical( Params,'Block A-V System', GotIt)
BlockHcurl = ListGetLogical( Params,'Block Quadratic Hcurl System', GotIt)
BlockHdiv = ListGetLogical( Params,'Block Hdiv system',GotIt)
BlockReIm = ListGetLogical( Params,'Block Re-Im system',GotIt)
BlockNodal = ListGetLogical( Params,'Block Nodal System', GotIt)
BlockHorVer = ListGetLogical( Params,'Block Hor-Ver System', GotIt)
BlockCart = ListGetLogical( Params,'Block Cartesian System', GotIt)
BlockDomain = ListGetLogical( Params,'Block Domain System',GotIt)
BlockDummy = ListGetLogical( Params,'Block Nested System',GotIt)
BlockComplex = ListGetLogical( Params,'Block Complex System',GotIt)
DoMyOwnVars = .FALSE.
IF( BlockDomain .OR. BlockHdiv .OR. BlockReIm .OR. BlockHcurl .OR. &
BlockAV .OR. BlockHorVer .OR. BlockCart .OR. BlockNodal ) THEN
n = SIZE( Solver % Variable % Values)
ALLOCATE( BlockIndex(n) )
BlockIndex = 0
BlockDofs = 0
DoMyOwnVars = .TRUE.
IF( BlockDomain ) THEN
CALL BlockPickDofsPhysical( PSolver, BlockIndex, BlockDofs )
ELSE IF( BlockHdiv ) THEN
CALL BlockPickHdiv( PSolver, BlockIndex, BlockDofs )
ELSE IF( BlockReIm ) THEN
CALL BlockPickReIm( PSolver, BlockIndex, BlockDofs )
ELSE IF( BlockHCurl ) THEN
CALL BlockPickMatrixHcurl( PSolver, BlockDofs, BlockComplex, BlockIndex )
ELSE IF( BlockAV ) THEN
CALL BlockPickAV( PSolver, BlockIndex, BlockDofs )
ELSE IF( BlockNodal ) THEN
CALL BlockPickMatrixNodal( PSolver, BlockDofs, BlockComplex, BlockIndex )
ELSE IF(BlockHorVer .OR. BlockCart) THEN
CALL BlockPickMatrixHorVer( PSolver, BlockDofs, BlockCart, BlockIndex )
END IF
GotSlaveSolvers = .FALSE.
ELSE
SlaveSolvers => ListGetIntegerArray( Params, &
'Block Solvers', GotSlaveSolvers )
IF( GotSlaveSolvers ) THEN
BlockDofs = SIZE( SlaveSolvers )
ELSE IF( BlockDummy ) THEN
BlockDofs = 1
ELSE
BlockDofs = Solver % Variable % Dofs
END IF
END IF
VarDofs = BlockDofs
HaveConstraint = 0
IF ( ASSOCIATED(A % ConstraintMatrix) ) HaveConstraint = 1
HaveConstraint = ParallelReduction(HaveConstraint)
HaveAdd = 0
IF ( ASSOCIATED(A % AddMatrix) ) THEN
IF ( A % AddMatrix % NumberOFRows > 0 ) HaveAdd = 1
END IF
HaveAdd = ParallelReduction(HaveAdd)
IF( HaveConstraint > 0 .AND. HaveAdd > 0 ) THEN
CALL Fatal('BlockSolveInt','Cannot yet do both Constraint and Add matrix!')
END IF
IF( HaveConstraint > 0 ) THEN
i = 0
IF ( ASSOCIATED(A % ConstraintMatrix) ) THEN
i = A % ConstraintMatrix % NumberOfRows
END IF
CALL Info('BlockSolveInt','Block system has ConstraintMatrix with '//I2S(i)//' rows!',Level=10)
BlockDofs = BlockDofs + 1
IF (BlockAV) BlockDofs = BlockDofs + 1
END IF
IF( HaveAdd > 0 ) THEN
i = A % AddMatrix % NumberOfRows - A % NumberOfRows
CALL Info('BlockSolveInt','Block system has AddMatrix with '//I2S(i)//' own rows!',Level=10)
BlockDofs = BlockDofs + 1
END IF
IF(.NOT. OldMatrix ) THEN
CALL BlockInitMatrix( Solver, TotMatrix, BlockDofs, VarDofs, DoMyOwnVars )
END IF
NoVar = TotMatrix % NoVar
TotMatrix % Solver => Solver
SaveMatrix => Solver % Matrix
SolverMatrix => A
Solver % Matrix => A
SolverVar => Solver % Variable
SaveValues => SolverVar % Values
SolverVar % Values => x
SaveRHS => SolverMatrix % RHS
SolverMatrix % RHS => b
IF( .NOT. GotSlaveSolvers ) THEN
CALL Info('BlockSolveInt','Splitting monolithic matrix into pieces',Level=10)
IF( DoMyOwnVars ) THEN
CALL BlockPickMatrixPerm( Solver, BlockIndex, VarDofs, HaveAdd > 0 )
IF(ASSOCIATED(BlockIndex)) THEN
CALL BlockInitVar( Solver, TotMatrix, BlockIndex )
DEALLOCATE(BlockIndex)
ELSE
CALL BlockInitVar( Solver, TotMatrix )
END IF
ELSE IF( BlockDummy .OR. VarDofs == 1 ) THEN
CALL Info('BlockSolveInt','Using the original matrix as the (1,1) block!',Level=10)
TotMatrix % SubMatrix(1,1) % Mat => SolverMatrix
TotMatrix % SubMatrix(1,1) % Mat % Complex = ListGetLogical(Params,'Linear System Complex',Found)
ELSE
CALL BlockPickMatrix( Solver, NoVar )
VarDofs = NoVar
END IF
CALL Info('BlockSolveInt','Block matrix system created',Level=12)
END IF
IF( ListGetLogical( Params,'Structure-Structure Coupling',Found ) ) THEN
CALL StructureCouplingBlocks( Solver )
ELSE
CALL FsiCouplingBlocks( Solver )
END IF
IF( HaveConstraint > 0 ) THEN
SkipPrec = ListCheckPrefix( Params,'Schur Operator' )
SkipPrec = SkipPrec .OR. ListGetLogical( Params,'Skip Constraint Prec', Found )
CALL BlockPickConstraint( Solver, VarDofs, SkipPrec )
SaveCM => Solver % Matrix % ConstraintMatrix
Solver % Matrix % ConstraintMatrix => NULL()
END IF
CALL BlockPrecMatrix( Solver, NoVar )
IF( ListCheckSuffix(Params,': Linear System Save') ) THEN
DO RowVar=1,NoVar
DO ColVar=1,NoVar
IF( ListGetLogical( Params,'block '//I2S(10*ColVar+RowVar)//': Linear System Save',Found ) ) THEN
Amat => TotMatrix % SubMatrix(RowVar,ColVar) % Mat
CALL SaveLinearSystem( Solver, Amat,'block'//I2S(10*ColVar+RowVar) )
END IF
END DO
IF( ListGetLogical( Params,'prec '//I2S(11*RowVar)//': Linear System Save',Found ) ) THEN
Amat => TotMatrix % SubMatrix(RowVar,RowVar) % PrecMat
CALL SaveLinearSystem( Solver, Amat,'prec'//I2S(11*RowVar) )
END IF
END DO
END IF
Found = .FALSE.
DO RowVar=1,NoVar
Amat => TotMatrix % SubMatrix(RowVar,RowVar) % Mat
Var => TotMatrix % SubVector(RowVar) % Var
IF( ASSOCIATED( Var ) ) THEN
IF(.NOT. ASSOCIATED(Var % Perm)) THEN
CALL Info('BlockSolveInt','Block variable '//I2S(RowVar)//' ('&
//TRIM(Var % Name)//') exists but not Perm!',Level=3)
Found = .TRUE.
END IF
END IF
END DO
IF(Found) THEN
IF( isParallel ) THEN
CALL Fatal('BlockSolveInt','Cannot continue without Perm in parallel!')
ELSE
CALL Warn('BlockSolveInt','Could not continue without Perm in parallel!!')
END IF
END IF
IF (isParallel .AND. .NOT. OldMatrix ) THEN
CALL Info('BlockSolveInt','Initializing parallel block matrices',Level=12)
DO RowVar=1,NoVar
DO ColVar=1,NoVar
Amat => TotMatrix % SubMatrix(RowVar,ColVar) % Mat
IF(Amat % NumberOfRows == 0) CYCLE
Amat % Comm = Solver % Matrix % Comm
Parenv % ActiveComm = Amat % Comm
Solver % Variable => TotMatrix % SubVector(ColVar) % Var
IF(TotMatrix % Submatrix(RowVar,ColVar) % ParallelIsolatedMatrix ) CYCLE
GotIt = (Amat % NumberOfRows == MAXVAL(Amat % Cols))
TotMatrix % Submatrix(RowVar,ColVar) % ParallelSquareMatrix = GotIt
IF(GotIt) THEN
CALL Info('BlockSolverInt','Block matrix is square matrix',Level=20)
IF (.NOT.ASSOCIATED(Amat % ParMatrix)) THEN
CALL Info('BlockSolveInt','Initializing parallel matrix: '//I2S(10*RowVar+ColVar),Level=6)
CALL ParallelInitMatrix(Solver,Amat)
END IF
IF(ASSOCIATED(Amat % ParMatrix )) THEN
Amat % ParMatrix % ParEnv % ActiveComm = Amat % Comm
ParEnv => Amat % ParMatrix % ParEnv
END IF
ELSE
CALL Info('BlockSolverInt','Block matrix '//I2S(10*RowVar+ColVar)//&
' is not square matrix - cannot initialize parallel structures!',Level=20)
END IF
END DO
END DO
CALL ParallelShrinkPerm()
Solver % Variable => SolverVar
CALL Info('BlockSolveInt','Initialization of block matrix finished',Level=20)
END IF
IF(InfoActive(25)) THEN
CALL Info('BlockSolveInt','Initial Block matrix system information:')
CALL BlockMatrixInfo()
END IF
TotNorm = 0.0_dp
MaxChange = 0.0_dp
IF( BlockScaling ) THEN
CALL CreateBlockMatrixScaling()
CALL DoBlockMatrixScaling(.FALSE.)
END IF
CALL ListPushNamespace('outer:')
IF (BlockScaling) THEN
END IF
IF( NoVar == 1 .AND. .NOT. BlockDummy ) THEN
CALL Info('BlockSolveInt','Solving in standard manner',Level=6)
Solver % Variable => TotMatrix % SubVector(1) % Var
Solver % Matrix => TotMatrix % Submatrix(1,1) % Mat
IF (BlockScaling) THEN
CALL ListAddLogical(Solver % Values, 'Linear System Row Equilibration', .TRUE.)
END IF
TotNorm = DefaultSolve()
MaxChange = Solver % Variable % NonlinChange
ELSE IF( BlockMonolithic ) THEN
CALL Info('BlockSolveInt','Using monolithic strategy for the block',Level=6)
CALL BlockMonolithicSolve( Solver, MaxChange )
ELSE IF( BlockPrec ) THEN
CALL Info('BlockSolveInt','Using block preconditioning strategy',Level=6)
CALL BlockKrylovIter( Solver, MaxChange )
ELSE
Solver % Variable => TotMatrix % SubVector(1) % Var
Solver % Matrix => TotMatrix % Submatrix(1,1) % Mat
CALL Info('BlockSolveInt','Using block solution strategy',Level=6)
CALL BlockStandardIter( Solver, MaxChange )
END IF
CALL ListPopNamespace('outer:')
IF( BlockScaling ) THEN
CALL DoBlockMatrixScaling(.TRUE.)
CALL DestroyBlockMatrixScaling()
END IF
SolverMatrix % RHS => SaveRHS
Solver % Matrix => SaveMatrix
Solver % Variable => SolverVar
Solver % Variable % Values => SaveValues
IF( HaveConstraint > 0 ) THEN
Solver % Matrix % ConstraintMatrix => SaveCM
END IF
IF( DoMyOwnVars ) THEN
CALL BlockBackCopyVar( Solver, TotMatrix )
END IF
IF( ListGetLogical( Solver % Values,'Block Save Iterations',Found ) ) THEN
CALL ListAddInteger(CurrentModel % Simulation,'res: block iterations',TotMatrix % NoIters)
END IF
CALL Info('BlockSolveInt','All done')
CALL Info('BlockSolveInt','-------------------------------------------------',Level=5)
END SUBROUTINE BlockSolveInt
END MODULE BlockSolve
SUBROUTINE BlockSolveExt(A,x,b,Solver)
USE Types
USE BlockSolve, ONLY: BlockSolveInt
USE Lists, ONLY : ListGetLogical, ListAddLogical
IMPLICIT NONE
TYPE(Matrix_t), POINTER :: A
TYPE(Solver_t) :: Solver
REAL(KIND=dp) :: x(:),b(:)
LOGICAL :: Found, bm
bm = ListGetLogical( Solver % Values, 'Linear System Block Mode', Found)
IF(Found) &
CALL ListAddLogical(Solver % Values,'Linear System Block Mode',.FALSE.)
CALL BlockSolveInt(A,x,b,Solver)
IF(Found) &
CALL ListAddLogical(Solver % Values,'Linear System Block Mode',bm )
END SUBROUTINE BlockSolveExt