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