Skip to content

Commit 0557a96

Browse files
committed
add docs and more tests
1 parent 2fb123b commit 0557a96

2 files changed

Lines changed: 384 additions & 0 deletions

File tree

docs/src/solvers/solvers.md

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,187 @@ GinkgoJL_CG
375375
GinkgoJL_GMRES
376376
```
377377

378+
### PETSc.jl
379+
380+
!!! note
381+
382+
Using this solver requires loading PETSc.jl and MPI.jl, and initialising MPI:
383+
```julia
384+
using PETSc, MPI, SparseMatricesCSR # SparseMatricesCSR is optional but recommended for best performance
385+
MPI.Init()
386+
```
387+
388+
!!! warning "Serial only"
389+
390+
The current implementation supports only **single-process** solves (`MPI.COMM_SELF`).
391+
Passing a multi-rank communicator will raise an error. MPI-parallel support is planned
392+
for a future release.
393+
394+
`PETScAlgorithm` wraps PETSc's KSP (Krylov subspace) solvers and exposes the full PETSc
395+
preconditioner interface using [PETSc.jl](https://github.com/JuliaParallel/PETSc.jl). It works with **dense matrices**, **`SparseMatrixCSC`**, and
396+
**`SparseMatrixCSR`** (from [SparseMatricesCSR.jl](https://github.com/gridap/SparseMatricesCSR.jl)).
397+
398+
#### Solver type
399+
400+
The first positional argument selects the KSP algorithm. Any string accepted by
401+
[`KSPSetType`](https://petsc.org/release/manualpages/KSP/KSPSetType/) can be passed as a `Symbol`.
402+
The most commonly used options are:
403+
404+
| Symbol | Method | Notes |
405+
| :--- | :--- | :--- |
406+
| `:gmres` (default) | GMRES | General non-symmetric systems |
407+
| `:fgmres` | Flexible GMRES | Allows variable preconditioner |
408+
| `:lgmres` | LGMRES | Augmented GMRES, better for restarting |
409+
| `:cg` | Conjugate Gradient | SPD systems only |
410+
| `:fcg` | Flexible CG | CG with variable preconditioner |
411+
| `:minres` | MINRES | Symmetric indefinite systems |
412+
| `:symmlq` | SYMMLQ | Symmetric indefinite systems |
413+
| `:bcgs` | BiCGStab | Non-symmetric, more stable than BiCG |
414+
| `:fbcgs` | Flexible BiCGStab | BiCGStab with variable preconditioner |
415+
| `:bcgsl` | BiCGStab(ℓ) | Stabilised BiCGStab variant |
416+
| `:bicg` | BiConjugate Gradient | Non-symmetric |
417+
| `:cgs` | CGS | Non-symmetric, faster but less stable |
418+
| `:tfqmr` | TFQMR | Transpose-free QMR |
419+
| `:tcqmr` | TCQMR | Transpose-free QMR variant |
420+
| `:cr` | Conjugate Residuals | Symmetric systems |
421+
| `:gcr` | GCR | Generalized CR, flexible preconditioner |
422+
| `:chebyshev` | Chebyshev iteration | Requires eigenvalue bounds; good for smoothing |
423+
| `:richardson` | Richardson iteration | Stationary; mainly used as smoother |
424+
| `:lsqr` | LSQR | Least-squares problems |
425+
| `:cgls` | CGLS | Least-squares problems |
426+
| `:preonly` | Preconditioner only | Use with `:lu` for a direct solve |
427+
| `:none` | No solver | Identity; useful for debugging |
428+
429+
#### Preconditioners
430+
431+
Preconditioners are selected via the `pc_type` keyword. Any string accepted by
432+
[`PCSetType`](https://petsc.org/release/manualpages/PC/PCSetType/) can be passed as a `Symbol`.
433+
The most commonly used options are:
434+
435+
| Symbol | Preconditioner | Notes |
436+
| :--- | :--- | :--- |
437+
| `:none` (default) | No preconditioner | Useful for well-conditioned problems |
438+
| `:jacobi` | Diagonal (Jacobi) scaling | Cheap; good for diagonally dominant systems |
439+
| `:pbjacobi` | Point Block Jacobi | Fixed-size dense blocks along the diagonal |
440+
| `:sor` | SOR / Gauss-Seidel | Successive over-relaxation |
441+
| `:eisenstat` | Eisenstat SSOR | Symmetric SOR; cheaper than a full SSOR sweep |
442+
| `:ilu` | Incomplete LU | General sparse systems |
443+
| `:icc` | Incomplete Cholesky | SPD systems; symmetric analogue of ILU |
444+
| `:lu` | Exact LU (direct) | Use with `:preonly` for a direct solve |
445+
| `:cholesky` | Exact Cholesky (direct) | SPD systems; use with `:preonly` |
446+
| `:bjacobi` | Block Jacobi | Applies an independent ILU/LU solve per block |
447+
| `:asm` | Additive Schwarz | Overlapping domain decomposition |
448+
| `:gasm` | Generalized Additive Schwarz | Multi-level ASM variant |
449+
| `:gamg` | Algebraic Multigrid (GAMG) | No hierarchy needed; good for PDEs |
450+
| `:hypre` | Hypre BoomerAMG | Excellent AMG for large ill-conditioned systems |
451+
| `:kaczmarz` | Kaczmarz | Row-projection smoother |
452+
453+
A separate matrix for building the preconditioner can be supplied via `prec_matrix`:
454+
455+
```julia
456+
PETScAlgorithm(:gmres; prec_matrix = P)
457+
```
458+
459+
#### Matrix format recommendations
460+
461+
PETSc operates internally on 0-based CSR arrays. The recommended matrix format is
462+
**`SparseMatrixCSR{0}`** (from SparseMatricesCSR.jl), which matches PETSc's native layout
463+
exactly:
464+
465+
- **`SparseMatrixCSR{0}`***fastest*: zero-copy path on construction; direct `copyto!`
466+
on value-only updates.
467+
- **`SparseMatrixCSR{1}`** — slightly slower than `{0}` on construction (index shift on
468+
cold start), same fast value-update path.
469+
- **`SparseMatrixCSC`** — supported, but requires a CSC→CSR permutation and scatter on
470+
every value update.
471+
- **Dense `Matrix`** — supported via `MatSeqDense`; works out of the box.
472+
473+
```julia
474+
using SparseMatricesCSR, SparseArrays
475+
476+
A_csc = spdiagm(-1 => -ones(n-1), 0 => 2ones(n), 1 => -ones(n-1))
477+
478+
# Recommended: one-liner to build SparseMatrixCSR{0} from a CSC matrix.
479+
# Note: this mutates A_csc's internal storage (colptr/rowvals are shifted in-place).
480+
# Use a copy if you need to keep A_csc usable afterwards.
481+
A = SparseMatrixCSR{0}(transpose(sparse(transpose(A_csc))))
482+
```
483+
484+
#### Basic usage
485+
486+
```julia
487+
using LinearSolve, PETSc, MPI, SparseArrays, LinearAlgebra
488+
MPI.Init()
489+
490+
n = 200
491+
A = sprand(n, n, 0.05); A = A + A' + 20I
492+
b = rand(n)
493+
494+
# Simple one-shot solve with ILU preconditioner
495+
sol = solve(LinearProblem(A, b), PETScAlgorithm(:gmres; pc_type = :ilu))
496+
@show norm(A * sol.u - b) / norm(b)
497+
```
498+
499+
#### Repeated solves (same sparsity pattern, values change)
500+
501+
When the sparsity pattern is fixed across calls,
502+
the KSP is reused and only the matrix values are updated.
503+
504+
```julia
505+
using LinearSolve, PETSc, MPI, SparseArrays, SparseMatricesCSR, LinearAlgebra
506+
import SciMLBase
507+
MPI.Init()
508+
509+
n = 200
510+
A_csc = sprand(n, n, 0.05); A_csc = A_csc + A_csc' + 20I
511+
b = rand(n)
512+
513+
# Convert to SparseMatrixCSR{0} once — getrowptr/getcolval require a CSR matrix
514+
A = SparseMatrixCSR{0}(transpose(sparse(transpose(A_csc))))
515+
516+
cache = SciMLBase.init(LinearProblem(A, b), PETScAlgorithm(:gmres; pc_type = :ilu))
517+
solve!(cache)
518+
519+
# Extract the fixed sparsity structure once (0-based row pointers and column indices)
520+
rowptr0 = copy(SparseMatricesCSR.getrowptr(A))
521+
colval0 = copy(SparseMatricesCSR.getcolval(A))
522+
523+
# Iterate: only nzval changes, sparsity pattern is fixed
524+
for t in 1:10
525+
new_vals = A.nzval .* (1 + 0.1 * t) # e.g. time-varying coefficients
526+
A_new = SparseMatrixCSR{0}(n, n, rowptr0, colval0, new_vals)
527+
SciMLBase.reinit!(cache; A = A_new, b = rand(n))
528+
solve!(cache)
529+
end
530+
```
531+
532+
#### Extra PETSc options
533+
534+
Any PETSc Options Database key can be forwarded via `ksp_options`:
535+
536+
```julia
537+
PETScAlgorithm(:gmres;
538+
pc_type = :ilu,
539+
ksp_options = (ksp_monitor = "", ksp_rtol = 1e-12, pc_factor_levels = 2))
540+
```
541+
542+
#### Memory management
543+
544+
PETSc objects live in C-managed memory outside Julia's GC. Call
545+
`cleanup_petsc_cache!` explicitly when finished to release resources promptly:
546+
547+
```julia
548+
PETScExt = Base.get_extension(LinearSolve, :LinearSolvePETScExt)
549+
PETScExt.cleanup_petsc_cache!(sol) # after solve(...)
550+
PETScExt.cleanup_petsc_cache!(cache) # after init/solve! cycle
551+
```
552+
553+
A GC finalizer is registered as a safety net, but explicit cleanup is strongly preferred.
554+
555+
```@docs
556+
PETScAlgorithm
557+
```
558+
378559
### LinearSolvePyAMG.jl
379560

380561
!!! note

0 commit comments

Comments
 (0)