-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24 from gridap/block-preconditioners
Block-diagonal smoothers
- Loading branch information
Showing
28 changed files
with
1,707 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
struct BlockDiagonalSmoother{A,B} <: Gridap.Algebra.LinearSolver | ||
blocks :: A | ||
solvers :: B | ||
function BlockDiagonalSmoother(blocks ::AbstractArray{<:AbstractMatrix}, | ||
solvers::AbstractArray{<:Gridap.Algebra.LinearSolver}) | ||
@check length(blocks) == length(solvers) | ||
A = typeof(blocks) | ||
B = typeof(solvers) | ||
return new{A,B}(blocks,solvers) | ||
end | ||
end | ||
|
||
# Constructors | ||
|
||
function BlockDiagonalSmoother(block_mat :: AbstractBlockMatrix, | ||
solvers :: AbstractArray{<:Gridap.Algebra.LinearSolver}) | ||
mat_blocks = diag(blocks(block_mat)) | ||
return BlockDiagonalSmoother(mat_blocks,solvers) | ||
end | ||
|
||
function BlockDiagonalSmoother(biforms :: AbstractArray{<:Function}, | ||
trials :: AbstractArray{<:FESpace}, | ||
tests :: AbstractArray{<:FESpace}, | ||
solvers :: AbstractArray{<:Gridap.Algebra.LinearSolver}) | ||
mat_blocks = compute_block_matrices(biforms,trials,tests) | ||
return BlockDiagonalSmoother(mat_blocks,solvers) | ||
end | ||
|
||
function BlockDiagonalSmoother(biforms :: AbstractArray{<:Function}, | ||
U :: Union{MultiFieldFESpace,GridapDistributed.DistributedMultiFieldFESpace}, | ||
V :: Union{MultiFieldFESpace,GridapDistributed.DistributedMultiFieldFESpace}, | ||
solvers :: AbstractArray{<:Gridap.Algebra.LinearSolver}) | ||
return BlockDiagonalSmoother(biforms,[U...],[V...],solvers) | ||
end | ||
|
||
function compute_block_matrices(biforms :: AbstractArray{<:Function}, | ||
trials :: AbstractArray{<:FESpace}, | ||
tests :: AbstractArray{<:FESpace}) | ||
@check length(biforms) == length(tests) == length(trials) | ||
mat_blocks = map(assemble_matrix,biforms,tests,trials) | ||
return mat_blocks | ||
end | ||
|
||
# Symbolic and numerical setup | ||
struct BlockDiagonalSmootherSS{A,B} <: Gridap.Algebra.SymbolicSetup | ||
solver :: A | ||
block_ss :: B | ||
end | ||
|
||
function Gridap.Algebra.symbolic_setup(solver::BlockDiagonalSmoother,mat::AbstractMatrix) | ||
block_ss = map(symbolic_setup,solver.solvers,solver.blocks) | ||
return BlockDiagonalSmootherSS(solver,block_ss) | ||
end | ||
|
||
struct BlockDiagonalSmootherNS{A,B} <: Gridap.Algebra.NumericalSetup | ||
solver :: A | ||
block_ns :: B | ||
end | ||
|
||
function Gridap.Algebra.numerical_setup(ss::BlockDiagonalSmootherSS,mat::AbstractMatrix) | ||
solver = ss.solver | ||
block_ns = map(numerical_setup,ss.block_ss,solver.blocks) | ||
return BlockDiagonalSmootherNS(solver,block_ns) | ||
end | ||
|
||
# Solve | ||
|
||
function Gridap.Algebra.solve!(x::AbstractBlockVector,ns::BlockDiagonalSmootherNS,b::AbstractBlockVector) | ||
@check blocklength(x) == blocklength(b) == length(ns.block_ns) | ||
for (iB,bns) in enumerate(ns.block_ns) | ||
xi = x[Block(iB)] | ||
bi = b[Block(iB)] | ||
solve!(xi,bns,bi) | ||
end | ||
return x | ||
end | ||
|
||
function LinearAlgebra.ldiv!(x,ns::BlockDiagonalSmootherNS,b) | ||
solve!(x,ns,b) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
|
||
# GMRES Solver | ||
struct GMRESSolver <: Gridap.Algebra.LinearSolver | ||
m ::Int | ||
Pl ::Gridap.Algebra.LinearSolver | ||
tol::Float64 | ||
end | ||
|
||
struct GMRESSymbolicSetup <: Gridap.Algebra.SymbolicSetup | ||
solver | ||
end | ||
|
||
function Gridap.Algebra.symbolic_setup(solver::GMRESSolver, A::AbstractMatrix) | ||
return GMRESSymbolicSetup(solver) | ||
end | ||
|
||
mutable struct GMRESNumericalSetup <: Gridap.Algebra.NumericalSetup | ||
solver | ||
A | ||
Pl_ns | ||
caches | ||
end | ||
|
||
function get_gmres_caches(m,A) | ||
w = allocate_col_vector(A) | ||
V = [allocate_col_vector(A) for i in 1:m+1] | ||
Z = [allocate_col_vector(A) for i in 1:m] | ||
|
||
H = zeros(m+1,m) # Hessenberg matrix | ||
g = zeros(m+1) # Residual vector | ||
c = zeros(m) # Gibens rotation cosines | ||
s = zeros(m) # Gibens rotation sines | ||
return (w,V,Z,H,g,c,s) | ||
end | ||
|
||
function Gridap.Algebra.numerical_setup(ss::GMRESSymbolicSetup, A::AbstractMatrix) | ||
solver = ss.solver | ||
Pl_ns = numerical_setup(symbolic_setup(solver.Pl,A),A) | ||
caches = get_gmres_caches(solver.m,A) | ||
return GMRESNumericalSetup(solver,A,Pl_ns,caches) | ||
end | ||
|
||
function Gridap.Algebra.numerical_setup!(ns::GMRESNumericalSetup, A::AbstractMatrix) | ||
numerical_setup!(ns.Pl_ns,A) | ||
ns.A = A | ||
end | ||
|
||
function Gridap.Algebra.solve!(x::AbstractVector,ns::GMRESNumericalSetup,b::AbstractVector) | ||
solver, A, Pl, caches = ns.solver, ns.A, ns.Pl_ns, ns.caches | ||
m, tol = solver.m, solver.tol | ||
w, V, Z, H, g, c, s = caches | ||
println(" > Starting GMRES solver: ") | ||
|
||
# Initial residual | ||
mul!(w,A,x); w .= b .- w | ||
|
||
β = norm(w) | ||
iter = 0 | ||
while (β > tol) | ||
println(" > Iteration ", iter," - Residual: ", β) | ||
fill!(H,0.0) | ||
|
||
# Arnoldi process | ||
fill!(g,0.0); g[1] = β | ||
V[1] .= w ./ β | ||
j = 1 | ||
while ( j < m+1 && β > tol ) | ||
println(" > Inner iteration ", j," - Residual: ", β) | ||
# Arnoldi orthogonalization by Modified Gram-Schmidt | ||
solve!(Z[j],Pl,V[j]) | ||
mul!(w,A,Z[j]) | ||
for i in 1:j | ||
H[i,j] = dot(w,V[i]) | ||
w .= w .- H[i,j] .* V[i] | ||
end | ||
H[j+1,j] = norm(w) | ||
V[j+1] = w ./ H[j+1,j] | ||
|
||
# Update QR | ||
for i in 1:j-1 | ||
γ = c[i]*H[i,j] + s[i]*H[i+1,j] | ||
H[i+1,j] = -s[i]*H[i,j] + c[i]*H[i+1,j] | ||
H[i,j] = γ | ||
end | ||
|
||
# New Givens rotation, update QR and residual | ||
c[j], s[j], _ = LinearAlgebra.givensAlgorithm(H[j,j],H[j+1,j]) | ||
H[j,j] = c[j]*H[j,j] + s[j]*H[j+1,j]; H[j+1,j] = 0.0 | ||
g[j+1] = -s[j]*g[j]; g[j] = c[j]*g[j] | ||
|
||
β = abs(g[j+1]) | ||
j += 1 | ||
end | ||
j = j-1 | ||
|
||
# Solve least squares problem Hy = g by backward substitution | ||
for i in j:-1:1 | ||
g[i] = (g[i] - dot(H[i,i+1:j],g[i+1:j])) / H[i,i] | ||
end | ||
|
||
# Update solution & residual | ||
for i in 1:j | ||
x .+= g[i] .* Z[i] | ||
end | ||
mul!(w,A,x); w .= b .- w | ||
|
||
iter += 1 | ||
end | ||
println(" Exiting GMRES solver.") | ||
println(" > Num Iter: ", iter," - Final residual: ", β) | ||
|
||
return x | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
|
||
# Row/Col vector allocations for serial | ||
function allocate_row_vector(A::AbstractMatrix{T}) where T | ||
return zeros(T,size(A,1)) | ||
end | ||
|
||
function allocate_col_vector(A::AbstractMatrix{T}) where T | ||
return zeros(T,size(A,2)) | ||
end | ||
|
||
# Row/Col vector allocations for parallel | ||
function allocate_row_vector(A::PSparseMatrix) | ||
T = eltype(A) | ||
return pfill(zero(T),partition(axes(A,1))) | ||
end | ||
|
||
function allocate_col_vector(A::PSparseMatrix) | ||
T = eltype(A) | ||
return pfill(zero(T),partition(axes(A,2))) | ||
end | ||
|
||
# Row/Col vector allocations for blocks | ||
function allocate_row_vector(A::AbstractBlockMatrix) | ||
return mortar(map(Aii->allocate_row_vector(Aii),blocks(A)[:,1])) | ||
end | ||
|
||
function allocate_col_vector(A::AbstractBlockMatrix) | ||
return mortar(map(Aii->allocate_col_vector(Aii),blocks(A)[1,:])) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
|
||
# Identity solver, for testing purposes | ||
struct IdentitySolver <: Gridap.Algebra.LinearSolver | ||
end | ||
|
||
struct IdentitySymbolicSetup <: Gridap.Algebra.SymbolicSetup | ||
solver | ||
end | ||
|
||
function Gridap.Algebra.symbolic_setup(s::IdentitySolver,A::AbstractMatrix) | ||
IdentitySymbolicSetup(s) | ||
end | ||
|
||
struct IdentityNumericalSetup <: Gridap.Algebra.NumericalSetup | ||
solver | ||
end | ||
|
||
function Gridap.Algebra.numerical_setup(ss::IdentitySymbolicSetup,mat::AbstractMatrix) | ||
s = ss.solver | ||
return IdentityNumericalSetup(s) | ||
end | ||
|
||
function Gridap.Algebra.solve!(x::AbstractVector,ns::IdentityNumericalSetup,y::AbstractVector) | ||
copy!(x,y) | ||
return x | ||
end |
Oops, something went wrong.