Skip to content

Commit f2d9ba5

Browse files
authored
make gmres more robust for singular operators (#153)
1 parent ea36dd4 commit f2d9ba5

1 file changed

Lines changed: 22 additions & 9 deletions

File tree

src/linsolve/gmres.jl

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ function linsolve(operator, b, x₀, alg::GMRES, a₀::Number = 0, a₁::Number
5252
lmul!(gs[1], y)
5353
β = convert(S, abs(y[2]))
5454

55-
while> tol && length(fact) < krylovdim) # inner arnoldi loop
55+
while (!iszero(R[k, k]) && β > tol && length(fact) < krylovdim) # inner arnoldi loop
5656
if alg.verbosity >= EACHITERATION_LEVEL
5757
@info "GMRES linsolve in iteration $numiter; step $k: normres = $(normres2string(β))"
5858
end
@@ -69,32 +69,45 @@ function linsolve(operator, b, x₀, alg::GMRES, a₀::Number = 0, a₁::Number
6969
R[k, k] = α₀ + α₁ * H[k, k]
7070
end
7171

72-
# Apply Givens rotations
72+
# Apply old Givens rotations
7373
Rk = view(R, :, k)
7474
@inbounds for i in 1:(k - 1)
7575
lmul!(gs[i], Rk)
7676
end
77-
gs[k], R[k, k] = givens(R[k, k], α₁ * normres(fact), k, k + 1)
7877

79-
# Apply Givens rotations to right hand side
80-
y[k + 1] = zero(T)
81-
lmul!(gs[k], y)
78+
# Compute new Givens rotations for final row and also apply to right hand side
79+
if hypot(R[k, k], α₁ * normres(fact)) < tol
80+
if alg.verbosity >= WARN_LEVEL
81+
@warn "GMRES linsolve in iteration $numiter; step $k: linear operator is singular in Krylov subspace"
82+
end
83+
# rotate all the weight into y[k + 1]
84+
gs[k], y[k + 1] = givens(zero(T), y[k], k + 1, k)
85+
y[k] = zero(T)
86+
R[k, k] = zero(T)
87+
else
88+
gs[k], R[k, k] = givens(R[k, k], α₁ * normres(fact), k, k + 1)
89+
y[k + 1] = zero(T)
90+
lmul!(gs[k], y)
91+
end
8292

8393
# New error
8494
β = convert(S, abs(y[k + 1]))
8595
end
8696

8797
# Solve upper triangular system
88-
y2 = copy(y)
89-
ldiv!(UpperTriangular(R), y, 1:k)
98+
if iszero(R[k, k]) && iszero(y[k])
99+
ldiv!(UpperTriangular(R), y, 1:(k - 1))
100+
else
101+
ldiv!(UpperTriangular(R), y, 1:k)
102+
end
90103

91104
# Update x
92105
V = basis(fact)
93106
@inbounds for i in 1:k
94107
x = add!!(x, V[i], y[i])
95108
end
96109

97-
if β > tol
110+
if β > tol && numiter < maxiter
98111
# Recompute residual without reevaluating operator
99112
w = residual(fact)
100113
push!(V, scale!!(w, 1 / normres(fact)))

0 commit comments

Comments
 (0)