Release notes

v0.5.5

The last release before 0.6, which removes every shim and flips several defaults. Run your code on 0.5.5 with warnings on and fix what they report; "Coming in v0.6" lists the changes that print no warning.

Coming in v0.6

These change what working code does or remove a name. The ones marked "warns" print a warning in this release; the others can't warn without firing on correct code.

  • KSP, SNES and TS apply their constructor options once, at the first setup! or solve!, as options_at = :first_solve does now. SNES no longer re-reads the options at every solve, which can reset a preconditioner configured in code.
  • solve! throws a ConvergenceError when a KSP, SNES or TS solve does not converge, instead of warning (warns since 0.5.3; check = true throws now).
  • Every name, method and keyword form that warns in 0.5.x is removed.
  • VecPtr and MatPtr go (warns). Wrap a raw handle with PetscVec(petsclib, ptr; own) or PetscMat(petsclib, ptr; own).
  • isapprox(v, w) on two PetscVecs compares norms, ‖v − w‖ ≤ max(atol, rtol·max(‖v‖, ‖w‖)), as for Julia arrays, instead of entry by entry (warns).
  • An out-of-place broadcast on a PetscVec, w = 2 .* x, returns a PetscVec of x's layout instead of a Vector, and works on a distributed vector. The caller destroys it. 2 * x and x + y already return a PetscVec.
  • size(v) on a PetscVec returns a tuple (n,) of Int and length(v) an Int, as for any vector. size(v) == n becomes false, so check code that uses size(v) as a number.
  • copy_disc!(dst, src) takes the destination first, as copyto! does. Both arguments are DMs, so a call in the old order runs and copies the wrong way.
  • set_convergence_test! passes the norms to the callback as PetscReal, not Float64. This matters only for a Float32 library with a callback whose arguments are annotated Float64.
  • star_fd_coloring returns its index arrays as Vector{Int}, not Vector{Int32}.
  • The …Fn callback types (SNESSetFunctionFn, TSSetRHSFunctionFn, …) are no longer public.
  • PetscVec <: AbstractVector and PetscMat <: AbstractMatrix. Element-by-element fallbacks throw by default, so a generic method that would make one C call per entry fails instead. == on two PetscVecs compares values (VecEqual, collective) as it already does on PetscMats, and hash on either throws.

Added

  • PetscMat(petsclib, ptr; own = false) wraps a raw Mat handle, as PetscVec(petsclib, ptr; own) does for a Vec.
  • PetscVec has copy, dot, axpy!, axpby!, rmul!, lmul! and the operators x + y, x - y, -x, α * x and x / α, through VecCopy, VecDot, VecAXPY, VecAXPBY, VecScale and VecWAXPY. An assembled PetscMat has copy, A + B, A - B, -A and α * A, through MatDuplicate, MatAXPY and MatScale. All are collective and work on distributed objects; copy and the operators return a new Vec or Mat, which on more than one rank needs destroy! like any other. dot(x, y) conjugates x, as for Julia arrays.
  • MatShell takes the operations mult_transpose(y, x), diagonal(d) and mult_add(z, x, y) as keywords, so transpose(A) * x, A' * x, pc_type = jacobi and MatMultAdd work on a shell.
  • with_local_arrays!(f!, g_fx, l_x) calls f!(fx, lx) with the local arrays of the two Vecs, on the device when a GPU extension is loaded, and hands them back afterwards, also when f! throws.
  • with_local_coordinate_array(f, dm) calls f(coord) with the local coordinates of a DMDA or DMStag, addressed with global indices, and hands the array back when f returns or throws.
  • AMD GPUs: with AMDGPU.jl loaded and a PETSc built with HIP, with_local_array! and with_local_arrays! return ROCArrays for Vecs in HIP memory (PETScAMDGPUExt). with_local_arrays! also handles one Vec on the host and the other on the device, as on coarser multigrid levels. with_field_views! on a DMStag with device vectors gives views of device arrays for kernels; broadcast over parent(view), since OffsetArray broadcasts on the host.

Deprecated

  • VecPtr(petsclib, ptr; own) and MatPtr(…) warn and go in v0.6: use PetscVec(petsclib, ptr; own) and PetscMat(petsclib, ptr; own), which give the same wrappers.
  • isapprox(v, w) on two PetscVecs warns once that it compares norms from v0.6.
  • user_ctx, set_user_ctx! and the callback forms with a trailing context warn and go in v0.6. A closure carries the context: set_rhs_function!(ts) do F, ts, t, u … end reads what it needs from the enclosing scope, and every callback then has one calling form.
  • vtk_merge_tensor and create_split_boundary_labels! warn and go in v0.6. Both fit particular examples rather than PETSc: copies are in examples/dmplex/vtk_tensor.jl and examples/dmplex/ex69.jl.
  • local_arrays and restore_local_arrays! warn: use with_local_arrays!. An exception between the two calls left both Vecs checked out.
  • local_coordinate_array(dm) warns: use with_local_coordinate_array(f, dm). It now returns a copy. It used to leave the coordinate vector checked out until the garbage collector freed the array, and if the DM was destroyed first, that late hand-back crashed Julia.
  • @simple_fn, @residual_fn, @jacobian_fn and @bd_fn take the library first, @residual_fn(petsclib, f0, Nf), and use its PetscInt, PetscReal and PetscScalar for the C signature. The library value or its type both work; it is evaluated when the macro expands, so it must be a global defined before the call. Without the library, the macros take PetscInt, PetscScalar and PetscReal from the calling module's globals as before, and warn. That form needed those three consts and allowed only one library per module.

Behaviour changes

  • star_fd_coloring throws an ArgumentError for a DMDA that is not 2-D with a STAR stencil, where a 1-D or 3-D one gave a MethodError and a BOX one a coloring that leaves out entries.

Fixed

  • CUDA: with_local_arrays! with one Vec on the host and the other on the device threw a MethodError, and arrays went back to PETSc before CUDA.jl's kernels on them had finished unless one was a host copy. Both now work as with AMDGPU: the host Vec is copied to the device and back, and the device is synchronized before every hand-back. Not tested on an NVIDIA GPU.
  • examples/dmda/ex19.jl runs on the GPU again, with CUDA or HIP (const gpu = :cuda or :hip). Its GPU branch passed a raw pointer to MatSetValuesCOO, which takes a Vector, and its residual got a host and a device array on coarser multigrid levels.
  • LibPETSc.PetscGetArgs, PetscGetArguments, PetscStrToArray, PetscFunctionListGet and PetscViewerBinaryReadStringArray return a Vector{String}. They passed one char ** where PETSc takes a char ***, so they returned a wrong string or crashed. PetscStrArrayallocpy, PetscStrArrayDestroy, PetscStrNArrayallocpy, PetscStrNArrayDestroy and PetscOptionsInsert still take a char *** or char ** as one string and are not usable.
  • audit_file no longer reports PetscVec(petsclib, ptr; own = false) or PetscMat(…; own = false) as a leak: a borrowed handle has nothing to destroy.

v0.5.4

Deprecated

  • Insert modes, scatter modes and diag are keywords, mode, scatter and diag: set_values!(A, rows, cols, vals; mode = ADD_VALUES), ghost_update!(v; mode = ADD_VALUES, scatter = SCATTER_REVERSE), global_to_local!(l, dm, g; mode), zero_rows!(A, rows; diag = 2). This covers ghost_update!, ghost_update_begin!, ghost_update_end!, local_to_global!, global_to_local!, local_to_local!, set_values!, project_function!, project_field!, zero_rows! and zero_rows_local!. The positional forms still work and warn once; they go in v0.6. project_function! also takes ctxs as a keyword, and both projections default to mode = INSERT_VALUES.
  • DMDA and DMStag take the stencil width and type as keywords with defaults, DMStag(petsclib, comm, boundary, dims, dof; stencil_width = 1, stencil_type = :box), where they were positional. The DM constructors' setfromoptions and dmsetup keywords are set_from_options and setup. The old forms still work and warn once; they go in v0.6.
  • add_coarsen_hook! takes the DM first, add_coarsen_hook!(dm, coarsenhook, restricthook), as set_residual! does. Its hooks are C function pointers, which do syntax can't supply, so putting them first bought nothing. The hook-first order still works and warns.
  • distribute! is distribute: it returns a new distributed DM and leaves its argument unchanged, so the name has no !. distribute! and plexdistribute! still work and warn.
  • own is a keyword with default false when wrapping a raw handle: VecPtr(petsclib, ptr; own = true), MatPtr(petsclib, ptr; own) and PetscVec(petsclib, ptr; own), as in narrow(dm; own). The positional own still works and warns.
  • The CSR constructor takes the communicator second, PetscMat(petsclib, comm, rowptr, colval, nzval), as every other constructor does; the comm keyword still works and warns. Without comm the matrix is on MPI.COMM_SELF, as before.
  • MatShell takes the operator first, MatShell(f, petsclib, comm, local_rows, local_cols; global_rows, global_cols), so MatShell(petsclib, comm, m, n) do y, x … end works. The global sizes are keywords. The library-first order still works and warns.

Behaviour changes

  • A LibPETSc call whose arguments match no generated method, such as an Int where the library takes its scalar type, throws a MethodError naming the argument types, instead of an ErrorException with the text "no generated method for these argument types".
  • library_info() prints as the NamedTuple it returns. The report it printed came from a show method that also changed how any other NamedTuple with the same five field names printed. PETSc.petsclibs lists the libraries loaded in the session.

Added

  • The handle types are public API, with docstrings: the abstract types to annotate with (AbstractPetscVec, AbstractPetscMat, AbstractPetscDM, AbstractKSP, AbstractPC, AbstractSNES, AbstractTS, AbstractPetscOptions, AbstractIS, AbstractAO, AbstractPF, AbstractTao) and the handles PetscDM, PC, IS, AO, PF and Tao, all reachable as PETSc.X. PETSc.realtype(petsclib) gives the library's real type.
  • A PetscError prints the C function the failing call went to and PETSc's message for it, for example PetscError(56) from VecSetSizes: No support for this operation for this object type. Cannot change/reset vector sizes to 4 local 4 global after previously setting them to 3 local 3 global, where it printed PetscError(56). The fields func and message hold the two; PetscError(code) still works.
  • DMStag(dm, dof) takes prefix, and every DMDA, DMStag, DMPlex, KSP, SNES and TS constructor takes any AbstractString as prefix, a SubString included.
  • PetscVec(petsclib, comm, n; local_size = PETSC_DECIDE) creates a vector distributed over comm, by global length n or by local_size with n = PETSC_DETERMINE.

Fixed

  • A dense matrix made with PetscMat(petsclib, A::Matrix) or PetscMat(petsclib, m, n; type = :dense) could lose its storage while a KSP still used it: once the Julia handle was collected, the array went with it, and the next solve read freed memory (a wrong answer or a PETSc zero-pivot error). The array now lives as long as the PETSc matrix, as it already did for CSR matrices and vectors on Julia arrays. type = :dense lets PETSc allocate the storage.
  • A DMDA, DMStag or DMPlex constructor, or fe_create_default, that threw inside PETSc (for example on da_refine = "abc") left its options pushed on PETSc's options stack. Every object created afterwards read them, and the options could no longer be destroyed. The options are now popped whether or not the call throws.
  • PETSc.scalartype and PETSc.inttype are now the same functions as LibPETSc.scalartype and LibPETSc.inttype. They were two separate copies, so a method added to one was missing from the other.
  • mul!, ksp \ b, ldiv! and solve!(x, ksp, b) took only PetscVec, so a borrowed VecPtr gave a MethodError (A * x with a VecPtr failed inside). They take any vector handle.
  • A 2D or 3D DMDA built without a stencil type threw a MethodError; it now defaults to :box, as DMStag does.
  • DMStag(dm, dof; dmsetfromoptions = false) passed -dmsetfromoptions to PETSc as an option and still applied the options; the keyword is honoured, with a deprecation warning pointing to set_from_options.

v0.5.3

Behaviour changes

  • A KSP, SNES or TS solve that stops without converging now prints a warning, once per call site, instead of returning in silence: PETSc leaves the last iterate in the solution vector, and nothing else said the solve had failed. From v0.6 such a solve should throw a ConvergenceError. Pass check = false to solve! to keep handling converged_reason yourself and silence the warning, or check = true to throw now.

Fixed

  • Pushing a PetscOptions that was already on PETSc's options stack broke the stack: the next pop! failed, and PETSc's global options were lost for the rest of the run. push! now throws an ArgumentError instead.
  • An MPI run started against a stale precompile cache (after an update, or a change to a deved PETSc.jl) could hang for good at 0% CPU. The rank that precompiled PETSc called MPI.Init inside the precompile process, which then waited for peers that never came. PETSc no longer initializes MPI while it loads; initialize does it, as before.
  • A' * x, transpose(A) * x and mul!(y, A', x) on a PETSc matrix threw a MethodError: the transposed products existed but could not be reached. They now run MatMultHermitianTranspose and MatMultTranspose, without forming the transpose.
  • On a PetscVec made on a Julia array (PetscVec(petsclib, x)), every norm type after the first came back as 0: norm(v) followed by norm(v, LibPETSc.NORM_1) gave 5 and then 0. PETSc saw the other norms as already cached, because such a vector starts in the same object state as PETSc's empty norm cache. The vector is now moved past that state when it is created.
  • isapprox(v, w; rtol = 1e-8) on two PetscVecs threw a MethodError; atol, rtol and nans now apply to each entry.
  • DMDA and DMStag with more than three dimensions failed with an UndefVarError; they throw an ArgumentError saying a DM has 1 to 3 dimensions.
  • PetscVec(petsclib, comm, x) with an x of the wrong element type throws an ArgumentError naming both types, as PetscVec(petsclib, x) does, instead of a MethodError from the generated layer.
  • copyto!(A, S::SparseMatrixCSC) has a docstring saying how S is placed (from the first row the rank owns; in parallel, the rank's diagonal block), and throws a DimensionMismatch when S does not fit.
  • LibPETSc.DMCreateFieldDecomposition returned the field names as one garbled string: it passed PETSc's char *** as a char **. It now returns a Vector{String} (for a DMStag Stokes layout ["face", "element"], the names PCFIELDSPLIT uses as option prefixes) and frees the names and the array. LibPETSc.DMCreateDomainDecomposition leaked its subdomain names; they are freed too.

Added

  • The manual page "Direct solvers" says which of the direct solvers in PETSc_jll give the right answer, serially and on several ranks, and scripts/direct_solvers.jl checks an installation against it. PETSc's default LU doesn't pivot and SuperLUDIST is wrong on one saddle-point test; both report success. MUMPS on more than one rank needs MUMPSjll 5.9.5 or later on Linux.
  • tolerances and set_tolerances! on a KSP (rtol, atol, divtol, max_it) and a SNES (atol, rtol, stol, max_it, max_funcs), as TS had them. The names are the options' without their prefix, so set_tolerances!(ksp; max_it = 200) does what -ksp_max_it 200 does. set_from_options! also takes a PC, matrix or vector; options_prefix and set_options_prefix! also take a DM, matrix or vector; comm also takes a PC or an index set; and interpolate(ts, t) returns the interpolated solution in a new vector.
  • examples/dmstag/dmstag_stokes.jl and the manual page "Stokes flow on a DMStag": 2D incompressible Stokes flow around a stiff sinker, with each equation written as a residual and turned into a matrix row by ForwardDiff, free-slip walls, and a Schur-complement fieldsplit whose velocity block is a geometric multigrid V-cycle set up in a set_post_setup! hook. FGMRES takes 12 iterations at uniform viscosity and about 30 at a contrast of 10⁴, flat from 32² to 128².
  • with_destroy(f) destroys a group of objects when its block ends, also after an exception: objects registered with track!(list, obj) are destroyed in reverse order, the same on every rank. On more than one process nothing else frees them, and every rank must destroy the same objects in the same order. untrack! takes out an object that should outlive the block, and a borrowed handle is never tracked.
  • set_post_setup!(f!, pc) runs f!(pc) at the end of every preconditioner setup. It is the place to configure the solvers of a :fieldsplit's splits, which exist only once the preconditioner is set up, for example a multigrid on one split with interpolation operators built in Julia. set_pre_solve!(f!, ksp) runs f!(ksp, b, x) at the start of every solve. Both keep the closure with the PETSc object, and an exception thrown inside comes out of the solve! that ran it.
  • ConvergenceError and a check keyword on solve! (KSP, SNES, TS) and step!: with check = true a solve that stops without converging throws a ConvergenceError carrying the solver, its converged reason, the iteration count and, for a SNES, the last residual norm. Its message says in words why the solver stopped and which options show more. A TS step that fails while errorifstepfailed is set (the default) throws a ConvergenceError with check = true, and the PetscError it threw before otherwise.
  • An options_at keyword on the KSP, SNES and TS constructors says when their options are applied: :construction, :each_solve or :first_solve (once, at the first setup! or solve!, after the DM and callbacks are attached). The defaults keep each type's behaviour: KSP applies them at construction, SNES and TS at every solve, where they override a preconditioner set in code. with_options(f, ksp) (or snes, ts, or a PetscOptions) runs f with those options pushed and returns its result. setup! works on a KSP and a SNES.
  • set_values! (both 0-based forms), ksp \ b, the CSR PetscMat(petsclib, rowptr, colval, nzval) constructor and dof_slot accept any vector or integer type: other element types, views, ranges and offset arrays. Arrays already of the library's types still go to PETSc without a copy; anything else is copied once. ksp \ b returns x with the axes of b.
  • norm(v, p) for p = 1, 2 and Inf, and norm(A, 2) (Frobenius), beside the NormType methods; opnorm(A, 1) and opnorm(A, Inf) for the induced matrix norms.
  • size(v, d), size(A, d), axes(A) and axes(A, d) for any PETSc vector or matrix, with size(_, d) == 1 beyond the last dimension as for a Julia array; ndims on a matrix no longer calls into PETSc.

v0.5.2

0.5.2 is what a staggered-grid solver needs from PETSc.jl: DMStag gets locations keyed by axis, stencils built from 1-based indices, assembly and halo exchange, and field views that hand a callback concretely typed arrays. TS gets what a long run needs, and Vec and Mat get the Base verbs that were missing. The rest is leaks closed in the generated layer and two performance traps, one of which made a 4-rank DMStag solve 25 times slower. Working code is most likely to notice the three behaviour changes below; the rest is additive.

Behaviour changes

  • When several MPI ranks share a node, initialize sets Julia's BLAS pool to one thread, unless -blas_num_threads, OPENBLAS_NUM_THREADS or OMP_NUM_THREADS says otherwise. Each rank otherwise ran a pool of busy-waiting threads, which made a 4-rank DMStag Stokes solve 25× slower. Serial runs and one rank per node are unaffected.
  • solution(ksp), solution(ts), local_coordinates(dm) and the vatol/vrtol of tolerances(ts) return a borrowed PetscVec, as solution(snes) already did, instead of a VecPtr. Both are AbstractPetscVecs with the same ownership, so only code that checks for VecPtr by type notices.
  • LibPETSc release functions that free a C array of handles (VecDestroyVecs, MatDestroyMatrices, DMPlexRestoreConeRecursive, …) no longer accept a Julia array of raw handles, which PETSc would have freed as its own memory. They take the pointer PETSc returned; MatDestroySubMatrices, MatDestroyMatrices, VecNestRestoreSubVecsRead and the two subdomain destroyers also take the vector the matching wrapper returned.

Fixed

  • with_local_array! spent 23 allocations per call and did not infer its return type: it queried every vector's PetscMemType with a checkout of its own before checking the vectors out for real, and memtype_backend dispatched on a Val built from that run-time value. Host memory, the common case, now answers before the dispatch and the extra query is gone, so a one-vector checkout costs 2 allocations and infers. with_field_views! had the same fault plus a read/write variable that changed type, and goes from 24 allocations to 8. A SNES solve whose callbacks check arrays out drops from 210 allocations to 47. Device memory dispatches as before, so the CUDA extension is unaffected.
  • v[i] = a on a PetscVec and v[i] built their one-element index vector twice over. v[i] = a now allocates nothing and v[i] two.
  • Out-of-place broadcasting over a PetscVec, w = 2 .* x, read one entry at a time through VecGetValues, which cost 4003 allocations at 10 000 entries and failed on a distributed vector with a raw PETSc error. It runs on the local arrays now, at about 5 allocations whatever the length, and still gives a Vector. A distributed vector throws an ArgumentError, since a Vector of the whole vector only means something where one rank holds all of it.
  • Broadcasting into a PetscVec (y .= 2 .* x, a typical MatShell body) read and wrote the vectors one entry at a time, through VecGetValues and VecSetValues: at 10 000 entries a MatShell product took 139 000 allocations and was 500× slower than the same loop on the local arrays. The vectors now take part as their local arrays, at a fixed cost of about 10 allocations. On several ranks the broadcast runs over the entries each rank owns.
  • LibPETSc.ISColoringGetIS with PETSC_OWN_POINTER returned the index sets as borrowed, so they and the C array holding them leaked. The index sets are now owned by the caller and the array is freed. ISColoringRestoreIS accepts the vector ISColoringGetIS returns.
  • LibPETSc.DMCreateFieldIS leaked the field names and both C arrays.
  • The TS and SNES manual pages still described the 0.5.0 callback rules (return an error code, exceptions become a PetscError).
  • 14 LibPETSc functions that return a vector of new handles leaked the C array PETSc allocated for them: DMCreateDomainDecomposition, DMCreateFieldDecomposition, DMCreateSuperDM, DMCreateSectionSuperDM, MatSubdomainsCreateCoalesce, PCASMCreateSubdomains, PCASMCreateSubdomains2D, PCGASMCreateSubdomains, PCGASMCreateSubdomains2D, PCGASMGetSubdomains, PCGetCoarseOperators, PCGetInterpolations, PetscQuadratureComputePermutations and VecConcatenate. The array is now freed once the handles are copied.
  • LibPETSc.MatCreateSubMatrices and MatCreateSubMatricesMPI did not work with MAT_REUSE_MATRIX, and MatDestroySubMatrices could not take their result. Pass the returned vector back to either.
  • LibPETSc.VecNestRestoreSubVecsRead accepts the vector VecNestGetSubVecsRead returns; before, it only took a raw pointer that no wrapper handed out, so the read lock could not be released.
  • LibPETSc.PCASMDestroySubdomains and PCGASMDestroySubdomains accept the vectors the subdomain creators return.
  • On an Int32 PETSc build (the PetscInt = "Int32" preference), LibPETSc.DMStagStencil, MatStencil and the other C structs had Int64 fields, so PETSc read them wrong. They now take the integer width of the loaded library, and the two stencil constructors convert their indices to it.
  • LibPETSc.DMStagRestoreProductCoordinateArraysRead restored the arrays through the writable restore, which does not match the read-only get.
  • The KSP and SNES docstrings did not say when the options given to the constructor are applied: once at construction for KSP, at every solve! for SNES (and TS).
  • -blas_num_threads had no effect. Every PETScjll build calls BLAS through libblastrampoline, so PETSc's BLAS runs in Julia's OpenBLAS pool, which PETSc cannot size. initialize now forwards the option to `LinearAlgebra.BLAS.setnum_threads`.
  • initialize(petsclib; options) appended -no_signal_handler to the caller's options vector.
  • On Windows, the options and log_view given to initialize never reached PETSc: they went through ENV["PETSC_OPTIONS"], which PETSc there reads from its own copy of the environment. They are now PETSc's command line (LibPETSc.PetscInitialize takes a Vector{String}), and still override a PETSC_OPTIONS set before Julia starts.

Added

  • A performance contract: test/core/performance.jl checks that 29 calls meant for a loop infer a concrete return type and allocate the same amount at two problem sizes, and docs/src/man/performance.md says how to keep that cost (array blocks, BLAS threads per rank, concretely typed objects, precompiling before mpiexec, -log_view).
  • copyto!(dst, src) between two PetscVecs.
  • Matrix methods: fill!(A, 0), zero_rows! and zero_rows_local! for Dirichlet rows, set_option!, diagonal!(d, A) and isassembled.
  • destroy! on IS, AO, PF and Tao handles.
  • LibPETSc.PetscFree, for memory PETSc hands to the caller.
  • Long TS runs: set_pre_step!(f!, ts) and set_post_step!(f!, ts) hooks that may change the run, set_max_snes_failures!, set_max_step_rejections!, set_error_if_step_fails!, set_step_number! for restarts, and equation_type/set_equation_type!.
  • set_solution!(snes, x), as on TS.
  • LibPETSc.PETSC_UNLIMITED and LibPETSc.PETSC_CURRENT, which PETSc's manual pages ask for.
  • DMStag locations by axis: vertex_location(dm), edge_location(dm, a, b), face_location(dm, axis) and element_location(dm), which mean the same in 2D and 3D, unlike DMSTAG_DOWN.
  • stencil(dm, loc, I; dof = 0) builds a DMStagStencil from a 1-based element index, allocation free.
  • Assembly with DMStag stencils: set_values!(J, dm, rows, cols, vals, mode), set_values!(v, dm, positions, vals, mode) and zero_rows_local!(J, dm, rows, diag). They take any AbstractVector, and pass a Vector or a prefix view view(buf, 1:n) of one without a copy.
  • LibPETSc.IS(dm, loc => dof, ...), the index set of whole DMStag fields, for set_fieldsplit_is!.
  • length(is) on an IS: its global size, as length of a PetscVec.
  • on_lower_side(loc, axis): whether a DMStag location sits on the lower side of its element along axis, so on the axes where it has one more index than there are elements.
  • local_to_local!(dst, dm, src) and the in-place local_to_local!(v, dm), to refresh ghost points.
  • with_product_coordinates(f, dm): read-only access to a DMStag's per-axis coordinates, handed back when f returns.
  • set_matrix_preallocate_only!(dm, flag), so a matrix from dm gets its nonzero pattern from the first assembly.
  • with_field_views!(f, dm, vecs...; fields, read, write): concretely typed views of DMStag local vectors by location => dof, indexed like stencil, handed back when f returns. About 9 allocations per vector, whatever the grid size. The docstring shows two DMs checked out by nesting, with one vector handed back mid-scope for a halo exchange.

v0.5.1

0.5.1 settles how a wrapper relates to its PETSc object and what happens when PETSc calls back into Julia (docs/src/man/naming.md §18), fixes a use-after-free, and adds what a nested or logged solve needs. Working code is most likely to notice the four behaviour changes below; each replaces behaviour that was unsafe or contradicted the docs.

Behaviour changes

  • Handles returned by a LibPETSc Get function are borrowed, as in PETSc: destroy! on them does nothing. This covers snes(ts), ksp(ts), pc(ksp) and callback arguments, which could be destroyed from under a running solver. The 36 Get functions that return a new reference (MatGetFactor, DMLabelGetStratumIS, …; see wrapping/generator/rules/ownership.toml) still return an owner.
  • An exception in a TS callback comes out of solve! or step! as itself, not as a PetscError.
  • LibPETSc.PC is a handle type, PC{PetscLib}, instead of a raw pointer. Code that passes a PC between calls is unaffected; code that expects a Ptr needs pc.ptr.
  • add_boundary! and add_natural_boundary! return dm instead of the boundary number, which LibPETSc.DMAddBoundary still returns.

Fixed

  • Use-after-free: PetscVec(petsclib, array) and PetscVec(petsclib, comm, array) did not keep array alive, so after a garbage collection the vector could use reclaimed memory. ksp \ b with a Julia vector and M * x with a MatShell had the same bug. The same applied to matrices built on CSR arrays once a solver outlived the handle.
  • An exception in a SNES, KSP or MatShell callback unwound through PETSc's C code, which is undefined behaviour. solve!, step! and setup! now rethrow the original exception; a solve started through LibPETSc logs it and throws PetscError.
  • A callback set through a borrowed handle, such as set_function!(f!, snes(ts), r), could be garbage-collected while the solver still used it. Callbacks, the user context and constructor options now live with the PETSc object (naming.md §18.3); the old fields such as snes.user_ctx still work.
  • set_convergence_test! overwrote snes.user_ctx.
  • KSP(petsclib, comm, S::SparseMatrixCSC) leaked its matrix.
  • TSIRK types (-ts_irk_type gauss, …) were lost after finalize and initialize.
  • PetscOptions(petsclib) succeeded on an uninitialized library; it now throws PetscNotInitialized like every other constructor.
  • set_from_options!(ts) ignored the options given to the TS constructor.
  • converged_reason(ksp), solution(snes) and set_from_options!(snes), shown in the manual, did not exist.

Added

  • pc(ksp), with set_type!, type_name and set_fieldsplit_is!, and a Julia :shell preconditioner through set_shell_apply!(apply!, p) and set_shell_setup!(setup!, p).
  • Solver readers: ksp(snes), solution(snes), iteration_number, converged_reason, ksp_iterations(snes), function_norm(snes) and prev_time(ts).
  • Nested solvers without LibPETSc: set_operators!(ksp, A, P = A), set_dm_active!, set_options_prefix! and options_prefix, and set_from_options! on KSP and SNES.
  • set_function_domain_error!(snes), and user_ctx/set_user_ctx! on SNES and TS.
  • Every handle carries an own field, read by owns(obj); constructors take own as a keyword. destroy!(pc) destroys a PC created with LibPETSc.PCCreate.

Changed

  • Every ! function returns the object it mutates (naming.md §7), for example set_type!(ksp, :cg) returns ksp and solve!(x, ksp, b) returns x; about 60 returned nothing. The exceptions are destroy! and other releases, which return nothing, and with_local_array!, which returns its block's result.
  • A callback's return value is ignored: it fails by throwing. Until v0.6, a nonzero Integer still fails the call and warns.
  • KSP, MatShell and the CSR and SparseMatrixCSC PetscMat constructors attach a finalizer on one process, like SNES and TS.
  • save_vtk! and vtk_merge_tensor! are now save_vtk and vtk_merge_tensor, since they mutate no argument; the old names warn until v0.6.
  • MPIPreferences is a test-only dependency.

v0.5.0

PETSc.jl 0.5 wraps PETSc 3.25.4 (PETSc_jll 3.25) and requires Julia 1.12. The low-level LibPETSc bindings are regenerated by a new rules-based generator (wrapping/, see wrapping/WRAPPING.md) that can be rerun for every PETSc release; the hand edits that used to live in src/autowrapped/ are expressed as rules and overrides. This changes the calling convention of many LibPETSc functions.

Breaking changes (low-level LibPETSc)

  • Outputs are returned, not written into caller-supplied handles or Refs. PCCreate(petsclib, comm) returns the PC; KSPGetPC(petsclib, ksp) returns the PC; DMPlexDistribute(petsclib, dm, overlap) returns (sf, dmParallel); ISSorted(petsclib, is) returns a PetscBool; PetscSFGetGraph(petsclib, sf) returns (nroots, nleaves, ilocal, iremote). About 480 functions changed this way (wrapping/DEVIATIONS.md lists every category).
  • XDestroy takes the handle or a Ref to it: PetscViewerDestroy(petsclib, viewer).
  • String enums are Julia Strings. PCSetType(petsclib, pc, "ilu") works directly; Base.unsafe_convert(Ptr{Int8}, "ilu") is no longer accepted, and the hand-written String overloads (src/string_wrappers*.jl) are gone. The registered names are constants: LibPETSc.PCMG == "mg", LibPETSc.KSPGMRES, LibPETSc.MATSEQAIJ, ... XGetType returns a String ("" when unset).
  • PetscKSP -> KSP, PetscSNES -> SNES, AbstractPetscKSP -> AbstractKSP, AbstractPetscSNES -> AbstractSNES; AbstractPETScMemBackend -> AbstractPetscMemBackend (PR #260 naming conventions). The old names remain as deprecated aliases until v0.6.
  • Input arguments accept abstract types (AbstractPetscVec, AbstractVector{<:Number}, Integer), returned handles are concrete (PR #263). A call with unsupported argument types throws instead of silently returning nothing.
  • Callbacks and contexts are Ptr{Cvoid}; const T *x inputs are Vector{T}; char[] inputs are String; const char *x[] outputs return a String.
  • PETSc-owned output arrays with a documented length come back as Vectors (arrays of handles as Vector{IS} etc.); those without one return the raw pointer.
  • PetscSplitOwnership*, PetscSortRemoveDups* and the nmax of PetscOptionsGet*Array take and return their in/out scalar.
  • 95 header-inline functions and macros without a symbol in libpetsc (PetscStrcmp, PetscTime, VecSetValue, MatSetValue, PetscOptionsBegin, ...) are no longer wrapped.
  • Deprecated enum values are not emitted. KSPSetDMActive takes the KSPDMActive flag (PETSc 3.25).

High-level API renamed (naming conventions)

The high-level interface follows docs/src/man/naming.md from v0.5 on. Roughly a hundred names change, and the full rename table is at the end of that page — what follows is what the changes are and how to move.

The register and the shims. scripts/renames.jl is the register: a plain list of old => new pairs plus the internal and unchanged-public sets. src/deprecations.jl, src/public_names.jl, src/audit_names.jl and test/test_deprecations.jl are generated from it by scripts/generate_renames.jl, so they cannot drift apart, and scripts/api_surface.jl --check (run by the test suite) fails if a binding is in none of its sets. Every renamed name keeps a forwarding shim that warns once per call site — through @warn, not Base.depwarn, so it prints whatever --depwarn is set to — and the shims are removed in v0.6.

Exports. PETSc now exports only types and construction entry points:

export LibPETSc
export DMDA, DMStag, DMPlex
export PetscVec, PetscMat, PetscOptions
export KSP, SNES, TS
export petsclibs

v0.4 exported twelve functions and no types at all. audit_petsc_file, set_petsclib, set_library!, unset_library!, library_info, AbstractPetscMemBackend, AbstractPETScMemBackend, determine_memtype, get_petsc_arrays, restore_petsc_arrays and dmda_star_fd_coloring lose their export (HostBackend was exported but never defined). No shim can help here: the replacements are not exported either, so using PETSc code qualifies the call (PETSc.set_library!) or imports the name. The rest of the API is marked public, so names(PETSc) reports it without exporting it.

Construction goes through the type. PetscVec(petsclib, …) replaces VecSeq and as_petsc_vec; PetscMat(petsclib, …) replaces MatSeqAIJ, MatSeqDense, MatCreateSeqAIJ, MatSeqAIJWithArrays and MatAIJ; PetscOptions replaces Options; PetscLibType(path; …) replaces set_petsclib. KSP, SNES and TS are types rather than factory functions, so ksp isa PETSc.KSP holds.

A typed DM hierarchy. DMDA{L,N}, DMStag{L,N} and DMPlex{L} are concrete types under LibPETSc.AbstractPetscDM, not one type with a runtime string flavour. Code annotated ::PetscDM no longer matches — use AbstractPetscDM. PETSc.narrow(dm) turns a low-level handle into the typed one; it queries PETSc, so its return type is a wide Union and hot code should narrow once behind a function barrier. The nine DM-flavour @asserts are gone: dispatch enforces what they checked.

Borrowed handles. A reader that hands back a PETSc object owned by another object — dm(ksp), solution(snes), local_coordinates(dm), tolerances(ts)'s vectors — returns a borrowed handle: no finalizer, and destroy! on it is a no-op (PETSc.owns tells the two apart). Nothing changed at runtime; destroying such a handle was corrupting the owner's already. destroy is now destroy!, per the mutation convention.

Type names are Symbol. type_name on a Vec, Mat, KSP, SNES, TS or DM returns a Symbol, or nothing when PETSc has no type for the object yet, so type_name(ksp) == "gmres" is now false; compare against :gmres. The new set_type!(obj, :gmres) covers Vec, Mat, KSP, SNES and DM as well as TS, and set_type!(obj, "gmres") warns until v0.6. This break has no shim on the reader side.

Argument order, and petsclib dropped. The written vector leads, the DM follows it, and the library is recovered from the object: project_function!(X, dm, time, funcs, ctxs, mode), project_field!(X, dm, time, U, funcs, mode), global_to_local!(lvec, dm, gvec, mode), local_to_global!(gvec, dm, lvec, mode), l2diff(dm, time, funcs, ctxs, X), add_boundary!(dm, …), add_natural_boundary!(dm, …), set_snes_local_fem!(dm), save_vtk!(vec, filename), star_fd_coloring(da). The v0.4 spellings forward and warn, but a call passed through invoke or a function reference is not caught.

Callback setters take the callback first, only. set_function!, set_snes_jacobian!, set_convergence_test!, set_compute_rhs!, set_compute_operators!, set_rhs_function!, set_rhs_jacobian!, set_ifunction!, set_ijacobian!, set_monitor! and add_coarsen_hook! no longer accept the subject-first order v0.4 also offered, so do syntax is always available. No shim: dispatch cannot tell the two orders apart.

Dimension-correct returns. corners, ghost_corners, local_indices, global_indices, info and size answer with the DM's own dimension: lower/upper are CartesianIndex{N}, size/nextra are NTuple{N,Int}, and center/vertex are keyed x, y (, z) by dimension. v0.4 padded everything to three, so corners(dm2d).size[3] returned 1 and now throws a BoundsError. This is also a performance fix: the tuples are built with ntuple(…, Val(N)) and infer concretely instead of allocating. info drops the duplicate s field, renames dof to ndofs and mpi_proc_size to procs, and ghost_corners(::DMStag) has no nextra field: DMStagGetGhostCorners never reported one, though the v0.4 docstring promised it.

ownership_range(A) is 1-based. That was already the default; the positional ownership_range(A, false) still returns PETSc's numbering, warns, and is a MethodError in v0.6. set_values! spells its index parameters rows_0b/cols_0b and star_fd_coloring returns row_coo_local_0b, col_coo_local_0b, perturb_cols_1b, coo_idxs_1b and local_rows_1b, so every bulk index vector says which base it uses.

Smaller changes. library_info() returns (; source, path, scalar, int, real) and prints its old report from a show method. Argument problems raise ArgumentError, DimensionMismatch or PetscNotInitialized rather than AssertionError or a bare error. PETSc.KSP(…) / PETSc.SNES(…) construct the LibPETSc.KSP / LibPETSc.SNES types.

The rename table, and the reasoning behind each rule, are in docs/src/man/naming.md; the C-function-to-Julia-name lookup is the generated "C to Julia name index" page in the manual.

Changed

  • ForwardDiff, UnicodePlots, Statistics and Pkg are no longer dependencies of the package: nothing in src/ used them, and the tests and examples that do now pull them through [extras] and examples/Project.toml. Installing PETSc.jl resolves 86 packages instead of 121, which cuts cold precompilation by roughly a factor of five.

  • Only one PetscInt width of PETSc_jll is loaded per process (#241): PETSc.petsclibs holds the four scalar variants of Int64 by default, PETSc.set_petscint!(Int32) switches to the Int32 libraries on the next session. Loading both widths cross-binds the identically named HYPRE/SuperLU_DIST symbols of the two integer ABIs. Code indexing petsclibs[5:8] breaks.

Added

  • PetscSF communication: PetscSFBcastBegin/End, PetscSFReduceBegin/End, PetscSFFetchAndOpBegin/End (hand-written; getAPI.py rejects MPI_Datatype functions).
  • PetscDraw and TSMonitorLGCtx handles work (they were empty placeholder structs).
  • Windows CI with MPI (PETSc_jll 3.25.4 ships MPI-enabled Windows binaries).
  • Documentation pages for every wrapper file, and the maintainer guide "Regenerating the wrappers".
  • Test coverage: test/wrapper_quality.jl (every generated method infers a concrete return type; representatives are allocation free), test/wrapper_leaks.jl, an ambiguity budget, test/low_level_petscsf.jl.

Fixed

  • PetscBool is one byte, matching PETSc's typedef bool PetscBool (since 3.24). The previous 32-bit type read three bytes PETSc never wrote, so a PETSC_FALSE output could come back as true (#268), Vector{PetscBool} arguments had the wrong stride and the MatFactorInfo, PetscFEGeom and PetscEventPerfInfo struct layouts were off.

  • Re-initialising PETSc after finalize works with Tao, TaoTerm and TSTrajectory (PETSc 3.25.x does not reset their RegisterAllCalled flags; on Windows the internal symbols are not exported, see PETSc.tao_usable_after_reinitialize()).

  • Re-initialising PETSc no longer overwrites three bytes of PETSc's memory: the TaoRegisterAllCalled, TaoTermRegisterAllCalled and TSTrajectoryRegisterAllCalled flags were reset with a 4-byte store, while PetscBool is 1 byte.

  • unsafe_local_array no longer touches a destroyed vector or a finalized library.

  • Double free of DMDA coordinate vectors; PCMGSetLevels reading uninitialised communicators.

  • Block assignment A[rows, cols] = block on a PetscMat works (#248, #271). It threw a MethodError, and the values were laid out column by column where MatSetValues reads them row by row. A block whose size does not match the index ranges raises a DimensionMismatch.

  • PetscOptions records the initialize/finalize cycle it was created in, like PetscVec, PetscMat, KSP, SNES, TS and the DMs, so destroy! and its finalizer no longer call PetscOptionsDestroy on an object from an earlier cycle (#270).

Removed

  • The old PythonCall-based generator (wrapping/generatejuliabindings.jl), src/deprecated/, src/startup.jl, src/string_wrappers*.jl.
  • LibPETSc.petsc_version and PETSc.SUPPORTED_PETSC_VERSIONS, added in 0.4.14 for running on PETSc 3.22 and 3.25. 0.5 binds PETSc 3.25 only; PETSc.check_wrappers_version(petsclib).installed_version returns the library version.