Low-Level Interface (LibPETSc)
PETSc.jl provides two ways to interact with the PETSc library:
- High-level interface: Julia-friendly wrappers that handle memory management, use 1-based indexing, and provide convenient syntax (e.g.,
A[1,2] = 3.0) - Low-level interface (
LibPETSc): Direct access to nearly the entire PETSc C API (~13,000+ functions)
This guide focuses on the low-level interface.
When to Use the Low-Level Interface
Use the low-level LibPETSc interface when:
- You need PETSc functionality not yet wrapped in the high-level interface
- You're porting existing PETSc C/Fortran code to Julia
- You need fine-grained control over PETSc objects
- You want to access advanced or experimental PETSc features
- Performance-critical code requires eliminating Julia wrapper overhead
For most common tasks (creating vectors/matrices, solving linear systems), the high-level interface is recommended.
Basic Usage Pattern
The low-level interface follows the PETSc C API closely. All functions require a petsclib parameter as the first argument:
using PETSc
# Get a library instance (usually you'll use the first one)
petsclib = PETSc.petsclibs[1]
# Initialize PETSc
PETSc.initialize(petsclib)
# Create and use PETSc objects
vec = LibPETSc.VecCreate(petsclib, LibPETSc.PETSC_COMM_SELF)
LibPETSc.VecSetSizes(petsclib, vec, 10, 10)
LibPETSc.VecSetType(petsclib, vec, "seq") # Set vector type
LibPETSc.VecSetFromOptions(petsclib, vec)
# Work with the vector
LibPETSc.VecSet(petsclib, vec, 1.0)
println("Vector size: ", LibPETSc.VecGetSize(petsclib, vec))
# Clean up
LibPETSc.VecDestroy(petsclib, vec)
PETSc.finalize(petsclib)Key Concepts
1. The petsclib Parameter
Every low-level function requires a petsclib instance. This specifies which PETSc library variant to use (e.g., Float64 vs Float32, Int32 vs Int64):
# Default libraries available (uses prebuilt PETSc binaries)
petsclib = PETSc.petsclibs[1] # Usually Float64, Int64
# Access the scalar and integer types
PetscScalar = petsclib.PetscScalar # The floating-point type (e.g., Float64)
PetscInt = petsclib.PetscInt # The integer type (e.g., Int64)
PetscReal = petsclib.PetscReal # The real type (real part of PetscScalar)Using a Custom PETSc Build
You can link to your own custom build of PETSc instead of using the prebuilt binaries. This is useful when you need:
- Specific configure options not available in the default build
- Custom optimizations for your hardware
- Debug builds for troubleshooting
- Integration with specific external packages
To persistently configure a custom PETSc installation (recommended):
using PETSc
PETSc.set_library!("/path/to/your/libpetsc.so"; PetscScalar=Float64, PetscInt=Int64)
# Restart Julia — PETSc_jll is not loaded and your library is used automatically.To revert: PETSc.unset_library!(). To inspect the current config: PETSc.library_info().
For a one-off session without changing persistent settings, use the PetscLibType constructor:
petsclib = PETSc.LibPETSc.PetscLibType("/path/to/your/libpetsc.so";
PetscScalar=Float64, PetscInt=Int64)
PETSc.initialize(petsclib)
# ... your code using petsclib ...
PETSc.finalize(petsclib)Important notes for custom builds:
- The library must be compiled as a dynamic/shared library (
libpetsc.so/.dylib) PetscScalarandPetscIntmust match how your PETSc was configured- Your PETSc must be linked against the same MPI that
MPI.jluses - You can check available precompiled libraries with
[PETSc.petsclibs...]
PETSc.LibPETSc.getlib — Function
getlib(; PetscScalar = Float64, PetscInt = Int64)Return the PetscLibType with the associated parameters
2. Zero-Based Indexing
Important: The low-level interface uses 0-based indexing (C convention), while Julia uses 1-based indexing:
# Low-level (0-based)
indices = PetscInt[0, 1, 2] # First three elements
LibPETSc.VecSetValues(petsclib, vec, 3, indices, values, INSERT_VALUES)
# High-level (1-based)
vec[1] = value # First element3. Error Handling
Low-level functions return PetscErrorCode. Use the @chk macro to check for errors:
using PETSc.LibPETSc: @chk
err = LibPETSc.VecCreate(petsclib, MPI.COMM_SELF)
@chk err # Throws an error if PETSc returned non-zero4. String-valued types
PETSc "string enums" such as PCType, KSPType or MatType are C strings (typedef const char *PCType). Every wrapper that takes one accepts a Julia String, and every XGetType returns a String. The registered names are available as constants in LibPETSc, so both spellings below are equivalent:
LibPETSc.MatSetType(petsclib, mat, "seqaij")
LibPETSc.MatSetType(petsclib, mat, LibPETSc.MATSEQAIJ)
LibPETSc.KSPSetType(petsclib, ksp, LibPETSc.KSPGMRES)
LibPETSc.PCSetType(petsclib, pc, LibPETSc.PCILU)
LibPETSc.DMSetType(petsclib, dm, LibPETSc.DMPLEX)
LibPETSc.PetscViewerSetType(petsclib, viewer, LibPETSc.PETSCVIEWERASCII)
LibPETSc.KSPGetType(petsclib, ksp) == LibPETSc.KSPGMRES # trueMost wrapper functions already include error checking, but when calling C functions directly, use @chk.
4. Memory Management
PETSc objects created with Create functions must be destroyed with corresponding Destroy functions:
# Create
mat = LibPETSc.MatCreate(petsclib, MPI.COMM_WORLD)
LibPETSc.MatSetSizes(petsclib, mat, m_local, n_local, m_global, n_global)
# ... use mat ...
# Destroy when done
LibPETSc.MatDestroy(petsclib, mat)For serial (single-process) objects, the high-level interface handles this automatically via finalizers.
PETSc.destroy! works on every handle, including the ones with no high-level layer (IS, AO, PF, Tao). Unlike the raw Destroy call, it does nothing on a borrowed handle (see PETSc.owns), and it is safe to call twice or after a finalize/initialize cycle. length(is) is an index set's global size.
Some functions hand back memory PETSc allocated and say the caller frees it with PetscFree(). PetscFree is a C macro; LibPETSc.PetscFree(petsclib, ptr) does the same from Julia. DMCreateFieldIS and ISColoringGetIS (with PETSC_OWN_POINTER) copy what they return into Julia Vectors and free the C arrays themselves.
PETSc.destroy! — Method
destroy!(v::AbstractPetscVec)Destroy a PETSc vector and release its resources.
Safe to call more than once, and safe to reach as a GC finalizer after the library has been finalized or re-initialized: see isdestroyable. Does nothing on a vector that only borrows its handle: see owns.
External Links
- PETSc Manual:
Vec/VecDestroy
destroy!(m::AbstractPetscMat)Destroy a Mat (matrix) object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a matrix that only borrows its handle: see owns.
External Links
- PETSc Manual:
Mat/MatDestroy
destroy!(opts::AbstractPetscOptions)Free the options database opts holds, if this process is still allowed to.
Does nothing when the library has been finalized or re-initialized, or when opts was already destroyed: see isdestroyable. Does nothing on a borrowed handle either: see owns.
destroy!(ts::AbstractTS)Destroy ts and release the options database attached to it.
The call is a no-op when the library has been finalized or when ts predates the current initialize/finalize cycle, so a stale handle never reaches TSDestroy. Does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
TS/TSDestroy
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
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
destroy!(is::LibPETSc.AbstractIS)Destroy the index set is holds. Safe to call more than once. Does nothing on a borrowed index set, such as one ISColoringGetIS leaves with its coloring: see owns.
External Links
- PETSc Manual:
IS/ISDestroy
destroy!(ao::LibPETSc.AbstractAO)Destroy the application ordering ao holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
AO/AODestroy
destroy!(pf::LibPETSc.AbstractPF)Destroy the mathematical function pf holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
PF/PFDestroy
destroy!(tao::LibPETSc.AbstractTao)Destroy the optimization solver tao holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
Tao/TaoDestroy
destroy!(snes::AbstractSNES)Destroy a SNES (nonlinear solver) object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a borrowed handle, such as the one snes(ts) hands back.
External Links
- PETSc Manual:
SNES/SNESDestroy
destroy!(dm::AbstractPetscDM)Destroy a DM object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a DM that only borrows its handle: see owns.
External Links
- PETSc Manual:
DM/DMDestroy
PETSc.destroy! — Method
destroy!(v::AbstractPetscVec)Destroy a PETSc vector and release its resources.
Safe to call more than once, and safe to reach as a GC finalizer after the library has been finalized or re-initialized: see isdestroyable. Does nothing on a vector that only borrows its handle: see owns.
External Links
- PETSc Manual:
Vec/VecDestroy
destroy!(m::AbstractPetscMat)Destroy a Mat (matrix) object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a matrix that only borrows its handle: see owns.
External Links
- PETSc Manual:
Mat/MatDestroy
destroy!(opts::AbstractPetscOptions)Free the options database opts holds, if this process is still allowed to.
Does nothing when the library has been finalized or re-initialized, or when opts was already destroyed: see isdestroyable. Does nothing on a borrowed handle either: see owns.
destroy!(ts::AbstractTS)Destroy ts and release the options database attached to it.
The call is a no-op when the library has been finalized or when ts predates the current initialize/finalize cycle, so a stale handle never reaches TSDestroy. Does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
TS/TSDestroy
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
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
destroy!(is::LibPETSc.AbstractIS)Destroy the index set is holds. Safe to call more than once. Does nothing on a borrowed index set, such as one ISColoringGetIS leaves with its coloring: see owns.
External Links
- PETSc Manual:
IS/ISDestroy
destroy!(ao::LibPETSc.AbstractAO)Destroy the application ordering ao holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
AO/AODestroy
destroy!(pf::LibPETSc.AbstractPF)Destroy the mathematical function pf holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
PF/PFDestroy
destroy!(tao::LibPETSc.AbstractTao)Destroy the optimization solver tao holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
Tao/TaoDestroy
destroy!(snes::AbstractSNES)Destroy a SNES (nonlinear solver) object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a borrowed handle, such as the one snes(ts) hands back.
External Links
- PETSc Manual:
SNES/SNESDestroy
destroy!(dm::AbstractPetscDM)Destroy a DM object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a DM that only borrows its handle: see owns.
External Links
- PETSc Manual:
DM/DMDestroy
PETSc.destroy! — Method
destroy!(v::AbstractPetscVec)Destroy a PETSc vector and release its resources.
Safe to call more than once, and safe to reach as a GC finalizer after the library has been finalized or re-initialized: see isdestroyable. Does nothing on a vector that only borrows its handle: see owns.
External Links
- PETSc Manual:
Vec/VecDestroy
destroy!(m::AbstractPetscMat)Destroy a Mat (matrix) object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a matrix that only borrows its handle: see owns.
External Links
- PETSc Manual:
Mat/MatDestroy
destroy!(opts::AbstractPetscOptions)Free the options database opts holds, if this process is still allowed to.
Does nothing when the library has been finalized or re-initialized, or when opts was already destroyed: see isdestroyable. Does nothing on a borrowed handle either: see owns.
destroy!(ts::AbstractTS)Destroy ts and release the options database attached to it.
The call is a no-op when the library has been finalized or when ts predates the current initialize/finalize cycle, so a stale handle never reaches TSDestroy. Does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
TS/TSDestroy
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
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
destroy!(is::LibPETSc.AbstractIS)Destroy the index set is holds. Safe to call more than once. Does nothing on a borrowed index set, such as one ISColoringGetIS leaves with its coloring: see owns.
External Links
- PETSc Manual:
IS/ISDestroy
destroy!(ao::LibPETSc.AbstractAO)Destroy the application ordering ao holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
AO/AODestroy
destroy!(pf::LibPETSc.AbstractPF)Destroy the mathematical function pf holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
PF/PFDestroy
destroy!(tao::LibPETSc.AbstractTao)Destroy the optimization solver tao holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
Tao/TaoDestroy
destroy!(snes::AbstractSNES)Destroy a SNES (nonlinear solver) object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a borrowed handle, such as the one snes(ts) hands back.
External Links
- PETSc Manual:
SNES/SNESDestroy
destroy!(dm::AbstractPetscDM)Destroy a DM object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a DM that only borrows its handle: see owns.
External Links
- PETSc Manual:
DM/DMDestroy
PETSc.destroy! — Method
destroy!(v::AbstractPetscVec)Destroy a PETSc vector and release its resources.
Safe to call more than once, and safe to reach as a GC finalizer after the library has been finalized or re-initialized: see isdestroyable. Does nothing on a vector that only borrows its handle: see owns.
External Links
- PETSc Manual:
Vec/VecDestroy
destroy!(m::AbstractPetscMat)Destroy a Mat (matrix) object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a matrix that only borrows its handle: see owns.
External Links
- PETSc Manual:
Mat/MatDestroy
destroy!(opts::AbstractPetscOptions)Free the options database opts holds, if this process is still allowed to.
Does nothing when the library has been finalized or re-initialized, or when opts was already destroyed: see isdestroyable. Does nothing on a borrowed handle either: see owns.
destroy!(ts::AbstractTS)Destroy ts and release the options database attached to it.
The call is a no-op when the library has been finalized or when ts predates the current initialize/finalize cycle, so a stale handle never reaches TSDestroy. Does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
TS/TSDestroy
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
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
destroy!(is::LibPETSc.AbstractIS)Destroy the index set is holds. Safe to call more than once. Does nothing on a borrowed index set, such as one ISColoringGetIS leaves with its coloring: see owns.
External Links
- PETSc Manual:
IS/ISDestroy
destroy!(ao::LibPETSc.AbstractAO)Destroy the application ordering ao holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
AO/AODestroy
destroy!(pf::LibPETSc.AbstractPF)Destroy the mathematical function pf holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
PF/PFDestroy
destroy!(tao::LibPETSc.AbstractTao)Destroy the optimization solver tao holds. Safe to call more than once; does nothing on a borrowed handle: see owns.
External Links
- PETSc Manual:
Tao/TaoDestroy
destroy!(snes::AbstractSNES)Destroy a SNES (nonlinear solver) object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a borrowed handle, such as the one snes(ts) hands back.
External Links
- PETSc Manual:
SNES/SNESDestroy
destroy!(dm::AbstractPetscDM)Destroy a DM object and release associated resources.
This function is typically called automatically via finalizers when the object is garbage collected, but can be called explicitly to free resources immediately. Does nothing on a DM that only borrows its handle: see owns.
External Links
- PETSc Manual:
DM/DMDestroy
Base.length — Method
length(is::LibPETSc.AbstractIS)The global number of indices in is, summed over its ranks, as length of a PetscVec is its global length.
External Links
- PETSc Manual:
IS/ISGetSize
PETSc.LibPETSc.PetscFree — Function
PetscFree(petsclib::PetscLibType, ptr::Ptr)Frees memory that PETSc allocated with PetscMalloc() and handed to the caller, such as the arrays some Create and Get functions return with the note "the caller must free it with PetscFree()". Does nothing on C_NULL.
PetscFree() is a C macro, so this calls the allocator's free routine PetscTrFree directly, which also honours an allocator installed with PetscMallocSet().
Not Collective
Input Parameter:
ptr- memory allocated by PETSc
Level: beginner
See also: PetscMalloc(), PetscMallocSet()
External Links
- PETSc Manual:
Sys/PetscFree
The Get...Array functions return a PetscArray that points into PETSc's storage. Pass it back to the matching Restore...Array function when you are done with it.
PETSc.LibPETSc.PetscArray — Type
PetscArray{T,N} <: AbstractArray{T,N}Behaves like a normal Julia array but holds a pointer to PETSc data, which can be destroyed
5. Assembly
After setting values in vectors or matrices, you must call assembly functions:
# Set values
LibPETSc.VecSetValues(petsclib, vec, n, indices, values, INSERT_VALUES)
# Assemble
LibPETSc.VecAssemblyBegin(petsclib, vec)
LibPETSc.VecAssemblyEnd(petsclib, vec)Common Patterns
Creating and Filling a Vector
petsclib = PETSc.petsclibs[1]
PetscInt = petsclib.PetscInt
PetscScalar = petsclib.PetscScalar
# Create vector
vec = LibPETSc.VecCreate(petsclib, MPI.COMM_SELF)
LibPETSc.VecSetSizes(petsclib, vec, 10, 10)
LibPETSc.VecSetType(petsclib, vec, "seq") # Set vector type
LibPETSc.VecSetFromOptions(petsclib, vec)
# Set values (0-based indices!)
indices = PetscInt[0, 1, 2, 3, 4]
values = PetscScalar[1.0, 2.0, 3.0, 4.0, 5.0]
LibPETSc.VecSetValues(petsclib, vec, 5, indices, values, INSERT_VALUES)
# Assemble
LibPETSc.VecAssemblyBegin(petsclib, vec)
LibPETSc.VecAssemblyEnd(petsclib, vec)
# View (print to stdout)
LibPETSc.VecView(petsclib, vec, C_NULL)
# Clean up
LibPETSc.VecDestroy(petsclib, vec)Creating a Sparse Matrix
# Create matrix
mat = LibPETSc.MatCreate(petsclib, MPI.COMM_SELF)
LibPETSc.MatSetSizes(petsclib, mat, 5, 5, 5, 5)
LibPETSc.MatSetType(petsclib, mat, "seqaij")
LibPETSc.MatSetUp(petsclib, mat)
# Set values (0-based indexing!)
row = PetscInt[0]
cols = PetscInt[0, 1]
vals = PetscScalar[2.0, -1.0]
LibPETSc.MatSetValues(petsclib, mat, 1, row, 2, cols, vals, INSERT_VALUES)
# Assemble
LibPETSc.MatAssemblyBegin(petsclib, mat, LibPETSc.MAT_FINAL_ASSEMBLY)
LibPETSc.MatAssemblyEnd(petsclib, mat, LibPETSc.MAT_FINAL_ASSEMBLY)
# View
LibPETSc.MatView(petsclib, mat, C_NULL)
# Clean up
LibPETSc.MatDestroy(petsclib, mat)Solving a Linear System
# Create KSP solver
ksp = LibPETSc.KSPCreate(petsclib, MPI.COMM_SELF)
LibPETSc.KSPSetOperators(petsclib, ksp, mat, mat)
LibPETSc.KSPSetFromOptions(petsclib, ksp)
# Solve Ax = b
LibPETSc.KSPSolve(petsclib, ksp, b, x)
# Get convergence info
reason = LibPETSc.KSPGetConvergedReason(petsclib, ksp)
iterations = LibPETSc.KSPGetIterationNumber(petsclib, ksp)
println("Converged in $(iterations) iterations, reason: $(reason)")
# Clean up
LibPETSc.KSPDestroy(petsclib, ksp)Mixing High-Level and Low-Level Interfaces
You can mix both interfaces. High-level objects provide .ptr field to access the underlying C pointer:
# Create with high-level interface
vec_high = PetscVec(petsclib, 10)
# Use with low-level interface
LibPETSc.VecSet(petsclib, vec_high.ptr, 5.0)
# Or use the object directly (if it's a compatible type)
LibPETSc.VecView(petsclib, vec_high, C_NULL)Finding Functions
The low-level interface provides wrappers for most PETSc functions. To find a function:
- Check the PETSc manual: https://petsc.org/release/docs/
- Use Julia's help system: Type
?LibPETSc.FunctionName - Browse the documentation: See the reference pages for each PETSc class (Vec, Mat, KSP, etc.)
- Autocomplete: In the REPL, type
LibPETSc.Vecand press Tab to see all Vec functions
Type Conventions
Low-level functions use these type patterns:
# PETSc objects (opaque pointers)
CVec = Ptr{Cvoid} # Vector
CMat = Ptr{Cvoid} # Matrix
CDM = Ptr{Cvoid} # DM (domain management)
CKSP = Ptr{Cvoid} # KSP (linear solver)
CSNES = Ptr{Cvoid} # SNES (nonlinear solver)
# PETSc data types (depend on petsclib)
PetscInt # Integer type (Int32 or Int64)
PetscScalar # Scalar type (Float64, Float32, ComplexF64, etc.)
PetscReal # Real type (real part of PetscScalar)Reference Pages
Detailed documentation for low-level functions by category:
- Vec (Vectors) - ~293 functions for vector operations
- Mat (Matrices) - ~756 functions for matrix operations
- KSP (Linear Solvers) - ~256 functions for iterative linear solvers
- SNES (Nonlinear Solvers) - ~333 functions for nonlinear solvers
Getting Help
If you encounter issues:
- Check the PETSc documentation
- Review the examples
- Ask questions on Julia Discourse with the
petsctag - Open an issue on GitHub