@@ -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