mirror of https://github.com/fredrikekre/HYPRE.jl
Julia interface to hypre linear solvers (https://github.com/hypre-space/hypre)
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
568 lines
18 KiB
568 lines
18 KiB
# SPDX-License-Identifier: MIT |
|
|
|
""" |
|
HYPRESolver |
|
|
|
Abstract super type of all the wrapped HYPRE solvers. |
|
""" |
|
abstract type HYPRESolver end |
|
|
|
function Internals.safe_finalizer(Destroy, solver) |
|
# Add the solver to object tracker for possible atexit finalizing |
|
push!(Internals.HYPRE_OBJECTS, solver => nothing) |
|
# Add a finalizer that only calls Destroy if pointer not C_NULL |
|
finalizer(solver) do s |
|
if s.solver != C_NULL |
|
Destroy(s) |
|
s.solver = C_NULL |
|
end |
|
end |
|
end |
|
|
|
# Defining unsafe_convert enables ccall to automatically convert solver::HYPRESolver to |
|
# HYPRE_Solver while also making sure solver won't be GC'd and finalized. |
|
Base.unsafe_convert(::Type{HYPRE_Solver}, solver::HYPRESolver) = solver.solver |
|
|
|
# Fallback for the solvers that doesn't have required defaults |
|
Internals.set_precond_defaults(::HYPRESolver) = nothing |
|
|
|
# Generic fallback allocating a zero vector as initial guess |
|
# TODO: This should allocate x using the owned cols instead of rows of A/b, but currently |
|
# it is assumed these are always equivalent. |
|
""" |
|
solve(solver::HYPRESolver, A::HYPREMatrix, b::HYPREVector) -> HYPREVector |
|
|
|
Solve the linear system `A x = b` using `solver` and return the approximate solution. |
|
|
|
This method allocates an initial guess/output vector `x`, initialized to 0. |
|
|
|
See also [`solve!`](@ref). |
|
""" |
|
solve(solver::HYPRESolver, A::HYPREMatrix, b::HYPREVector) = solve!(solver, zero(b), A, b) |
|
|
|
""" |
|
solve!(solver::HYPRESolver, x::HYPREVector, A::HYPREMatrix, b::HYPREVector) |
|
|
|
Solve the linear system `A x = b` using `solver` with `x` as the initial guess. |
|
The approximate solution is stored in `x`. |
|
|
|
See also [`solve`](@ref). |
|
""" |
|
solve!(pcg::HYPRESolver, x::HYPREVector, A::HYPREMatrix, ::HYPREVector) |
|
|
|
|
|
###################################### |
|
# PartitionedArrays solver interface # |
|
###################################### |
|
|
|
# TODO: Would it be useful with a method that copied the solution to b instead? |
|
|
|
function solve(solver::HYPRESolver, A::PSparseMatrix, b::PVector) |
|
hypre_x = solve(solver, HYPREMatrix(A), HYPREVector(b)) |
|
x = copy!(similar(b, HYPRE_Complex), hypre_x) |
|
return x |
|
end |
|
function solve!(solver::HYPRESolver, x::PVector, A::PSparseMatrix, b::PVector) |
|
hypre_x = HYPREVector(x) |
|
solve!(solver, hypre_x, HYPREMatrix(A), HYPREVector(b)) |
|
copy!(x, hypre_x) |
|
return x |
|
end |
|
|
|
######################################## |
|
# SparseMatrixCS(C|R) solver interface # |
|
######################################## |
|
|
|
# TODO: This could use the HYPRE compile flag for sequential mode to avoid MPI overhead |
|
|
|
function solve(solver::HYPRESolver, A::Union{SparseMatrixCSC,SparseMatrixCSR}, b::Vector) |
|
hypre_x = solve(solver, HYPREMatrix(A), HYPREVector(b)) |
|
x = copy!(similar(b, HYPRE_Complex), hypre_x) |
|
return x |
|
end |
|
function solve!(solver::HYPRESolver, x::Vector, A::Union{SparseMatrixCSC,SparseMatrixCSR}, b::Vector) |
|
hypre_x = HYPREVector(x) |
|
solve!(solver, hypre_x, HYPREMatrix(A), HYPREVector(b)) |
|
copy!(x, hypre_x) |
|
return x |
|
end |
|
|
|
|
|
##################################### |
|
## Concrete solver implementations ## |
|
##################################### |
|
|
|
|
|
#################### |
|
# (ParCSR)BiCGSTAB # |
|
#################### |
|
|
|
""" |
|
BiCGSTAB(; settings...) |
|
|
|
Create a `BiCGSTAB` solver. See HYPRE API reference for details and supported settings. |
|
|
|
**External links** |
|
- [BiCGSTAB API reference](https://hypre.readthedocs.io/en/latest/api-sol-parcsr.html#breathe-section-title-parcsr-bicgstab-solver) |
|
""" |
|
mutable struct BiCGSTAB <: HYPRESolver |
|
comm::MPI.Comm |
|
solver::HYPRE_Solver |
|
precond::Union{HYPRESolver,Nothing} |
|
function BiCGSTAB(comm::MPI.Comm=MPI.COMM_NULL; kwargs...) |
|
# comm defaults to COMM_NULL since it is unused in HYPRE_ParCSRBiCGSTABCreate |
|
solver = new(comm, C_NULL, nothing) |
|
solver_ref = Ref{HYPRE_Solver}(C_NULL) |
|
@check HYPRE_ParCSRBiCGSTABCreate(comm, solver_ref) |
|
solver.solver = solver_ref[] |
|
# Attach a finalizer |
|
Internals.safe_finalizer(HYPRE_ParCSRBiCGSTABDestroy, solver) |
|
# Set the options |
|
Internals.set_options(solver, kwargs) |
|
return solver |
|
end |
|
end |
|
|
|
const ParCSRBiCGSTAB = BiCGSTAB |
|
|
|
function solve!(bicg::BiCGSTAB, x::HYPREVector, A::HYPREMatrix, b::HYPREVector) |
|
@check HYPRE_ParCSRBiCGSTABSetup(bicg, A, b, x) |
|
@check HYPRE_ParCSRBiCGSTABSolve(bicg, A, b, x) |
|
return x |
|
end |
|
|
|
Internals.setup_func(::BiCGSTAB) = HYPRE_ParCSRBiCGSTABSetup |
|
Internals.solve_func(::BiCGSTAB) = HYPRE_ParCSRBiCGSTABSolve |
|
|
|
function Internals.set_precond(bicg::BiCGSTAB, p::HYPRESolver) |
|
bicg.precond = p |
|
solve_f = Internals.solve_func(p) |
|
setup_f = Internals.setup_func(p) |
|
@check HYPRE_ParCSRBiCGSTABSetPrecond(bicg, solve_f, setup_f, p) |
|
return nothing |
|
end |
|
|
|
|
|
############# |
|
# BoomerAMG # |
|
############# |
|
|
|
""" |
|
BoomerAMG(; settings...) |
|
|
|
Create a `BoomerAMG` solver/preconditioner. See HYPRE API reference for details and |
|
supported settings. |
|
|
|
**External links** |
|
- [BoomerAMG documentation](https://hypre.readthedocs.io/en/latest/solvers-boomeramg.html) |
|
- [BoomerAMG API reference](https://hypre.readthedocs.io/en/latest/api-sol-parcsr.html#breathe-section-title-parcsr-boomeramg-solver-and-preconditioner) |
|
""" |
|
mutable struct BoomerAMG <: HYPRESolver |
|
solver::HYPRE_Solver |
|
function BoomerAMG(; kwargs...) |
|
solver = new(C_NULL) |
|
solver_ref = Ref{HYPRE_Solver}(C_NULL) |
|
@check HYPRE_BoomerAMGCreate(solver_ref) |
|
solver.solver = solver_ref[] |
|
# Attach a finalizer |
|
Internals.safe_finalizer(HYPRE_BoomerAMGDestroy, solver) |
|
# Set the options |
|
Internals.set_options(solver, kwargs) |
|
return solver |
|
end |
|
end |
|
|
|
function solve!(amg::BoomerAMG, x::HYPREVector, A::HYPREMatrix, b::HYPREVector) |
|
@check HYPRE_BoomerAMGSetup(amg, A, b, x) |
|
@check HYPRE_BoomerAMGSolve(amg, A, b, x) |
|
return x |
|
end |
|
|
|
Internals.setup_func(::BoomerAMG) = HYPRE_BoomerAMGSetup |
|
Internals.solve_func(::BoomerAMG) = HYPRE_BoomerAMGSolve |
|
|
|
function Internals.set_precond_defaults(amg::BoomerAMG) |
|
defaults = (; Tol = 0.0, MaxIter = 1) |
|
Internals.set_options(amg, pairs(defaults)) |
|
return nothing |
|
end |
|
|
|
|
|
############# |
|
# FlexGMRES # |
|
############# |
|
|
|
""" |
|
FlexGMRES(; settings...) |
|
|
|
Create a `FlexGMRES` solver. See HYPRE API reference for details and supported settings. |
|
|
|
**External links** |
|
- [FlexGMRES API reference](https://hypre.readthedocs.io/en/latest/api-sol-parcsr.html#breathe-section-title-parcsr-flexgmres-solver) |
|
""" |
|
mutable struct FlexGMRES <: HYPRESolver |
|
comm::MPI.Comm |
|
solver::HYPRE_Solver |
|
precond::Union{HYPRESolver,Nothing} |
|
function FlexGMRES(comm::MPI.Comm=MPI.COMM_NULL; kwargs...) |
|
# comm defaults to COMM_NULL since it is unused in HYPRE_ParCSRFlexGMRESCreate |
|
solver = new(comm, C_NULL, nothing) |
|
solver_ref = Ref{HYPRE_Solver}(C_NULL) |
|
@check HYPRE_ParCSRFlexGMRESCreate(comm, solver_ref) |
|
solver.solver = solver_ref[] |
|
# Attach a finalizer |
|
Internals.safe_finalizer(HYPRE_ParCSRFlexGMRESDestroy, solver) |
|
# Set the options |
|
Internals.set_options(solver, kwargs) |
|
return solver |
|
end |
|
end |
|
|
|
function solve!(flex::FlexGMRES, x::HYPREVector, A::HYPREMatrix, b::HYPREVector) |
|
@check HYPRE_ParCSRFlexGMRESSetup(flex, A, b, x) |
|
@check HYPRE_ParCSRFlexGMRESSolve(flex, A, b, x) |
|
return x |
|
end |
|
|
|
Internals.setup_func(::FlexGMRES) = HYPRE_ParCSRFlexGMRESSetup |
|
Internals.solve_func(::FlexGMRES) = HYPRE_ParCSRFlexGMRESSolve |
|
|
|
function Internals.set_precond(flex::FlexGMRES, p::HYPRESolver) |
|
flex.precond = p |
|
solve_f = Internals.solve_func(p) |
|
setup_f = Internals.setup_func(p) |
|
@check HYPRE_ParCSRFlexGMRESSetPrecond(flex, solve_f, setup_f, p) |
|
return nothing |
|
end |
|
|
|
|
|
######### |
|
## FSAI # |
|
######### |
|
|
|
# Requires version 2.25 |
|
|
|
#mutable struct FSAI <: HYPRESolver |
|
# solver::HYPRE_Solver |
|
# function FSAI(; kwargs...) |
|
# solver = new(C_NULL) |
|
# solver_ref = Ref{HYPRE_Solver}(C_NULL) |
|
# @check HYPRE_FSAICreate(solver_ref) |
|
# solver.solver = solver_ref[] |
|
# # Attach a finalizer |
|
# finalizer(x -> HYPRE_FSAIDestroy(x.solver), solver) |
|
# # Set the options |
|
# Internals.set_options(solver, kwargs) |
|
# return solver |
|
# end |
|
#end |
|
|
|
#function solve!(fsai::FSAI, x::HYPREVector, A::HYPREMatrix, b::HYPREVector) |
|
# @check HYPRE_FSAISetup(fsai, A, b, x) |
|
# @check HYPRE_FSAISolve(fsai, A, b, x) |
|
# return x |
|
#end |
|
|
|
#Internals.setup_func(::FSAI) = HYPRE_FSAISetup |
|
#Internals.solve_func(::FSAI) = HYPRE_FSAISolve |
|
|
|
#function Internals.set_precond_defaults(fsai::FSAI) |
|
# defaults = (; Tolerance = 0.0) |
|
# Internals.set_options(fsai, pairs(defaults)) |
|
# return nothing |
|
#end |
|
|
|
|
|
######### |
|
# GMRES # |
|
######### |
|
|
|
""" |
|
GMRES(; settings...) |
|
|
|
Create a `GMRES` solver. See HYPRE API reference for details and supported settings. |
|
|
|
**External links** |
|
- [GMRES API reference](https://hypre.readthedocs.io/en/latest/api-sol-parcsr.html#breathe-section-title-parcsr-gmres-solver) |
|
""" |
|
mutable struct GMRES <: HYPRESolver |
|
comm::MPI.Comm |
|
solver::HYPRE_Solver |
|
precond::Union{HYPRESolver,Nothing} |
|
function GMRES(comm::MPI.Comm=MPI.COMM_NULL; kwargs...) |
|
# comm defaults to COMM_NULL since it is unused in HYPRE_ParCSRGMRESCreate |
|
solver = new(comm, C_NULL, nothing) |
|
solver_ref = Ref{HYPRE_Solver}(C_NULL) |
|
@check HYPRE_ParCSRGMRESCreate(comm, solver_ref) |
|
solver.solver = solver_ref[] |
|
# Attach a finalizer |
|
Internals.safe_finalizer(HYPRE_ParCSRGMRESDestroy, solver) |
|
# Set the options |
|
Internals.set_options(solver, kwargs) |
|
return solver |
|
end |
|
end |
|
|
|
function solve!(gmres::GMRES, x::HYPREVector, A::HYPREMatrix, b::HYPREVector) |
|
@check HYPRE_ParCSRGMRESSetup(gmres, A, b, x) |
|
@check HYPRE_ParCSRGMRESSolve(gmres, A, b, x) |
|
return x |
|
end |
|
|
|
Internals.setup_func(::GMRES) = HYPRE_ParCSRGMRESSetup |
|
Internals.solve_func(::GMRES) = HYPRE_ParCSRGMRESSolve |
|
|
|
function Internals.set_precond(gmres::GMRES, p::HYPRESolver) |
|
gmres.precond = p |
|
solve_f = Internals.solve_func(p) |
|
setup_f = Internals.setup_func(p) |
|
@check HYPRE_ParCSRGMRESSetPrecond(gmres, solve_f, setup_f, p) |
|
return nothing |
|
end |
|
|
|
|
|
########## |
|
# Hybrid # |
|
########## |
|
|
|
""" |
|
Hybrid(; settings...) |
|
|
|
Create a `Hybrid` solver. See HYPRE API reference for details and supported settings. |
|
|
|
**External links** |
|
- [Hybrid documentation](https://hypre.readthedocs.io/en/latest/solvers-hybrid.html) |
|
- [Hybrid API reference](https://hypre.readthedocs.io/en/latest/api-sol-parcsr.html#breathe-section-title-parcsr-hybrid-solver) |
|
""" |
|
mutable struct Hybrid <: HYPRESolver |
|
solver::HYPRE_Solver |
|
precond::Union{HYPRESolver,Nothing} |
|
function Hybrid(; kwargs...) |
|
solver = new(C_NULL, nothing) |
|
solver_ref = Ref{HYPRE_Solver}(C_NULL) |
|
@check HYPRE_ParCSRHybridCreate(solver_ref) |
|
solver.solver = solver_ref[] |
|
# Attach a finalizer |
|
Internals.safe_finalizer(HYPRE_ParCSRHybridDestroy, solver) |
|
# Set the options |
|
Internals.set_options(solver, kwargs) |
|
return solver |
|
end |
|
end |
|
|
|
function solve!(hybrid::Hybrid, x::HYPREVector, A::HYPREMatrix, b::HYPREVector) |
|
@check HYPRE_ParCSRHybridSetup(hybrid, A, b, x) |
|
@check HYPRE_ParCSRHybridSolve(hybrid, A, b, x) |
|
return x |
|
end |
|
|
|
Internals.setup_func(::Hybrid) = HYPRE_ParCSRHybridSetup |
|
Internals.solve_func(::Hybrid) = HYPRE_ParCSRHybridSolve |
|
|
|
function Internals.set_precond(hybrid::Hybrid, p::HYPRESolver) |
|
hybrid.precond = p |
|
solve_f = Internals.solve_func(p) |
|
setup_f = Internals.setup_func(p) |
|
# Deactivate the finalizer of p since the HYBRIDDestroy function does this, |
|
# see https://github.com/hypre-space/hypre/issues/699 |
|
finalizer(x -> (x.solver = C_NULL), p) |
|
@check HYPRE_ParCSRHybridSetPrecond(hybrid, solve_f, setup_f, p) |
|
return nothing |
|
end |
|
|
|
|
|
####### |
|
# ILU # |
|
####### |
|
|
|
""" |
|
ILU(; settings...) |
|
|
|
Create a `ILU` solver/preconditioner. See HYPRE API reference for details and supported |
|
settings. |
|
|
|
**External links** |
|
- [ILU documentation](https://hypre.readthedocs.io/en/latest/solvers-hypre-ilu.html) |
|
- [ILU API reference](https://hypre.readthedocs.io/en/latest/api-sol-parcsr.html#breathe-section-title-parcsr-ilu-solver) |
|
""" |
|
mutable struct ILU <: HYPRESolver |
|
solver::HYPRE_Solver |
|
function ILU(; kwargs...) |
|
solver = new(C_NULL) |
|
solver_ref = Ref{HYPRE_Solver}(C_NULL) |
|
@check HYPRE_ILUCreate(solver_ref) |
|
solver.solver = solver_ref[] |
|
# Attach a finalizer |
|
Internals.safe_finalizer(HYPRE_ILUDestroy, solver) |
|
# Set the options |
|
Internals.set_options(solver, kwargs) |
|
return solver |
|
end |
|
end |
|
|
|
function solve!(ilu::ILU, x::HYPREVector, A::HYPREMatrix, b::HYPREVector) |
|
@check HYPRE_ILUSetup(ilu, A, b, x) |
|
@check HYPRE_ILUSolve(ilu, A, b, x) |
|
return x |
|
end |
|
|
|
Internals.setup_func(::ILU) = HYPRE_ILUSetup |
|
Internals.solve_func(::ILU) = HYPRE_ILUSolve |
|
|
|
function Internals.set_precond_defaults(ilu::ILU) |
|
defaults = (; Tol = 0.0, MaxIter = 1) |
|
Internals.set_options(ilu, pairs(defaults)) |
|
return nothing |
|
end |
|
|
|
|
|
##################### |
|
# (ParCSR)ParaSails # |
|
##################### |
|
|
|
""" |
|
ParaSails(comm=MPI.COMM_WORLD; settings...) |
|
|
|
Create a `ParaSails` preconditioner. See HYPRE API reference for details and supported |
|
settings. |
|
|
|
**External links** |
|
- [ParaSails documentation](https://hypre.readthedocs.io/en/latest/solvers-parasails.html) |
|
- [ParaSails API reference](https://hypre.readthedocs.io/en/latest/api-sol-parcsr.html#breathe-section-title-parcsr-parasails-preconditioner) |
|
""" |
|
mutable struct ParaSails <: HYPRESolver |
|
comm::MPI.Comm |
|
solver::HYPRE_Solver |
|
function ParaSails(comm::MPI.Comm=MPI.COMM_WORLD; kwargs...) |
|
# Note: comm is used in this solver so default to COMM_WORLD |
|
solver = new(comm, C_NULL) |
|
solver_ref = Ref{HYPRE_Solver}(C_NULL) |
|
@check HYPRE_ParCSRParaSailsCreate(comm, solver_ref) |
|
solver.solver = solver_ref[] |
|
# Attach a finalizer |
|
Internals.safe_finalizer(HYPRE_ParCSRParaSailsDestroy, solver) |
|
# Set the options |
|
Internals.set_options(solver, kwargs) |
|
return solver |
|
end |
|
end |
|
|
|
const ParCSRParaSails = ParaSails |
|
|
|
Internals.setup_func(::ParaSails) = HYPRE_ParCSRParaSailsSetup |
|
Internals.solve_func(::ParaSails) = HYPRE_ParCSRParaSailsSolve |
|
|
|
|
|
############### |
|
# (ParCSR)PCG # |
|
############### |
|
|
|
""" |
|
PCG(; settings...) |
|
|
|
Create a `PCG` solver. See HYPRE API reference for details and supported settings. |
|
|
|
**External links** |
|
- [PCG API reference](https://hypre.readthedocs.io/en/latest/api-sol-parcsr.html#breathe-section-title-parcsr-pcg-solver) |
|
""" |
|
mutable struct PCG <: HYPRESolver |
|
comm::MPI.Comm |
|
solver::HYPRE_Solver |
|
precond::Union{HYPRESolver, Nothing} |
|
function PCG(comm::MPI.Comm=MPI.COMM_NULL; kwargs...) |
|
# comm defaults to COMM_NULL since it is unused in HYPRE_ParCSRPCGCreate |
|
solver = new(comm, C_NULL, nothing) |
|
solver_ref = Ref{HYPRE_Solver}(C_NULL) |
|
@check HYPRE_ParCSRPCGCreate(comm, solver_ref) |
|
solver.solver = solver_ref[] |
|
# Attach a finalizer |
|
Internals.safe_finalizer(HYPRE_ParCSRPCGDestroy, solver) |
|
# Set the options |
|
Internals.set_options(solver, kwargs) |
|
return solver |
|
end |
|
end |
|
|
|
const ParCSRPCG = PCG |
|
|
|
function solve!(pcg::PCG, x::HYPREVector, A::HYPREMatrix, b::HYPREVector) |
|
@check HYPRE_ParCSRPCGSetup(pcg, A, b, x) |
|
@check HYPRE_ParCSRPCGSolve(pcg, A, b, x) |
|
return x |
|
end |
|
|
|
Internals.setup_func(::PCG) = HYPRE_ParCSRPCGSetup |
|
Internals.solve_func(::PCG) = HYPRE_ParCSRPCGSolve |
|
|
|
function Internals.set_precond(pcg::PCG, p::HYPRESolver) |
|
pcg.precond = p |
|
solve_f = Internals.solve_func(p) |
|
setup_f = Internals.setup_func(p) |
|
@check HYPRE_ParCSRPCGSetPrecond(pcg, solve_f, setup_f, p) |
|
return nothing |
|
end |
|
|
|
|
|
########################################################## |
|
# Extracting information about the solution from solvers # |
|
########################################################## |
|
|
|
""" |
|
HYPRE.GetFinalRelativeResidualNorm(s::HYPRESolver) |
|
|
|
Return the final relative residual norm from the last solve with solver `s`. |
|
|
|
This function dispatches on the solver to the corresponding C API wrapper |
|
`LibHYPRE.HYPRE_\$(Solver)GetFinalRelativeResidualNorm`. |
|
""" |
|
function GetFinalRelativeResidualNorm(s::HYPRESolver) |
|
r = Ref{HYPRE_Real}() |
|
if s isa BiCGSTAB |
|
@check HYPRE_ParCSRBiCGSTABGetFinalRelativeResidualNorm(s, r) |
|
elseif s isa BoomerAMG |
|
@check HYPRE_BoomerAMGGetFinalRelativeResidualNorm(s, r) |
|
elseif s isa FlexGMRES |
|
@check HYPRE_ParCSRFlexGMRESGetFinalRelativeResidualNorm(s, r) |
|
elseif s isa GMRES |
|
@check HYPRE_ParCSRGMRESGetFinalRelativeResidualNorm(s, r) |
|
elseif s isa Hybrid |
|
@check HYPRE_ParCSRHybridGetFinalRelativeResidualNorm(s, r) |
|
elseif s isa ILU |
|
@check HYPRE_ILUGetFinalRelativeResidualNorm(s, r) |
|
elseif s isa PCG |
|
@check HYPRE_ParCSRPCGGetFinalRelativeResidualNorm(s, r) |
|
else |
|
throw(ArgumentError("cannot get residual norm for $(typeof(s))")) |
|
end |
|
return r[] |
|
end |
|
|
|
""" |
|
HYPRE.GetNumIterations(s::HYPRESolver) |
|
|
|
Return number of iterations during the last solve with solver `s`. |
|
|
|
This function dispatches on the solver to the corresponding C API wrapper |
|
`LibHYPRE.HYPRE_\$(Solver)GetNumIterations`. |
|
""" |
|
function GetNumIterations(s::HYPRESolver) |
|
r = Ref{HYPRE_Int}() |
|
if s isa BiCGSTAB |
|
@check HYPRE_ParCSRBiCGSTABGetNumIterations(s, r) |
|
elseif s isa BoomerAMG |
|
@check HYPRE_BoomerAMGGetNumIterations(s, r) |
|
elseif s isa FlexGMRES |
|
@check HYPRE_ParCSRFlexGMRESGetNumIterations(s, r) |
|
elseif s isa GMRES |
|
@check HYPRE_ParCSRGMRESGetNumIterations(s, r) |
|
elseif s isa Hybrid |
|
@check HYPRE_ParCSRHybridGetNumIterations(s, r) |
|
elseif s isa ILU |
|
@check HYPRE_ILUGetNumIterations(s, r) |
|
elseif s isa PCG |
|
@check HYPRE_ParCSRPCGGetNumIterations(s, r) |
|
else |
|
throw(ArgumentError("cannot get number of iterations for $(typeof(s))")) |
|
end |
|
return r[] |
|
end
|
|
|