KSP
The KSP (Krylov Subspace Methods) module provides iterative linear solvers for systems of the form Ax = b. PETSc offers a wide variety of Krylov methods and preconditioners.
Overview
KSP provides:
- Krylov methods: GMRES, CG, BiCGStab, and many more
- Preconditioners: Jacobi, ILU, multigrid, direct solvers, etc.
- Runtime configuration: Choose methods via command-line options
- Convergence monitoring: Built-in residual tracking
Creating a KSP Solver
From a Matrix
# Basic creation with default options. The communicator comes from `A`
ksp = KSP(A)
# With the preconditioner construction matrix P
ksp = KSP(A, P)
# With options
ksp = KSP(A;
ksp_type = "gmres",
pc_type = "ilu",
ksp_rtol = 1e-8
)From a DM
# Create KSP associated with a DM (for multigrid, etc.)
ksp = KSP(dm;
ksp_type = "cg",
pc_type = "mg"
)When the options apply
The keyword options of KSP, SNES and TS are applied through XSetFromOptions, and options_at says when:
options_at | Applied | Default for |
|---|---|---|
:construction | in the constructor, once | KSP |
:each_solve | at the start of every solve! | SNES, TS |
:first_solve | once, at the first setup! or solve! (or step! for a TS) |
The order matters because a setting made in code and an option for the same thing overwrite each other, and the later one wins. Under :each_solve, pc_type = "ilu" replaces a set_type!(pc(ksp), :jacobi) made before every solve. Under :construction, the options are read before anything set up after the constructor. :first_solve waits until the solver is complete and then reads them once:
ksp = KSP(dm; options_at = :first_solve, pc_type = "mg")
PETSc.set_dm_active!(ksp, false) # the DM gives multigrid its hierarchy only
PETSc.set_operators!(ksp, J)
PETSc.solve!(x, ksp, b) # options applied here, and not againWhile a solver runs, its options stay pushed on PETSc's options stack, so sub-solvers PETSc creates during setup (the splits of a fieldsplit, the levels of a multigrid) read them too. PETSc.with_options does the same around any other code: with_options(ksp) do ... end.
From a Sparse Matrix
# Directly from Julia SparseMatrixCSC
using SparseArrays
S = sprand(100, 100, 0.1) + 10I
ksp = KSP(petsclib, MPI.COMM_SELF, S)Solving
# Solve Ax = b, writing into x. The written vector comes first
PETSc.solve!(x, ksp, b)
# `ldiv!` and `\` are the LinearAlgebra spellings of the same call
using LinearAlgebra
ldiv!(x, ksp, b)
x = ksp \ b
# What PETSc did
PETSc.type_name(ksp) # :gmres, a Symbol
PETSc.converged_reason(ksp) # positive when it converged
PETSc.iteration_number(ksp)
PETSc.destroy!(ksp)KSP is the type, not a factory function: ksp isa PETSc.KSP holds, and PETSc.dm(ksp) hands back the DM it was built on as a borrowed handle — destroy! on it is a no-op (naming conventions, §3.3).
Type names are Symbol at the Julia API: PETSc.set_type!(ksp, :cg) and PETSc.type_name(ksp) === :cg. The String spelling warns in v0.5 and is a MethodError in v0.6 (§3.1).
A nested solver
An inner solve, such as the Schur complement solve inside a preconditioner, starts from a bare KSP and an assembled operator. An options prefix keeps its options apart from the outer solver's:
inner = LibPETSc.KSPCreate(petsclib, comm)
PETSc.set_operators!(inner, S) # S also builds the preconditioner; pass P to differ
PETSc.set_options_prefix!(inner, "schur_") # reads -schur_ksp_type, -schur_pc_type, ...
PETSc.set_from_options!(inner) # apply them now rather than at the first solve!
PETSc.solve!(y, inner, r)
PETSc.options_prefix(inner) # "schur_"A KSP built on a DM computes its operator, right-hand side and initial guess from it. PETSc.set_dm_active!(ksp, false) keeps the DM for its geometry (multigrid needs it) and takes the rest from set_operators! and solve!; PETSc.set_dm_active!(ksp, :rhs, false) switches off one part.
Common Solver/Preconditioner Options
Krylov Methods (ksp_type)
cg- Conjugate Gradient (symmetric positive definite)gmres- Generalized Minimum Residualbicgstab- BiConjugate Gradient Stabilizedrichardson- Richardson iterationpreonly- Apply preconditioner only (for direct solvers)
Preconditioners (pc_type)
jacobi- Diagonal scalingilu- Incomplete LU factorizationlu- Direct LU factorizationmg- Geometric multigridgamg- Algebraic multigridnone- No preconditioning
Convergence Options
ksp_rtol- Relative tolerance (default: 1e-5)ksp_atol- Absolute toleranceksp_max_it- Maximum iterationsksp_monitor- Print residual each iteration
Example: Multigrid Solver
ksp = KSP(dm;
ksp_type = "cg",
pc_type = "mg",
pc_mg_levels = 4,
pc_mg_galerkin = true,
mg_levels_ksp_type = "richardson",
mg_levels_pc_type = "jacobi",
mg_coarse_pc_type = "lu"
)The preconditioner
PETSc.pc(ksp) hands back the preconditioner as a borrowed LibPETSc.PC. It takes the same set_type!/type_name pair as the solver, and is how a split preconditioner gets its index sets, which options alone cannot supply:
p = PETSc.pc(ksp) # not pc = pc(ksp), see naming.md §3.2
PETSc.set_type!(p, :fieldsplit)
PETSc.set_fieldsplit_is!(p, "u", is_u) # rows of the first split, 0-based
PETSc.set_fieldsplit_is!(p, "p", is_p) # options prefix -fieldsplit_p_
PETSc.type_name(p) # :fieldsplitA :shell preconditioner is written in Julia. The action writes into its first argument, like every other callback here:
p = PETSc.pc(ksp)
PETSc.set_type!(p, :shell)
PETSc.set_shell_setup!(p) do p
# rebuild whatever apply! needs, e.g. after the operator changed
end
PETSc.set_shell_apply!(p) do y, p, x
PETSc.with_local_array!(y, x; read = (false, true), write = (true, false)) do ya, xa
ya .= xa ./ diagonal # Jacobi, by hand
end
endThe closures are kept with the PETSc preconditioner, not with the wrapper p, so p can be dropped. An exception thrown inside either one comes out of the solve that ran it, as itself: a DomainError in apply! makes ksp \ b throw that DomainError (naming conventions, §18.4).
The solvers of a :fieldsplit's splits exist only once the preconditioner has been set up, inside the first solve. set_post_setup! runs a closure at the end of every setup, which is where to configure them:
PETSc.set_post_setup!(p) do p
_, subksps = LibPETSc.PCFieldSplitGetSubKSP(petsclib, p)
PETSc.set_type!(PETSc.pc(subksps[1]), :lu)
endIt runs again whenever the operator changes, and the options given to a SNES are applied again on every solve!, so write it so that a second run is harmless. With a Schur split, set the factorization type in code (LibPETSc.PCFieldSplitSetType) before LibPETSc.PCFieldSplitSetSchurPre with a user matrix: when the type comes only from the options, PETSc drops the user matrix without saying so. set_pre_solve! is the matching hook on the KSP; it runs at the start of every solve, before the preconditioner is set up.
A LibPETSc.PC is also what every low-level PC* function takes, so anything without a high-level verb is one call away: LibPETSc.PCFieldSplitSetType(petsclib, p, LibPETSc.PC_COMPOSITE_SCHUR).
Functions
PETSc.LibPETSc.KSP — Method
KSP(petsclib, comm::MPI.Comm, A::SparseMatrixCSC; options...)Create a KSP for the sparse matrix A, on comm, using the library petsclib. A is copied into a new PETSc matrix that the solver owns, so changing A afterwards does not change the solver. The keyword arguments are PETSc options, as for KSP(A::AbstractPetscMat; options...).
PETSc.LibPETSc.KSP — Method
KSP(dm::AbstractPetscDM; prefix = "", options_at = :construction, options...)Create a KSP associated with the dm with optional prefix and options.
options_at decides when the options are applied, through KSPSetFromOptions:
:construction(the default): here, once. A setting made in code afterwards, such asset_tolerances!, overrides them.:each_solve: at the start of everysolve!, so they override a setting made in code for the same option.:first_solve: once, at the firstsetup!orsolve!, after the DM and callbacks are attached.
The options stay pushed during solve!, and during setup! too unless options_at = :each_solve, so the sub-solvers PETSc creates during setup read them (see with_options).
The communicator is obtained from dm. The KSP can be used with geometric multigrid when the DM provides grid hierarchy information.
Arguments
dm::AbstractPetscDM: The DM object to associate with the KSPprefix::String: Optional prefix for command-line optionsoptions_at::Symbol: When the options are applied, see aboveoptions...: Additional PETSc options as keyword arguments
External Links
- PETSc Manual:
KSP/KSPCreate
- PETSc Manual:
KSP/KSPSetDM
- PETSc Manual:
KSP/KSPSetFromOptions
PETSc.LibPETSc.KSP — Method
KSP(A::AbstractPetscMat, P::AbstractPetscMat = A; prefix = "", options_at = :construction, options...)Create a KSP using the matrix A and preconditioner construction matrix P with optional prefix and options.
options_at decides when the options are applied, through KSPSetFromOptions:
:construction(the default): here, once. A setting made in code afterwards, such asset_tolerances!, overrides them.:each_solve: at the start of everysolve!, so they override a setting made in code for the same option.:first_solve: once, at the firstsetup!orsolve!, after the DM and callbacks are attached.
The options stay pushed during solve!, and during setup! too unless options_at = :each_solve, so the sub-solvers PETSc creates during setup read them (see with_options).
The communicator is obtained from A and if it has size 1 then the garbage collector is set, otherwise the user is responsible for calling destroy!.
External Links
- PETSc Manual:
KSP/KSPCreate
- PETSc Manual:
KSP/KSPSetOperators
- PETSc Manual:
KSP/KSPSetFromOptions
PETSc.converged_reason — Method
converged_reason(ksp::AbstractKSP)Why the last solve! stopped, as a LibPETSc.KSPConvergedReason: positive when it converged, negative when it diverged.
External Links
- PETSc Manual:
KSP/KSPGetConvergedReason
PETSc.destroy! — Method
destroy!(ksp::KSP)Destroy the solver ksp holds. Does nothing on a borrowed handle, such as the one ksp(ts) hands back: see owns.
External Links
- PETSc Manual:
KSP/KSPDestroy
PETSc.dm — Method
dm(ksp::AbstractKSP)The DM attached to ksp, narrowed to its flavour.
The returned object is owned by the object it was asked of, not by the caller: it carries no finalizer and must not be destroyed. destroy! on it is a no-op (owns).
External Links
- PETSc Manual:
KSP/KSPGetDM
PETSc.iteration_number — Method
iteration_number(ksp::AbstractKSP)The number of iterations the last solve! took.
External Links
- PETSc Manual:
KSP/KSPGetIterationNumber
PETSc.set_compute_operators! — Function
set_compute_operators!(ops!::Function, ksp::KSP)Define ops! to be the compute operators function for the ksp. A call to ops!(A, P, new_ksp) should set the elements of the PETSc matrix linear operator A and preconditioning matrix P based on the new_ksp.
The closure is kept with the PETSc object, not with the wrapper passed here, so a borrowed handle is fine to pass. It succeeds by returning and fails by throwing; its return value is ignored, except that a nonzero Integer still fails the call and warns until v0.6. An exception it throws comes out of the solve!, step! or setup! that ran it.
External Links
- PETSc Manual:
KSP/KSPSetComputeOperators
The callback comes first (docs/src/man/naming.md §8.1), so do block syntax works. v0.4 also accepted the subject-first order; that method is gone in v0.5, and there is no shim for it (§16).
PETSc.set_compute_rhs! — Function
set_compute_rhs!(rhs!::Function, ksp::AbstractKSP)Define rhs! to be the right-hand side function of the ksp. A call to rhs!(b, new_ksp) should set the elements of the PETSc vector b based on the new_ksp.
The closure is kept with the PETSc object, not with the wrapper passed here, so a borrowed handle is fine to pass. It succeeds by returning and fails by throwing; its return value is ignored, except that a nonzero Integer still fails the call and warns until v0.6. An exception it throws comes out of the solve!, step! or setup! that ran it.
External Links
- PETSc Manual:
KSP/KSPSetComputeRHS
The callback comes first (docs/src/man/naming.md §8.1), so do block syntax works. v0.4 also accepted the subject-first order; that method is gone in v0.5, and there is no shim for it (§16).
PETSc.set_dm_active! — Method
set_dm_active!(ksp::AbstractKSP, flag::Bool)
set_dm_active!(ksp::AbstractKSP, part::Symbol, flag::Bool)Whether the DM attached to ksp computes its operator, right-hand side and initial guess. The first form sets all three; the second sets one, part being :operator, :rhs or :initial_guess (:all is the first form). With false, ksp keeps the DM for its geometry, for example for multigrid, while set_operators! and solve! supply the rest. Returns ksp.
External Links
- PETSc Manual:
KSP/KSPSetDMActive
PETSc.set_operators! — Method
set_operators!(ksp::AbstractKSP, A::AbstractPetscMat, P::AbstractPetscMat = A)Solve with the operator A, building the preconditioner from P. Returns ksp.
ksp takes a reference to both matrices, so they stay valid inside it after the caller destroys its own handles.
External Links
- PETSc Manual:
KSP/KSPSetOperators
PETSc.set_pre_solve! — Function
set_pre_solve!(pre_solve!, ksp::AbstractKSP)Call pre_solve!(ksp, b, x) at the start of every solve of ksp, before the first iteration. b is the right-hand side and x the initial guess, both borrowed. Returns ksp. A second call replaces the first callback.
It runs before the preconditioner is set up for that solve, so the parts of a composite preconditioner aren't configured yet. To change those, use set_post_setup! on the preconditioner.
The callback comes first (docs/src/man/naming.md §8.1), so do block syntax works.
The closure is kept with the PETSc object, not with the wrapper passed here, so a borrowed handle is fine to pass. It succeeds by returning and fails by throwing; its return value is ignored, except that a nonzero Integer still fails the call and warns until v0.6. An exception it throws comes out of the solve!, step! or setup! that ran it.
External Links
- PETSc Manual:
KSP/KSPSetPreSolve
PETSc.set_type! — Method
set_type!(ksp::AbstractKSP, type::Symbol)Set the Krylov method, for example :gmres, :cg or :preonly.
External Links
- PETSc Manual:
KSP/KSPSetType
PETSc.setup! — Method
setup!(ksp::AbstractKSP)Set up ksp and its preconditioner, as solve! does before its first solve, and return ksp. Call it to build the preconditioner at a controlled point, for example to time it, or to reach the sub-solvers of a fieldsplit before the first solve. Unless options_at = :each_solve, the constructor options are pushed meanwhile, and under :first_solve applied first (see KSP).
External Links
- PETSc Manual:
KSP/KSPSetUp
PETSc.solution — Method
solution(ksp::AbstractKSP)The solution vector of ksp, as a PetscVec.
The returned object is owned by the object it was asked of, not by the caller: it carries no finalizer and must not be destroyed. destroy! on it is a no-op (owns).
External Links
- PETSc Manual:
KSP/KSPGetSolution
PETSc.solve! — Method
solve!(x::PetscVec, ksp::KSP, b::PetscVec; check = nothing)
solve!(ksp::KSP; check = nothing)Solve the linear system of ksp for the right-hand side b into x, and return x. The second form uses the vectors set on ksp (for example by set_compute_rhs!) and returns ksp. The initial guess is zero unless -ksp_initial_guess_nonzero is set.
PETSc does not report a failed solve: x holds the last iterate and converged_reason says why it stopped. check decides what happens then:
check = truethrows aConvergenceError.check = falsereturns normally, and the caller readsconverged_reason.- Not passed, it returns normally and warns once per call site that from v0.6 a failed solve throws.
External Links
- PETSc Manual:
KSP/KSPSolve
- PETSc Manual:
KSP/KSPGetConvergedReason
PETSc.type_name — Method
type_name(ksp::AbstractKSP)The name PETSc knows this solver by, as a Symbol (:gmres, :cg, …), or nothing when no type has been set yet (docs/src/man/naming.md §3.1). v0.4 answered with a String; that is a break with no shim (§16).
External Links
- PETSc Manual:
KSP/KSPGetType
PETSc.destroy! — Method
destroy!(p::AbstractPC)Destroy the preconditioner p holds. Does nothing on the borrowed handle pc hands back, which its KSP destroys: see owns.
External Links
- PETSc Manual:
PC/PCDestroy
PETSc.pc — Method
pc(ksp::AbstractKSP)The preconditioner ksp applies. Inside the package, bind it as p = pc(ksp), not pc = pc(ksp) (docs/src/man/naming.md §3.2).
The returned object is owned by the object it was asked of, not by the caller: it carries no finalizer and must not be destroyed. destroy! on it is a no-op (owns).
External Links
- PETSc Manual:
KSP/KSPGetPC
PETSc.set_fieldsplit_is! — Method
set_fieldsplit_is!(p::AbstractPC, name::AbstractString, is::AbstractIS)Define the split called name of a :fieldsplit preconditioner as the rows listed in is, which holds global, 0-based indices. Call it once per split, in the order the splits should have; name is also the options prefix of the split's solver (-fieldsplit_<name>_ksp_type).
Throws an ArgumentError unless p is already of type :fieldsplit: PETSc would otherwise ignore the call without saying so.
External Links
- PETSc Manual:
PC/PCFieldSplitSetIS
PETSc.set_post_setup! — Function
set_post_setup!(post_setup!, p::AbstractPC)Call post_setup!(p) at the end of every PCSetUp of p, that is whenever PETSc sets the preconditioner up, for example after the operator changes. Returns p.
This is where to configure the parts of a composite preconditioner that only exist once it has been set up, such as the solvers of a :fieldsplit's splits (LibPETSc.PCFieldSplitGetSubKSP). The options are applied again on every solve!, so the callback can run more than once on the same objects: write it so that a second run is harmless.
A second call replaces the first callback. Any PC type works, unlike set_shell_setup!, which is the setup of a :shell preconditioner itself.
The callback comes first (docs/src/man/naming.md §8.1), so do block syntax works.
The closure is kept with the PETSc object, not with the wrapper passed here, so a borrowed handle is fine to pass. It succeeds by returning and fails by throwing; its return value is ignored, except that a nonzero Integer still fails the call and warns until v0.6. An exception it throws comes out of the solve!, step! or setup! that ran it.
External Links
- PETSc Manual:
PC/PCSetPostSetUp
PETSc.set_shell_apply! — Function
set_shell_apply!(apply!, p::AbstractPC)Make apply! the action of the :shell preconditioner p. It is called as apply!(y, p, x) and writes the preconditioned x into y. Returns p.
Throws an ArgumentError unless p is already of type :shell: PETSc would otherwise ignore the call without saying so.
The callback comes first (docs/src/man/naming.md §8.1), so do block syntax works.
The closure is kept with the PETSc object, not with the wrapper passed here, so a borrowed handle is fine to pass. It succeeds by returning and fails by throwing; its return value is ignored, except that a nonzero Integer still fails the call and warns until v0.6. An exception it throws comes out of the solve!, step! or setup! that ran it.
External Links
- PETSc Manual:
PC/PCShellSetApply
PETSc.set_shell_setup! — Function
set_shell_setup!(setup!, p::AbstractPC)Make setup! the setup step of the :shell preconditioner p, called as setup!(p) whenever PETSc sets the preconditioner up, for example after the operator changes. The :shell requirement is as for set_shell_apply!. Returns p.
The callback comes first (docs/src/man/naming.md §8.1), so do block syntax works.
The closure is kept with the PETSc object, not with the wrapper passed here, so a borrowed handle is fine to pass. It succeeds by returning and fails by throwing; its return value is ignored, except that a nonzero Integer still fails the call and warns until v0.6. An exception it throws comes out of the solve!, step! or setup! that ran it.
External Links
- PETSc Manual:
PC/PCShellSetSetUp
PETSc.set_type! — Method
set_type!(p::AbstractPC, type::Symbol)Set the preconditioner, for example :jacobi, :ilu, :gamg or :fieldsplit.
External Links
- PETSc Manual:
PC/PCSetType
PETSc.type_name — Method
type_name(p::AbstractPC)The name PETSc knows this preconditioner by, as a Symbol (:jacobi, :ilu, :fieldsplit, …), or nothing when no type has been set yet.
External Links
- PETSc Manual:
PC/PCGetType