From 8c4434352f70a62909eb6b0973bff8f2c100221d Mon Sep 17 00:00:00 2001 From: filoferra <66474175+filoferra@users.noreply.github.com> Date: Mon, 28 Sep 2026 12:49:04 +0200 Subject: [PATCH 1/5] Tests: run the manual's example tests again; drop the stale skips --- docs/src/man/tao_lowlevel.md | 2 ++ test/01-hello.jl | 7 ------- test/doc_examples_is.jl | 22 ++++++++++++++++++---- test/doc_examples_viewer.jl | 36 ++++++++++++++++++++++++------------ test/runtests.jl | 12 ++++++++++-- 5 files changed, 54 insertions(+), 25 deletions(-) delete mode 100644 test/01-hello.jl diff --git a/docs/src/man/tao_lowlevel.md b/docs/src/man/tao_lowlevel.md index cf132f546..80aee9248 100644 --- a/docs/src/man/tao_lowlevel.md +++ b/docs/src/man/tao_lowlevel.md @@ -93,6 +93,8 @@ Available through `TaoSetType`: - `TAOBNTL`: Bound-constrained Newton trust-region - `TAOTRON`: Trust-region Newton method +The types built on an LMVM matrix (`lmvm`, `blmvm`, `bncg`, `bqnls`, `bqnkls`, `bntl` and `bntr`) fail after a `PETSc.finalize`/`PETSc.initialize` cycle in which a `KSP` was created: PETSc 3.25 forgets the LMVM matrix types at `PetscFinalize` and has no public way to register them again, so `TaoSetType` throws with "Unknown Mat type given: lmvmbfgs". Initialize once per Julia session, or restart Julia. `cg`, `nm`, `nls`, `ntr`, `ntl` and `tron` are not affected. + - **Constrained**: - `TAOALMM`: Augmented Lagrangian multiplier method - `TAOIPM`: Interior point method diff --git a/test/01-hello.jl b/test/01-hello.jl deleted file mode 100644 index 6fb796699..000000000 --- a/test/01-hello.jl +++ /dev/null @@ -1,7 +0,0 @@ -using MPI -using PETSc -MPI.Initialized() || MPI.Init() - -comm = MPI.COMM_WORLD -println("Hello world, I am $(MPI.Comm_rank(comm)) of $(MPI.Comm_size(comm))") -MPI.Barrier(comm) \ No newline at end of file diff --git a/test/doc_examples_is.jl b/test/doc_examples_is.jl index 8d3f6c3e0..44cea84ab 100644 --- a/test/doc_examples_is.jl +++ b/test/doc_examples_is.jl @@ -61,10 +61,24 @@ using MPI PETSc.LibPETSc.ISDestroy(petsclib, is_block) end - @testset "Set Operations - skipped due to complex API" begin - # Note: IS set operations (ISSum, ISDifference, ISExpand) have complex - # usage patterns that require careful setup. Skip for now. - @test_skip true + @testset "Set Operations" begin + is1 = PETSc.LibPETSc.ISCreateGeneral(petsclib, test_comm, 3, PetscInt[0, 2, 4], + PETSc.LibPETSc.PETSC_COPY_VALUES) + is2 = PETSc.LibPETSc.ISCreateGeneral(petsclib, test_comm, 3, PetscInt[2, 3, 4], + PETSc.LibPETSc.PETSC_COPY_VALUES) + function indices(is) + idx = PETSc.LibPETSc.ISGetIndices(petsclib, is) + out = copy(idx) + PETSc.LibPETSc.ISRestoreIndices(petsclib, is, idx) + PETSc.LibPETSc.ISDestroy(petsclib, is) + return out + end + @test indices(PETSc.LibPETSc.ISSum(petsclib, is1, is2)) == [0, 2, 3, 4] + @test indices(PETSc.LibPETSc.ISDifference(petsclib, is1, is2)) == [0] + @test indices(PETSc.LibPETSc.ISIntersect(petsclib, is1, is2)) == [2, 4] + @test indices(PETSc.LibPETSc.ISComplement(petsclib, is1, 0, 6)) == [1, 3, 5] + PETSc.LibPETSc.ISDestroy(petsclib, is1) + PETSc.LibPETSc.ISDestroy(petsclib, is2) end @testset "Querying Properties" begin diff --git a/test/doc_examples_viewer.jl b/test/doc_examples_viewer.jl index 22d55dbf8..54782de10 100644 --- a/test/doc_examples_viewer.jl +++ b/test/doc_examples_viewer.jl @@ -40,18 +40,30 @@ using MPI @test viewer_stderr_world != C_NULL end - @testset "ASCII File Output - skipped due to wrapper API issues" begin - # Note: PetscViewerASCIIOpen and PetscViewerBinaryOpen have wrapper signatures - # that don't match Julia's calling convention. They expect viewer::PetscViewer - # but need to accept Ref{PetscViewer} to work properly. - # Skip these tests for now. - @test_skip true - end - - @testset "Binary File I/O - skipped due to wrapper API issues" begin - # Note: PetscViewerBinaryOpen has wrapper signature issues - # Skip this test for now - @test_skip true + @testset "ASCII and binary file I/O" begin + x = PETSc.PetscVec(petsclib, [1.0, 2.0, 3.0]) + cd(mktempdir()) do + viewer = PETSc.LibPETSc.PetscViewerASCIIOpen(petsclib, test_comm, "output.txt") + PETSc.LibPETSc.PetscViewerPushFormat(petsclib, viewer, PETSc.LibPETSc.PETSC_VIEWER_ASCII_MATLAB) + PETSc.LibPETSc.VecView(petsclib, x, viewer) + PETSc.LibPETSc.PetscViewerPopFormat(petsclib, viewer) + PETSc.LibPETSc.PetscViewerDestroy(petsclib, viewer) + @test occursin("2.", read("output.txt", String)) + + # a vector saved in binary loads back unchanged + viewer = PETSc.LibPETSc.PetscViewerBinaryOpen(petsclib, test_comm, "checkpoint.dat", + PETSc.LibPETSc.FILE_MODE_WRITE) + PETSc.LibPETSc.VecView(petsclib, x, viewer) + PETSc.LibPETSc.PetscViewerDestroy(petsclib, viewer) + viewer = PETSc.LibPETSc.PetscViewerBinaryOpen(petsclib, test_comm, "checkpoint.dat", + PETSc.LibPETSc.FILE_MODE_READ) + y = PETSc.LibPETSc.VecCreate(petsclib, test_comm) + PETSc.LibPETSc.VecLoad(petsclib, y, viewer) + PETSc.LibPETSc.PetscViewerDestroy(petsclib, viewer) + @test y[:] == [1.0, 2.0, 3.0] + PETSc.destroy!(y) + end + PETSc.destroy!(x) end PETSc.finalize(petsclib) diff --git a/test/runtests.jl b/test/runtests.jl index d941b1d2b..cb2459afb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -74,6 +74,15 @@ include("low_level_petscsection.jl") # Low-level PetscSection functions include("low_level_petscsf.jl") # Low-level PetscSF graph and communication functions include("petscbool.jl") # PetscBool is one byte (PETSc >= 3.24) include("low_level_tao.jl") # Low-level Tao functions +include("doc_examples_is.jl") # the IS examples in the manual +# The lmvm Tao types work only in the first PETSc cycle of a process (see +# _reset_stale_register_flags in src/init.jl), so the Tao manual examples run in a fresh one +@testset "Tao manual examples, fresh process" begin + cmd = `$(Base.julia_cmd()) --project=. $(joinpath(@__DIR__, "doc_examples_tao.jl"))` + @test success(pipeline(cmd, stderr = stderr)) +end +include("doc_examples_ts.jl") # the TS examples in the manual +include("doc_examples_viewer.jl") # the PetscViewer examples in the manual include("test_destroy.jl") # destroy! guards: stale cycle, double destroy include("handles.jl") # destroy! on IS, AO, PF, Tao; ISColoringGetIS ownership include("handle_arrays.jl") # C arrays of handles go back to their release function @@ -83,8 +92,7 @@ include("test_api_surface.jl") # scripts/api_surface.jl --check: the register c include("testutils.jl") -# Run helper tests for SNES and TAO -include("snes_helpers.jl") +# Run helper tests for TAO (the SNES ones ran above) include("tao_helpers.jl") # Run the examples to make sure they all work From 1007d4aefe6dfd9eddaa4775a1da840719ccdc88 Mon Sep 17 00:00:00 2001 From: filoferra <66474175+filoferra@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:29:37 +0200 Subject: [PATCH 2/5] Tests: one folder per group, and run a subset with Pkg.test(test_args = [...]) The 62 test files move into core, vecmat, solvers, dm, lowlevel, regression, examples and mpi, without the test_/low_level_/mpi_/ doc_examples_ prefixes; no test changes beyond paths. runtests.jl runs the groups in order, and test_args selects some of them. The deprecation tests are generated into test/core/deprecations.jl. The contributing page says how to run one group. --- docs/src/man/contributing.md | 10 + docs/src/man/naming.md | 6 +- examples/ex12_mpi_test.jl | 4 +- examples/ex12_test.jl | 2 +- examples/ex17_mpi_test.jl | 4 +- examples/ex17_test.jl | 2 +- examples/ex62_mpi_test.jl | 2 +- examples/ex62_test.jl | 2 +- examples/ex69_mpi_test.jl | 2 +- examples/ex69_test.jl | 2 +- scripts/generate_renames.jl | 8 +- scripts/renames.jl | 4 +- .../api_surface.jl} | 2 +- test/{test_audit.jl => core/audit.jl} | 4 +- test/{ => core}/bang_returns.jl | 2 +- test/{ => core}/blas_threads.jl | 2 +- .../deprecations.jl} | 0 test/{test_destroy.jl => core/destroy.jl} | 2 +- test/{test_errors.jl => core/errors.jl} | 0 test/{ => core}/handle_arrays.jl | 2 +- test/{ => core}/handles.jl | 2 +- test/{ => core}/init.jl | 0 test/{ => core}/lib.jl | 0 test/{ => core}/lifetimes.jl | 2 +- test/{ => core}/options.jl | 0 test/{ => core}/petscbool.jl | 0 test/{old_test.jl => core/smoke.jl} | 0 test/{ => dm}/dm_dimension.jl | 0 test/{ => dm}/dmda.jl | 0 test/{ => dm}/dmnetwork.jl | 0 test/{ => dm}/dmplex.jl | 2 +- test/{ => dm}/dmproduct.jl | 0 test/{ => dm}/dmshell.jl | 0 test/{ => dm}/dmstag.jl | 0 test/{ => dm}/dmstag_halos.jl | 2 +- test/{test_dmstag.jl => dm/dmstag_serial.jl} | 0 test/{ => dm}/dmstag_stencils.jl | 2 +- test/{ => dm}/dmstag_views.jl | 2 +- test/{ => examples}/examples.jl | 2 +- .../manual_is.jl} | 0 .../manual_tao.jl} | 0 .../manual_ts.jl} | 0 .../manual_viewer.jl} | 0 test/{ => examples}/mpi_examples.jl | 2 +- test/{low_level_is.jl => lowlevel/is.jl} | 0 .../petscsection.jl} | 0 .../petscsf.jl} | 0 test/{ => lowlevel}/snes_helpers.jl | 0 test/{low_level_tao.jl => lowlevel/tao.jl} | 0 test/{ => lowlevel}/tao_helpers.jl | 0 test/{low_level_ts.jl => lowlevel/ts.jl} | 0 .../viewer.jl} | 0 test/{ => lowlevel}/wrapper_leaks.jl | 0 test/{ => lowlevel}/wrapper_quality.jl | 0 test/{ => lowlevel}/wrapper_signatures.jl | 0 .../blas_threads.jl} | 2 +- .../dmstag_halos.jl} | 2 +- test/{mpimat.jl => mpi/mat.jl} | 0 test/{mpivec.jl => mpi/vec.jl} | 0 test/{ => regression}/ts_ex16.jl | 2 +- test/{ => regression}/ts_ex51.jl | 2 +- test/{ => regression}/ts_ex51_implicit.jl | 2 +- test/runtests.jl | 186 ++++++++++-------- test/{ => solvers}/ksp.jl | 0 test/{ => solvers}/pc.jl | 0 test/{ => solvers}/snes.jl | 0 .../snes_callbacks.jl} | 0 test/{ => solvers}/solver_api.jl | 2 +- test/{ => solvers}/ts.jl | 2 +- test/{ => solvers}/ts_long_runs.jl | 2 +- test/{ => solvers}/ts_scenarios.jl | 4 +- test/{ => vecmat}/mat.jl | 0 test/{ => vecmat}/mat_vec_methods.jl | 2 +- test/{ => vecmat}/matshell.jl | 0 test/{ => vecmat}/vec.jl | 0 wrapping/DEVIATIONS.md | 4 +- wrapping/WRAPPING.md | 6 +- 77 files changed, 161 insertions(+), 135 deletions(-) rename test/{test_api_surface.jl => core/api_surface.jl} (92%) rename test/{test_audit.jl => core/audit.jl} (97%) rename test/{ => core}/bang_returns.jl (98%) rename test/{ => core}/blas_threads.jl (97%) rename test/{test_deprecations.jl => core/deprecations.jl} (100%) rename test/{test_destroy.jl => core/destroy.jl} (99%) rename test/{test_errors.jl => core/errors.jl} (100%) rename test/{ => core}/handle_arrays.jl (99%) rename test/{ => core}/handles.jl (99%) rename test/{ => core}/init.jl (100%) rename test/{ => core}/lib.jl (100%) rename test/{ => core}/lifetimes.jl (99%) rename test/{ => core}/options.jl (100%) rename test/{ => core}/petscbool.jl (100%) rename test/{old_test.jl => core/smoke.jl} (100%) rename test/{ => dm}/dm_dimension.jl (100%) rename test/{ => dm}/dmda.jl (100%) rename test/{ => dm}/dmnetwork.jl (100%) rename test/{ => dm}/dmplex.jl (99%) rename test/{ => dm}/dmproduct.jl (100%) rename test/{ => dm}/dmshell.jl (100%) rename test/{ => dm}/dmstag.jl (100%) rename test/{ => dm}/dmstag_halos.jl (99%) rename test/{test_dmstag.jl => dm/dmstag_serial.jl} (100%) rename test/{ => dm}/dmstag_stencils.jl (99%) rename test/{ => dm}/dmstag_views.jl (99%) rename test/{ => examples}/examples.jl (90%) rename test/{doc_examples_is.jl => examples/manual_is.jl} (100%) rename test/{doc_examples_tao.jl => examples/manual_tao.jl} (100%) rename test/{doc_examples_ts.jl => examples/manual_ts.jl} (100%) rename test/{doc_examples_viewer.jl => examples/manual_viewer.jl} (100%) rename test/{ => examples}/mpi_examples.jl (90%) rename test/{low_level_is.jl => lowlevel/is.jl} (100%) rename test/{low_level_petscsection.jl => lowlevel/petscsection.jl} (100%) rename test/{low_level_petscsf.jl => lowlevel/petscsf.jl} (100%) rename test/{ => lowlevel}/snes_helpers.jl (100%) rename test/{low_level_tao.jl => lowlevel/tao.jl} (100%) rename test/{ => lowlevel}/tao_helpers.jl (100%) rename test/{low_level_ts.jl => lowlevel/ts.jl} (100%) rename test/{low_level_viewer.jl => lowlevel/viewer.jl} (100%) rename test/{ => lowlevel}/wrapper_leaks.jl (100%) rename test/{ => lowlevel}/wrapper_quality.jl (100%) rename test/{ => lowlevel}/wrapper_signatures.jl (100%) rename test/{mpi_blas_threads.jl => mpi/blas_threads.jl} (97%) rename test/{mpi_dmstag_halos.jl => mpi/dmstag_halos.jl} (98%) rename test/{mpimat.jl => mpi/mat.jl} (100%) rename test/{mpivec.jl => mpi/vec.jl} (100%) rename test/{ => regression}/ts_ex16.jl (98%) rename test/{ => regression}/ts_ex51.jl (97%) rename test/{ => regression}/ts_ex51_implicit.jl (98%) rename test/{ => solvers}/ksp.jl (100%) rename test/{ => solvers}/pc.jl (100%) rename test/{ => solvers}/snes.jl (100%) rename test/{test_snes.jl => solvers/snes_callbacks.jl} (100%) rename test/{ => solvers}/solver_api.jl (99%) rename test/{ => solvers}/ts.jl (99%) rename test/{ => solvers}/ts_long_runs.jl (99%) rename test/{ => solvers}/ts_scenarios.jl (98%) rename test/{ => vecmat}/mat.jl (100%) rename test/{ => vecmat}/mat_vec_methods.jl (98%) rename test/{ => vecmat}/matshell.jl (100%) rename test/{ => vecmat}/vec.jl (100%) diff --git a/docs/src/man/contributing.md b/docs/src/man/contributing.md index b873b3bab..3ca4188f6 100644 --- a/docs/src/man/contributing.md +++ b/docs/src/man/contributing.md @@ -20,6 +20,16 @@ Since there are usually only a limited number of new or updated functions betwee Make sure that the tests work! +#### Running the tests +The tests live in `test/`, one folder per group: `core` (initialization, handles, lifetimes, the API register), `vecmat`, `solvers`, `dm`, `lowlevel` (the generated `LibPETSc` wrappers), `regression`, `examples` (the scripts in `examples/` and the manual's examples) and `mpi` (files run on 4 ranks). A new test file goes in its group's folder and is listed in that group's block in `test/runtests.jl`. + +The whole suite takes about 15 minutes. To run only some groups: + +```julia +using Pkg +Pkg.test("PETSc"; test_args = ["dm", "mpi"]) +``` + #### Adding new functionality Please open a pull request to add any of the above contributions. diff --git a/docs/src/man/naming.md b/docs/src/man/naming.md index 1cf242297..d89c1fe43 100644 --- a/docs/src/man/naming.md +++ b/docs/src/man/naming.md @@ -150,7 +150,7 @@ The names stay short, and the package pays for it with a convention rather than ```julia d = dm(ksp) # not dm = dm(ksp) -s = snes(ts) # as test/ts.jl already writes it +s = snes(ts) # as test/solvers/ts.jl already writes it k = ksp(ts) ``` @@ -649,7 +649,7 @@ Argument problems raise standard Julia exceptions. `@assert` is reserved for inv | Library not initialized | `PetscNotInitialized` | | Error returned by PETSc itself | `PetscError` (existing) | -Every high-level constructor that creates a PETSc object (`PetscVec`, `PetscMat`, `PetscOptions`, `KSP`, `SNES`, `TS` and the DM types) checks that its library is initialized before calling PETSc, so a missing `initialize` is reported as `PetscNotInitialized` and not as the `PetscError` PETSc would raise. `test/test_errors.jl` checks each of them. `PetscOptions` is included although PETSc's `PetscOptionsCreate` works before `PetscInitialize`: the object records the library's current `age`, `initialize` advances it, so an options database created first would already be stale and `destroy!` would skip it. +Every high-level constructor that creates a PETSc object (`PetscVec`, `PetscMat`, `PetscOptions`, `KSP`, `SNES`, `TS` and the DM types) checks that its library is initialized before calling PETSc, so a missing `initialize` is reported as `PetscNotInitialized` and not as the `PetscError` PETSc would raise. `test/core/errors.jl` checks each of them. `PetscOptions` is included although PETSc's `PetscOptionsCreate` works before `PetscInitialize`: the object records the library's current `age`, `initialize` advances it, so an options database created first would already be stale and `destroy!` would skip it. ```julia length(A) == prod(sz) || @@ -765,7 +765,7 @@ The last row is policy with no instances, and that is the point of writing it do ### 17.3 Test coverage The main test suite is converted to the new names, so CI exercises the API that ships. -`test/test_deprecations.jl` calls every shim and asserts the warning is emitted, and asserts a throw for any entry marked as an erroring stub. It is generated from `scripts/renames.jl` too, so a rename cannot land without its shim being covered. +`test/core/deprecations.jl` calls every shim and asserts the warning is emitted, and asserts a throw for any entry marked as an erroring stub. It is generated from `scripts/renames.jl` too, so a rename cannot land without its shim being covered. ### Rename table diff --git a/examples/ex12_mpi_test.jl b/examples/ex12_mpi_test.jl index ec9e0a1bd..c4dba0f3b 100644 --- a/examples/ex12_mpi_test.jl +++ b/examples/ex12_mpi_test.jl @@ -1,10 +1,10 @@ # MPI subprocess tests for examples/ex12.jl. -# Picked up by test/examples.jl (plain Julia); each test internally spawns mpiexec. +# Picked up by test/examples/examples.jl (plain Julia); each test internally spawns mpiexec. # Each test launches ex12.jl as an MPI subprocess and checks L² error. # # Run via: # julia --project examples/ex12_mpi_test.jl -# or through the project test suite (picked up by test/examples.jl). +# or through the project test suite (picked up by test/examples/examples.jl). using Test using MPI diff --git a/examples/ex12_test.jl b/examples/ex12_test.jl index 396cc428e..663ff954a 100644 --- a/examples/ex12_test.jl +++ b/examples/ex12_test.jl @@ -4,7 +4,7 @@ # # Run via: # julia --project examples/ex12_test.jl -# or through the project test suite (picked up automatically by test/examples.jl). +# or through the project test suite (picked up automatically by test/examples/examples.jl). using Test diff --git a/examples/ex17_mpi_test.jl b/examples/ex17_mpi_test.jl index b41ae91f3..bac098ba9 100644 --- a/examples/ex17_mpi_test.jl +++ b/examples/ex17_mpi_test.jl @@ -1,9 +1,9 @@ # MPI subprocess tests for examples/ex17.jl. -# Picked up by test/examples.jl (plain Julia); each test internally spawns mpiexec. +# Picked up by test/examples/examples.jl (plain Julia); each test internally spawns mpiexec. # # Run via: # julia --project examples/ex17_mpi_test.jl -# or through the project test suite (picked up by test/examples.jl). +# or through the project test suite (picked up by test/examples/examples.jl). using Test using MPI diff --git a/examples/ex17_test.jl b/examples/ex17_test.jl index cacb25ac6..6b1e628b7 100644 --- a/examples/ex17_test.jl +++ b/examples/ex17_test.jl @@ -3,7 +3,7 @@ # # Run via: # julia --project examples/ex17_test.jl -# or through the project test suite (picked up by test/examples.jl). +# or through the project test suite (picked up by test/examples/examples.jl). using Test diff --git a/examples/ex62_mpi_test.jl b/examples/ex62_mpi_test.jl index d235f5bec..b7f2ff0c9 100644 --- a/examples/ex62_mpi_test.jl +++ b/examples/ex62_mpi_test.jl @@ -7,7 +7,7 @@ # # Run via: # julia --project examples/ex62_mpi_test.jl -# or through the project test suite (picked up by test/examples.jl). +# or through the project test suite (picked up by test/examples/examples.jl). using Test using MPI diff --git a/examples/ex62_test.jl b/examples/ex62_test.jl index b10fb3592..32537ccf5 100644 --- a/examples/ex62_test.jl +++ b/examples/ex62_test.jl @@ -4,7 +4,7 @@ # # Run via: # julia --project examples/ex62_test.jl -# or through the project test suite (picked up by test/examples.jl). +# or through the project test suite (picked up by test/examples/examples.jl). using Test diff --git a/examples/ex69_mpi_test.jl b/examples/ex69_mpi_test.jl index a0f168c46..de18e1063 100644 --- a/examples/ex69_mpi_test.jl +++ b/examples/ex69_mpi_test.jl @@ -6,7 +6,7 @@ # # Run via: # julia --project examples/ex69_mpi_test.jl -# or through the project test suite (picked up by test/examples.jl). +# or through the project test suite (picked up by test/examples/examples.jl). using Test using MPI diff --git a/examples/ex69_test.jl b/examples/ex69_test.jl index 3bbd83f01..477bca64e 100644 --- a/examples/ex69_test.jl +++ b/examples/ex69_test.jl @@ -4,7 +4,7 @@ # # Run via: # julia --project examples/ex69_test.jl -# or through the project test suite (picked up by test/examples.jl). +# or through the project test suite (picked up by test/examples/examples.jl). using Test diff --git a/scripts/generate_renames.jl b/scripts/generate_renames.jl index 747061ad5..7814230dd 100644 --- a/scripts/generate_renames.jl +++ b/scripts/generate_renames.jl @@ -7,7 +7,7 @@ # src/deprecations.jl forwarding shims (§17) # src/public_names.jl the `public` declaration (§13.1) # src/audit_names.jl the name sets src/audit.jl matches against -# test/test_deprecations.jl one test per shim (§17.3) +# test/core/deprecations.jl one test per shim (§17.3) # # None of those four files is edited by hand. @@ -263,7 +263,7 @@ the garbage collector rather than performing it, but the object is accounted for end # --------------------------------------------------------------------------- -# test/test_deprecations.jl +# test/core/deprecations.jl # --------------------------------------------------------------------------- function write_tests(path) @@ -403,5 +403,5 @@ check_register() write_deprecations(joinpath(ROOT, "src", "deprecations.jl")) write_public(joinpath(ROOT, "src", "public_names.jl")) write_audit_names(joinpath(ROOT, "src", "audit_names.jl")) -write_tests(joinpath(ROOT, "test", "test_deprecations.jl")) -println("wrote src/deprecations.jl, src/public_names.jl, src/audit_names.jl, test/test_deprecations.jl") +write_tests(joinpath(ROOT, "test", "core", "deprecations.jl")) +println("wrote src/deprecations.jl, src/public_names.jl, src/audit_names.jl, test/core/deprecations.jl") diff --git a/scripts/renames.jl b/scripts/renames.jl index 30c58eb56..bed1505ff 100644 --- a/scripts/renames.jl +++ b/scripts/renames.jl @@ -6,7 +6,7 @@ # src/deprecations.jl the forwarding shims (§17) # src/public_names.jl the `public` declaration (§13.1) # src/audit_names.jl the creator/destroyer name sets used by src/audit.jl -# test/test_deprecations.jl one test per shim (§17.3) +# test/core/deprecations.jl one test per shim (§17.3) # (the rename table at the end of docs/src/man/naming.md) # # Run `julia --project=. scripts/generate_renames.jl` after editing. @@ -273,7 +273,7 @@ const CUSTOM_SHIMS = Dict{Symbol, String}( # These keep an argument the v0.5 signature no longer takes and warn when it is # passed, so they cannot be expressed as `old => new`. They are emitted verbatim # into src/deprecations.jl and removed with it in v0.6. `test` is a test body -# appended to test/test_deprecations.jl. +# appended to test/core/deprecations.jl. # --------------------------------------------------------------------------- const EXTRA_SHIMS = NamedTuple{(:name, :code, :test), Tuple{String, String, String}}[ diff --git a/test/test_api_surface.jl b/test/core/api_surface.jl similarity index 92% rename from test/test_api_surface.jl rename to test/core/api_surface.jl index 1b92330f7..45a7446f6 100644 --- a/test/test_api_surface.jl +++ b/test/core/api_surface.jl @@ -8,7 +8,7 @@ using Test using PETSc -include(joinpath(@__DIR__, "..", "scripts", "api_surface.jl")) +include(joinpath(pkgdir(PETSc), "scripts", "api_surface.jl")) @testset "api_surface --check" begin absent = APISurface.unregistered() diff --git a/test/test_audit.jl b/test/core/audit.jl similarity index 97% rename from test/test_audit.jl rename to test/core/audit.jl index 21445085f..8188d8bf5 100644 --- a/test/test_audit.jl +++ b/test/core/audit.jl @@ -1,8 +1,8 @@ using Test using PETSc -const LEAKY = joinpath(@__DIR__, "fixtures", "leaky.jl") -const CONSTRUCTS = joinpath(@__DIR__, "fixtures", "constructs.jl") +const LEAKY = joinpath(dirname(@__DIR__), "fixtures", "leaky.jl") +const CONSTRUCTS = joinpath(dirname(@__DIR__), "fixtures", "constructs.jl") @testset "audit_file" begin report = PETSc.audit_file(LEAKY; verbose = false) diff --git a/test/bang_returns.jl b/test/core/bang_returns.jl similarity index 98% rename from test/bang_returns.jl rename to test/core/bang_returns.jl index 417f71f71..551a5499d 100644 --- a/test/bang_returns.jl +++ b/test/core/bang_returns.jl @@ -1,4 +1,4 @@ -# test/bang_returns.jl +# test/core/bang_returns.jl # A `!` function returns the object it mutates (docs/src/man/naming.md §7), with # the exceptions §7 lists: releases and package-state setters return `nothing`, # and a do-block function returns the block's result. diff --git a/test/blas_threads.jl b/test/core/blas_threads.jl similarity index 97% rename from test/blas_threads.jl rename to test/core/blas_threads.jl index 6ba2eca3c..5e5cd322e 100644 --- a/test/blas_threads.jl +++ b/test/core/blas_threads.jl @@ -1,4 +1,4 @@ -# test/blas_threads.jl +# test/core/blas_threads.jl # PETSc's BLAS runs in Julia's OpenBLAS pool, so `-blas_num_threads` has to size # that pool: PETSc's own setter cannot reach it. diff --git a/test/test_deprecations.jl b/test/core/deprecations.jl similarity index 100% rename from test/test_deprecations.jl rename to test/core/deprecations.jl diff --git a/test/test_destroy.jl b/test/core/destroy.jl similarity index 99% rename from test/test_destroy.jl rename to test/core/destroy.jl index a05b40e13..3ffcede29 100644 --- a/test/test_destroy.jl +++ b/test/core/destroy.jl @@ -1,4 +1,4 @@ -# test/test_destroy.jl +# test/core/destroy.jl # Destroying PETSc objects must stay safe in the awkward cases: a second # explicit destroy!, and an object left over from an earlier # initialize/finalize cycle. diff --git a/test/test_errors.jl b/test/core/errors.jl similarity index 100% rename from test/test_errors.jl rename to test/core/errors.jl diff --git a/test/handle_arrays.jl b/test/core/handle_arrays.jl similarity index 99% rename from test/handle_arrays.jl rename to test/core/handle_arrays.jl index 1cc8fa3f2..5a02e411b 100644 --- a/test/handle_arrays.jl +++ b/test/core/handle_arrays.jl @@ -1,4 +1,4 @@ -# test/handle_arrays.jl +# test/core/handle_arrays.jl # C arrays of handles: the vector a wrapper returns goes back to the matching # release function, and a vector built in Julia is refused. diff --git a/test/handles.jl b/test/core/handles.jl similarity index 99% rename from test/handles.jl rename to test/core/handles.jl index f7b67fbf4..7338af90a 100644 --- a/test/handles.jl +++ b/test/core/handles.jl @@ -1,4 +1,4 @@ -# test/handles.jl +# test/core/handles.jl # destroy! on the handles with no high-level layer (IS, AO, PF, Tao), and the # ownership of the index sets ISColoringGetIS hands out. diff --git a/test/init.jl b/test/core/init.jl similarity index 100% rename from test/init.jl rename to test/core/init.jl diff --git a/test/lib.jl b/test/core/lib.jl similarity index 100% rename from test/lib.jl rename to test/core/lib.jl diff --git a/test/lifetimes.jl b/test/core/lifetimes.jl similarity index 99% rename from test/lifetimes.jl rename to test/core/lifetimes.jl index 8bebe7d36..32258436f 100644 --- a/test/lifetimes.jl +++ b/test/core/lifetimes.jl @@ -1,4 +1,4 @@ -# test/lifetimes.jl +# test/core/lifetimes.jl # A Vec or Mat built on Julia arrays uses their memory without copying it, so the # arrays must live as long as the PETSc object. Each test drops every Julia # reference to the arrays, forces a collection and reuses the memory, then reads diff --git a/test/options.jl b/test/core/options.jl similarity index 100% rename from test/options.jl rename to test/core/options.jl diff --git a/test/petscbool.jl b/test/core/petscbool.jl similarity index 100% rename from test/petscbool.jl rename to test/core/petscbool.jl diff --git a/test/old_test.jl b/test/core/smoke.jl similarity index 100% rename from test/old_test.jl rename to test/core/smoke.jl diff --git a/test/dm_dimension.jl b/test/dm/dm_dimension.jl similarity index 100% rename from test/dm_dimension.jl rename to test/dm/dm_dimension.jl diff --git a/test/dmda.jl b/test/dm/dmda.jl similarity index 100% rename from test/dmda.jl rename to test/dm/dmda.jl diff --git a/test/dmnetwork.jl b/test/dm/dmnetwork.jl similarity index 100% rename from test/dmnetwork.jl rename to test/dm/dmnetwork.jl diff --git a/test/dmplex.jl b/test/dm/dmplex.jl similarity index 99% rename from test/dmplex.jl rename to test/dm/dmplex.jl index 94f2d9183..d4ed67174 100644 --- a/test/dmplex.jl +++ b/test/dm/dmplex.jl @@ -1,4 +1,4 @@ -# test/dmplex.jl +# test/dm/dmplex.jl # Tests for DMPlex (unstructured mesh) functionality. # Covers both high-level PETSc.* wrappers and low-level LibPETSc.* calls. # Runs across all available petsclibs (different PetscScalar/PetscInt combos). diff --git a/test/dmproduct.jl b/test/dm/dmproduct.jl similarity index 100% rename from test/dmproduct.jl rename to test/dm/dmproduct.jl diff --git a/test/dmshell.jl b/test/dm/dmshell.jl similarity index 100% rename from test/dmshell.jl rename to test/dm/dmshell.jl diff --git a/test/dmstag.jl b/test/dm/dmstag.jl similarity index 100% rename from test/dmstag.jl rename to test/dm/dmstag.jl diff --git a/test/dmstag_halos.jl b/test/dm/dmstag_halos.jl similarity index 99% rename from test/dmstag_halos.jl rename to test/dm/dmstag_halos.jl index 7f2d0a98d..03f3fed68 100644 --- a/test/dmstag_halos.jl +++ b/test/dm/dmstag_halos.jl @@ -1,4 +1,4 @@ -# test/dmstag_halos.jl +# test/dm/dmstag_halos.jl # local_to_local! (in place and into another vector), the product coordinate # do-block, and matrices preallocated without their nonzero pattern. diff --git a/test/test_dmstag.jl b/test/dm/dmstag_serial.jl similarity index 100% rename from test/test_dmstag.jl rename to test/dm/dmstag_serial.jl diff --git a/test/dmstag_stencils.jl b/test/dm/dmstag_stencils.jl similarity index 99% rename from test/dmstag_stencils.jl rename to test/dm/dmstag_stencils.jl index 39b35ebb4..75e9a9929 100644 --- a/test/dmstag_stencils.jl +++ b/test/dm/dmstag_stencils.jl @@ -1,4 +1,4 @@ -# test/dmstag_stencils.jl +# test/dm/dmstag_stencils.jl # DMStag locations keyed by axis, stencils from 1-based indices, and the # operations that take stencils: set_values!, zero_rows_local! and IS. diff --git a/test/dmstag_views.jl b/test/dm/dmstag_views.jl similarity index 99% rename from test/dmstag_views.jl rename to test/dm/dmstag_views.jl index f8b84ef43..be02b7a24 100644 --- a/test/dmstag_views.jl +++ b/test/dm/dmstag_views.jl @@ -1,4 +1,4 @@ -# test/dmstag_views.jl +# test/dm/dmstag_views.jl # with_field_views!: views of DMStag local vectors by field, their types and # allocations, and that every vector is handed back. diff --git a/test/examples.jl b/test/examples/examples.jl similarity index 90% rename from test/examples.jl rename to test/examples/examples.jl index 666eba5f4..cce65a6a8 100644 --- a/test/examples.jl +++ b/test/examples/examples.jl @@ -5,7 +5,7 @@ using MPI using .PETScTestUtils: find_sources @testset "examples" begin - examples_dir = joinpath(dirname(@__DIR__), "examples") + examples_dir = joinpath(pkgdir(PETSc), "examples") examples = find_sources(examples_dir) filter!(file -> readline(file) != "# EXCLUDE FROM TESTING", examples) diff --git a/test/doc_examples_is.jl b/test/examples/manual_is.jl similarity index 100% rename from test/doc_examples_is.jl rename to test/examples/manual_is.jl diff --git a/test/doc_examples_tao.jl b/test/examples/manual_tao.jl similarity index 100% rename from test/doc_examples_tao.jl rename to test/examples/manual_tao.jl diff --git a/test/doc_examples_ts.jl b/test/examples/manual_ts.jl similarity index 100% rename from test/doc_examples_ts.jl rename to test/examples/manual_ts.jl diff --git a/test/doc_examples_viewer.jl b/test/examples/manual_viewer.jl similarity index 100% rename from test/doc_examples_viewer.jl rename to test/examples/manual_viewer.jl diff --git a/test/mpi_examples.jl b/test/examples/mpi_examples.jl similarity index 90% rename from test/mpi_examples.jl rename to test/examples/mpi_examples.jl index 7cc0216c4..816292a44 100644 --- a/test/mpi_examples.jl +++ b/test/examples/mpi_examples.jl @@ -4,7 +4,7 @@ using MPI using .PETScTestUtils: find_sources @testset "mpi examples" begin - examples_dir = joinpath(dirname(@__DIR__), "examples") + examples_dir = joinpath(pkgdir(PETSc), "examples") examples = find_sources(examples_dir) filter!(file -> readline(file) == "# INCLUDE IN MPI TEST", examples) diff --git a/test/low_level_is.jl b/test/lowlevel/is.jl similarity index 100% rename from test/low_level_is.jl rename to test/lowlevel/is.jl diff --git a/test/low_level_petscsection.jl b/test/lowlevel/petscsection.jl similarity index 100% rename from test/low_level_petscsection.jl rename to test/lowlevel/petscsection.jl diff --git a/test/low_level_petscsf.jl b/test/lowlevel/petscsf.jl similarity index 100% rename from test/low_level_petscsf.jl rename to test/lowlevel/petscsf.jl diff --git a/test/snes_helpers.jl b/test/lowlevel/snes_helpers.jl similarity index 100% rename from test/snes_helpers.jl rename to test/lowlevel/snes_helpers.jl diff --git a/test/low_level_tao.jl b/test/lowlevel/tao.jl similarity index 100% rename from test/low_level_tao.jl rename to test/lowlevel/tao.jl diff --git a/test/tao_helpers.jl b/test/lowlevel/tao_helpers.jl similarity index 100% rename from test/tao_helpers.jl rename to test/lowlevel/tao_helpers.jl diff --git a/test/low_level_ts.jl b/test/lowlevel/ts.jl similarity index 100% rename from test/low_level_ts.jl rename to test/lowlevel/ts.jl diff --git a/test/low_level_viewer.jl b/test/lowlevel/viewer.jl similarity index 100% rename from test/low_level_viewer.jl rename to test/lowlevel/viewer.jl diff --git a/test/wrapper_leaks.jl b/test/lowlevel/wrapper_leaks.jl similarity index 100% rename from test/wrapper_leaks.jl rename to test/lowlevel/wrapper_leaks.jl diff --git a/test/wrapper_quality.jl b/test/lowlevel/wrapper_quality.jl similarity index 100% rename from test/wrapper_quality.jl rename to test/lowlevel/wrapper_quality.jl diff --git a/test/wrapper_signatures.jl b/test/lowlevel/wrapper_signatures.jl similarity index 100% rename from test/wrapper_signatures.jl rename to test/lowlevel/wrapper_signatures.jl diff --git a/test/mpi_blas_threads.jl b/test/mpi/blas_threads.jl similarity index 97% rename from test/mpi_blas_threads.jl rename to test/mpi/blas_threads.jl index 0fb7df58b..32e2f1c17 100644 --- a/test/mpi_blas_threads.jl +++ b/test/mpi/blas_threads.jl @@ -1,4 +1,4 @@ -# test/mpi_blas_threads.jl +# test/mpi/blas_threads.jl # Run on several ranks of one node: `initialize` gives each rank one BLAS # thread, unless `-blas_num_threads` or the environment sizes the pool. diff --git a/test/mpi_dmstag_halos.jl b/test/mpi/dmstag_halos.jl similarity index 98% rename from test/mpi_dmstag_halos.jl rename to test/mpi/dmstag_halos.jl index af98efd69..946ace850 100644 --- a/test/mpi_dmstag_halos.jl +++ b/test/mpi/dmstag_halos.jl @@ -1,4 +1,4 @@ -# test/mpi_dmstag_halos.jl +# test/mpi/dmstag_halos.jl # Run on several ranks: local_to_local! in place fills each rank's ghost # points from the owned values its neighbours changed in their local vectors. diff --git a/test/mpimat.jl b/test/mpi/mat.jl similarity index 100% rename from test/mpimat.jl rename to test/mpi/mat.jl diff --git a/test/mpivec.jl b/test/mpi/vec.jl similarity index 100% rename from test/mpivec.jl rename to test/mpi/vec.jl diff --git a/test/ts_ex16.jl b/test/regression/ts_ex16.jl similarity index 98% rename from test/ts_ex16.jl rename to test/regression/ts_ex16.jl index f3e7068b8..2ccaca7d8 100644 --- a/test/ts_ex16.jl +++ b/test/regression/ts_ex16.jl @@ -1,7 +1,7 @@ using Test using PETSc -include(joinpath(dirname(@__DIR__), "examples", "ex16.jl")) +include(joinpath(pkgdir(PETSc), "examples", "ex16.jl")) function capture_stdout_to_string(f::Function) path, io = mktemp() diff --git a/test/ts_ex51.jl b/test/regression/ts_ex51.jl similarity index 97% rename from test/ts_ex51.jl rename to test/regression/ts_ex51.jl index 47762bf3c..a3427afba 100644 --- a/test/ts_ex51.jl +++ b/test/regression/ts_ex51.jl @@ -1,7 +1,7 @@ using Test using PETSc -include(joinpath(dirname(@__DIR__), "examples", "ex51.jl")) +include(joinpath(pkgdir(PETSc), "examples", "ex51.jl")) @testset "TS ex51 example" begin petsclib = PETSc.getlib(PetscScalar = Float64) diff --git a/test/ts_ex51_implicit.jl b/test/regression/ts_ex51_implicit.jl similarity index 98% rename from test/ts_ex51_implicit.jl rename to test/regression/ts_ex51_implicit.jl index 6cfd505d8..f9d0d8709 100644 --- a/test/ts_ex51_implicit.jl +++ b/test/regression/ts_ex51_implicit.jl @@ -1,7 +1,7 @@ using Test using PETSc -include(joinpath(dirname(@__DIR__), "examples", "ex51_implicit.jl")) +include(joinpath(pkgdir(PETSc), "examples", "ex51_implicit.jl")) @testset "TS ex51 implicit example" begin petsclib = PETSc.getlib(PetscScalar = Float64) diff --git a/test/runtests.jl b/test/runtests.jl index cb2459afb..6e8451b14 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -18,102 +18,118 @@ else @info "Testing PETSc.jl with" MPIPreferences.binary MPIPreferences.abi PETSc_jll.host_platform end -# Do the MPI tests first so we do not have mpi running inside MPI -mpi_tests = ("mpivec.jl", "mpimat.jl", "ksp.jl", "dmstag.jl", "mpi_dmstag_halos.jl", "mpi_blas_threads.jl") +# The test groups, one folder each, in the order they run. `Pkg.test(test_args = ["dm"])` +# runs only the named groups; without arguments every group runs. +const GROUPS = ("core", "vecmat", "solvers", "dm", "lowlevel", "regression", "examples", "mpi") +const SELECTED = isempty(ARGS) ? GROUPS : Tuple(ARGS) +for group in SELECTED + group in GROUPS || error("unknown test group \"$group\"; the groups are $(join(GROUPS, ", "))") +end +selected(group) = group in SELECTED -# PETSc_jll >= 3.25.4 has MPI-enabled Windows binaries (MicrosoftMPI), so the MPI tests run everywhere -do_mpi = true +# Runs `file` in a Julia process of its own, on `nranks` MPI ranks if given +function run_separately(file; nranks = nothing) + julia = `$(Base.julia_cmd()) --project=. $(joinpath(@__DIR__, file))` + cmd = isnothing(nranks) ? julia : `$(mpiexec()) -n $nranks $julia` + return success(pipeline(cmd, stderr = stderr)) +end -include("init.jl") -include("blas_threads.jl") # -blas_num_threads sizes the BLAS pool PETSc runs in -include("lib.jl") -include("vec.jl") # autowrapped -include("mat.jl") # autowrapped -include("options.jl") # autowrapped -include("ksp.jl") # autowrapped -include("pc.jl") # high-level PC -include("mat_vec_methods.jl") # copyto!, fill!, zero_rows!, set_option!, diagonal!, isassembled -include("snes.jl") # autowrapped -include("snes_helpers.jl") # small helper tests for SNES return-style wrappers -include("bang_returns.jl") # ! functions return the object they mutate -include("solver_api.jl") # KSP/SNES/TS/PC readers, operators, prefixes, set_from_options! -include("ts.jl") # high-level TS interface -include("ts_long_runs.jl") # equation type, step number, pre/post-step hooks, failure limits -include("dmda.jl") # autowrapped -include("dmstag.jl") # autowrapped -include("dmplex.jl") # DMPlex tests -include("dmnetwork.jl") # new test for DMNetwork example -include("dmshell.jl") # new test for DMShell example -include("dmproduct.jl") # test for DMProduct example -include("matshell.jl") # autowrapped! -include("test_dmstag.jl") -include("dmstag_stencils.jl") # DMStag locations by axis, stencils, stencil assembly -include("dmstag_halos.jl") # local_to_local!, with_product_coordinates, preallocate only -include("dmstag_views.jl") # with_field_views!: types, allocations, hand-back -include("dm_dimension.jl") # dimension-correct DM returns: shape, inference, allocations -include("test_snes.jl") -include("test_audit.jl") # leak auditor -include("test_errors.jl") # argument validation -include("wrapper_signatures.jl") # wrapper arguments take the abstract types -include("wrapper_quality.jl") # every generated method infers a concrete return type; no allocations -include("wrapper_leaks.jl") # repeated create/destroy and Get/Restore pairs do not grow memory -@testset "method ambiguities do not grow" begin - # 130 with the regenerated wrappers (all in the high-level layer); regenerate or rename - # without adding new ones - @test length(detect_ambiguities(PETSc; recursive = true)) <= 130 +if selected("core") + include("core/init.jl") # must run first: it checks a library never initialized + include("core/blas_threads.jl") # -blas_num_threads sizes the BLAS pool PETSc runs in + include("core/lib.jl") + include("core/options.jl") + include("core/bang_returns.jl") # ! functions return the object they mutate + include("core/audit.jl") # leak auditor + include("core/errors.jl") # argument validation + include("core/smoke.jl") # Vec, Mat and KSP end to end + include("core/petscbool.jl") # PetscBool is one byte (PETSc >= 3.24) + include("core/destroy.jl") # destroy! guards: stale cycle, double destroy + include("core/handles.jl") # destroy! on IS, AO, PF, Tao; ISColoringGetIS ownership + include("core/handle_arrays.jl") # C arrays of handles go back to their release function + include("core/lifetimes.jl") # arrays a Vec or Mat wraps live as long as it does + include("core/deprecations.jl") # the v0.4 names still work and warn (the only file calling them) + include("core/api_surface.jl") # scripts/api_surface.jl --check: the register covers the surface + @testset "method ambiguities do not grow" begin + # 130 with the regenerated wrappers (all in the high-level layer); regenerate or rename + # without adding new ones + @test length(detect_ambiguities(PETSc; recursive = true)) <= 130 + end end -include("old_test.jl") -include("low_level_viewer.jl") # Low-level viewer convenience functions -include("low_level_ts.jl") # Low-level TS functions -include("ts_ex51.jl") # Regression test for repeated ex51 solves -include("ts_ex51_implicit.jl") # Regression test for repeated implicit Gauss solves -include("ts_ex16.jl") # Regression test for the van der Pol IMEX example -include("ts_scenarios.jl") # High-level TS: ex16 equivalence + a damping sweep -include("low_level_is.jl") # Low-level IS functions -include("low_level_petscsection.jl") # Low-level PetscSection functions -include("low_level_petscsf.jl") # Low-level PetscSF graph and communication functions -include("petscbool.jl") # PetscBool is one byte (PETSc >= 3.24) -include("low_level_tao.jl") # Low-level Tao functions -include("doc_examples_is.jl") # the IS examples in the manual -# The lmvm Tao types work only in the first PETSc cycle of a process (see -# _reset_stale_register_flags in src/init.jl), so the Tao manual examples run in a fresh one -@testset "Tao manual examples, fresh process" begin - cmd = `$(Base.julia_cmd()) --project=. $(joinpath(@__DIR__, "doc_examples_tao.jl"))` - @test success(pipeline(cmd, stderr = stderr)) + +if selected("vecmat") + include("vecmat/vec.jl") + include("vecmat/mat.jl") + include("vecmat/mat_vec_methods.jl") # copyto!, fill!, zero_rows!, set_option!, diagonal!, isassembled + include("vecmat/matshell.jl") end -include("doc_examples_ts.jl") # the TS examples in the manual -include("doc_examples_viewer.jl") # the PetscViewer examples in the manual -include("test_destroy.jl") # destroy! guards: stale cycle, double destroy -include("handles.jl") # destroy! on IS, AO, PF, Tao; ISColoringGetIS ownership -include("handle_arrays.jl") # C arrays of handles go back to their release function -include("lifetimes.jl") # arrays a Vec or Mat wraps live as long as it does -include("test_deprecations.jl") # the v0.4 names still work and warn (the only file calling them) -include("test_api_surface.jl") # scripts/api_surface.jl --check: the register covers the surface -include("testutils.jl") +if selected("solvers") + include("solvers/ksp.jl") + include("solvers/pc.jl") # high-level PC + include("solvers/snes.jl") + include("solvers/snes_callbacks.jl") + include("solvers/solver_api.jl") # KSP/SNES/TS/PC readers, operators, prefixes, set_from_options! + include("solvers/ts.jl") # high-level TS interface + include("solvers/ts_long_runs.jl") # equation type, step number, pre/post-step hooks, failure limits + include("solvers/ts_scenarios.jl") # ex16 equivalence and a damping sweep +end -# Run helper tests for TAO (the SNES ones ran above) -include("tao_helpers.jl") +if selected("dm") + include("dm/dmda.jl") + include("dm/dmstag.jl") + include("dm/dmstag_serial.jl") + include("dm/dmstag_stencils.jl") # DMStag locations by axis, stencils, stencil assembly + include("dm/dmstag_halos.jl") # local_to_local!, with_product_coordinates, preallocate only + include("dm/dmstag_views.jl") # with_field_views!: types, allocations, hand-back + include("dm/dmplex.jl") + include("dm/dmnetwork.jl") + include("dm/dmshell.jl") + include("dm/dmproduct.jl") + include("dm/dm_dimension.jl") # dimension-correct DM returns: shape, inference, allocations +end -# Run the examples to make sure they all work -include("examples.jl") +if selected("lowlevel") + include("lowlevel/snes_helpers.jl") # SNES return-style wrappers + include("lowlevel/wrapper_signatures.jl") # wrapper arguments take the abstract types + include("lowlevel/wrapper_quality.jl") # every generated method infers a concrete return type; no allocations + include("lowlevel/wrapper_leaks.jl") # repeated create/destroy and Get/Restore pairs do not grow memory + include("lowlevel/viewer.jl") + include("lowlevel/ts.jl") + include("lowlevel/is.jl") + include("lowlevel/petscsection.jl") + include("lowlevel/petscsf.jl") # graph and communication functions + include("lowlevel/tao.jl") + include("lowlevel/tao_helpers.jl") +end + +if selected("regression") + include("regression/ts_ex51.jl") # repeated ex51 solves + include("regression/ts_ex51_implicit.jl") # repeated implicit Gauss solves + include("regression/ts_ex16.jl") # the van der Pol IMEX example +end + +if selected("examples") + include("examples/manual_is.jl") # the IS examples in the manual + # The lmvm Tao types work only in the first PETSc cycle of a process (see + # _reset_stale_register_flags in src/init.jl), so the Tao manual examples run in a fresh one + @testset "Tao manual examples, fresh process" begin + @test run_separately("examples/manual_tao.jl") + end + include("examples/manual_ts.jl") # the TS examples in the manual + include("examples/manual_viewer.jl") # the PetscViewer examples in the manual -# Examples with the comment -# # INCLUDE IN MPI TEST -# will be run here -# XXX: Currently not working on windows (since we have no PETSc + MPI) -if do_mpi - include("mpi_examples.jl") + include("testutils.jl") + include("examples/examples.jl") # every script in examples/ + include("examples/mpi_examples.jl") # the examples marked `# INCLUDE IN MPI TEST` end -# Do the MPI tests -# XXX: Currently not working on windows (since we have no PETSc + MPI) -if do_mpi +# Last, so that no MPI run happens inside another +if selected("mpi") @testset "MPI Tests" begin - for testfile in mpi_tests - testpath = joinpath(@__DIR__, testfile) - cmd = `$(mpiexec()) -n 4 $(Base.julia_cmd()) --project=. $testpath` - @test success(pipeline(cmd, stderr = stderr)) + for file in ("mpi/vec.jl", "mpi/mat.jl", "solvers/ksp.jl", "dm/dmstag.jl", + "mpi/dmstag_halos.jl", "mpi/blas_threads.jl") + @test run_separately(file; nranks = 4) end end end diff --git a/test/ksp.jl b/test/solvers/ksp.jl similarity index 100% rename from test/ksp.jl rename to test/solvers/ksp.jl diff --git a/test/pc.jl b/test/solvers/pc.jl similarity index 100% rename from test/pc.jl rename to test/solvers/pc.jl diff --git a/test/snes.jl b/test/solvers/snes.jl similarity index 100% rename from test/snes.jl rename to test/solvers/snes.jl diff --git a/test/test_snes.jl b/test/solvers/snes_callbacks.jl similarity index 100% rename from test/test_snes.jl rename to test/solvers/snes_callbacks.jl diff --git a/test/solver_api.jl b/test/solvers/solver_api.jl similarity index 99% rename from test/solver_api.jl rename to test/solvers/solver_api.jl index 76213e59a..5500a21ef 100644 --- a/test/solver_api.jl +++ b/test/solvers/solver_api.jl @@ -1,4 +1,4 @@ -# test/solver_api.jl +# test/solvers/solver_api.jl # Readers and setters on KSP, SNES, TS and PC that a nested or logged solve # needs: iteration counts, reasons, operators, options prefixes and # set_from_options!. diff --git a/test/ts.jl b/test/solvers/ts.jl similarity index 99% rename from test/ts.jl rename to test/solvers/ts.jl index d6b956834..6ee21aee6 100644 --- a/test/ts.jl +++ b/test/solvers/ts.jl @@ -493,7 +493,7 @@ MPI.Initialized() || MPI.Init() @test ts.ptr == C_NULL # A TS that never solved is destroyable too. (The v0.4 `destroy` - # spelling is covered by test/test_deprecations.jl.) + # spelling is covered by test/core/deprecations.jl.) ts2 = PETSc.TS(petsclib, comm) PETSc.destroy!(ts2) @test ts2.ptr == C_NULL diff --git a/test/ts_long_runs.jl b/test/solvers/ts_long_runs.jl similarity index 99% rename from test/ts_long_runs.jl rename to test/solvers/ts_long_runs.jl index fe082a2ad..414f3244e 100644 --- a/test/ts_long_runs.jl +++ b/test/solvers/ts_long_runs.jl @@ -1,4 +1,4 @@ -# test/ts_long_runs.jl +# test/solvers/ts_long_runs.jl # What a long TS run needs: the equation type, restarting the step count, # pre- and post-step hooks that may change the run, and the limits on failed # nonlinear solves and rejected steps. diff --git a/test/ts_scenarios.jl b/test/solvers/ts_scenarios.jl similarity index 98% rename from test/ts_scenarios.jl rename to test/solvers/ts_scenarios.jl index 61570ad27..7b304948c 100644 --- a/test/ts_scenarios.jl +++ b/test/solvers/ts_scenarios.jl @@ -8,12 +8,12 @@ using MPI # bindings, and checks the two agree to the last digit. The second is shaped # the way the low-level layer makes awkward. # -# `examples/ex16.jl` is loaded into its own module because `test/ts_ex16.jl` +# `examples/ex16.jl` is loaded into its own module because `test/regression/ts_ex16.jl` # also includes it, and its `@cfunction` pointers are `const`: a second # include into the same namespace would be a redefinition error, and the order # the two test files run in should not matter. module Ex16Reference -include(joinpath(dirname(dirname(@__FILE__)), "examples", "ex16.jl")) +include(joinpath(@__DIR__, "..", "..", "examples", "ex16.jl")) end @testset "High-level TS scenarios" begin diff --git a/test/mat.jl b/test/vecmat/mat.jl similarity index 100% rename from test/mat.jl rename to test/vecmat/mat.jl diff --git a/test/mat_vec_methods.jl b/test/vecmat/mat_vec_methods.jl similarity index 98% rename from test/mat_vec_methods.jl rename to test/vecmat/mat_vec_methods.jl index 46829ce8d..f7f2e27b5 100644 --- a/test/mat_vec_methods.jl +++ b/test/vecmat/mat_vec_methods.jl @@ -1,4 +1,4 @@ -# test/mat_vec_methods.jl +# test/vecmat/mat_vec_methods.jl # Base and Mat methods: copyto! between vectors, fill! on a matrix, row zeroing # for Dirichlet conditions, matrix options, the diagonal and isassembled. diff --git a/test/matshell.jl b/test/vecmat/matshell.jl similarity index 100% rename from test/matshell.jl rename to test/vecmat/matshell.jl diff --git a/test/vec.jl b/test/vecmat/vec.jl similarity index 100% rename from test/vec.jl rename to test/vecmat/vec.jl diff --git a/wrapping/DEVIATIONS.md b/wrapping/DEVIATIONS.md index 527b2e62c..14b076e06 100644 --- a/wrapping/DEVIATIONS.md +++ b/wrapping/DEVIATIONS.md @@ -33,7 +33,7 @@ formatting or still to be reviewed. Counts are from the run of 2026-09-15 (6086 Other differences from the baseline that are not per-function: - the docstring stub `function X(petsclib::PetscLibType, ...)` has loosened scalar types and throws - instead of silently returning `nothing` (this surfaced two test bugs in `test/test_dmstag.jl`); + instead of silently returning `nothing` (this surfaced two test bugs in `test/dm/dmstag_serial.jl`); - `PetscObject` arguments are untyped, so any handle (including `VecPtr`, `MatPtr`) is accepted; - `MPI_Comm` outputs are read through the C handle and wrapped in `MPI.Comm`; - `*Restore*` functions accept the array a `Get` returned, or the raw pointer if the size was unknown; @@ -68,7 +68,7 @@ Other differences from the baseline that are not per-function: - `petsc_wrappers_version.jl` no longer records a machine path; - `PC_wrappers.jl` is generated and included (the baseline excluded it). -Tests adapted: `test/dmplex.jl`, `test/mat.jl`, `test/snes.jl`, `test/test_dmstag.jl`; example +Tests adapted: `test/dm/dmplex.jl`, `test/vecmat/mat.jl`, `test/solvers/snes.jl`, `test/dm/dmstag_serial.jl`; example `examples/ex62b.jl`. Also `src/mat.jl` (`MatShellGetContext`), `src/ksp.jl`/`src/ts.jl`/`src/dm.jl` (solution and coordinate accessors return borrowed `VecPtr` handles, `destroy!` is a no-op on them), `src/options.jl` (NULL viewer for `PetscOptionsView`). diff --git a/wrapping/WRAPPING.md b/wrapping/WRAPPING.md index 860753651..e46e08dcd 100644 --- a/wrapping/WRAPPING.md +++ b/wrapping/WRAPPING.md @@ -131,7 +131,7 @@ which hid e.g. `Float64` literals passed to a `Float32` library in the tests). Input handle arguments always take the abstract type (`AbstractPetscVec`), so `VecPtr`, `MatShell` and the typed DM hierarchy pass; return positions use the concrete type (`PetscVec`). -`test/wrapper_signatures.jl` enforces this. +`test/lowlevel/wrapper_signatures.jl` enforces this. ### Rules (`generator/rules/`) @@ -191,7 +191,7 @@ override only when no rule can express the wrapper `.github/workflows/wrappers.yml` regenerates from the PETSc tarball on every change to `src/autowrapped` or `wrapping/generator` and fails if the committed files differ. -`test/wrapper_quality.jl` infers the return type of every generated method (must be concrete) +`test/lowlevel/wrapper_quality.jl` infers the return type of every generated method (must be concrete) and checks representatives of each argument kind with `@inferred` and `@allocated`. ## Checking a regeneration @@ -213,7 +213,7 @@ After regenerating, always run ```sh grep -rn "isa Ref ?" src/autowrapped/ # must be empty (Ptr{T} <: Ref{T}) grep -rn "VecGetLocalSize(petsclib, x)" src/autowrapped/ # placeholder sizes: must be empty -julia --project=. -e 'using Pkg; Pkg.test()' # includes test/wrapper_signatures.jl +julia --project=. -e 'using Pkg; Pkg.test()' # includes test/lowlevel/wrapper_signatures.jl ``` ## Moving to a new PETSc release (what happened for 3.24 -> 3.25) From 0941b21ba7d0f9a043c12c11fdb9017d624d77fd Mon Sep 17 00:00:00 2001 From: filoferra <66474175+filoferra@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:44:20 +0200 Subject: [PATCH 3/5] Tests: say what each DMStag file checks, and give the testsets unique names --- test/dm/dmstag.jl | 5 +++++ test/dm/dmstag_serial.jl | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/test/dm/dmstag.jl b/test/dm/dmstag.jl index d8af7f0b6..bf54b293e 100644 --- a/test/dm/dmstag.jl +++ b/test/dm/dmstag.jl @@ -1,3 +1,8 @@ +# test/dm/dmstag.jl +# Creating 1D, 2D and 3D DMStags for every boundary combination, with the checks +# that hold on any number of ranks: runs serially and on 4 ranks. The exact values +# a single rank sees are in dmstag_serial.jl. + using Test using PETSc, MPI MPI.Initialized() || MPI.Init() diff --git a/test/dm/dmstag_serial.jl b/test/dm/dmstag_serial.jl index af473cdbb..9764b139d 100644 --- a/test/dm/dmstag_serial.jl +++ b/test/dm/dmstag_serial.jl @@ -1,10 +1,14 @@ +# test/dm/dmstag_serial.jl +# DMStag on one rank, where sizes, entries, slots and vector positions have exact +# values: the LibPETSc getters, stencil get/set, array checkout, coordinates and +# matrices. Serial only; the checks that hold on any number of ranks are in dmstag.jl. + using Test using PETSc, MPI, OffsetArrays -#using SparseArrays MPI.Initialized() || MPI.Init() -@testset "DMStag All" begin +@testset "DMStag getters on one rank" begin comm = MPI.COMM_WORLD mpirank = MPI.Comm_rank(comm) @@ -316,7 +320,7 @@ MPI.Initialized() || MPI.Init() end end -@testset "DMStagCreate1d" begin +@testset "DMStag 1D: boundary types, keywords, local indices" begin comm = MPI.COMM_WORLD mpirank = MPI.Comm_rank(comm) @@ -435,7 +439,7 @@ end end end -@testset "DMStagCreate2d" begin +@testset "DMStag 2D: corners on one rank" begin comm = MPI.COMM_WORLD mpirank = MPI.Comm_rank(comm) From 298e75cf24db81e09d5b6eba5d00168f0abecff5 Mon Sep 17 00:00:00 2001 From: filoferra <66474175+filoferra@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:44:51 +0200 Subject: [PATCH 4/5] Tests: one SNES test for the 2x2 system, callbacks that return nothing --- test/core/smoke.jl | 172 +++++++-------------------------- test/lowlevel/readers.jl | 27 ++++++ test/lowlevel/snes_helpers.jl | 18 ---- test/lowlevel/tao_helpers.jl | 19 ---- test/runtests.jl | 4 +- test/solvers/snes.jl | 50 ++++++++++ test/solvers/snes_callbacks.jl | 89 ----------------- 7 files changed, 115 insertions(+), 264 deletions(-) create mode 100644 test/lowlevel/readers.jl delete mode 100644 test/lowlevel/snes_helpers.jl delete mode 100644 test/lowlevel/tao_helpers.jl delete mode 100644 test/solvers/snes_callbacks.jl diff --git a/test/core/smoke.jl b/test/core/smoke.jl index cfd219d10..241f7ef53 100644 --- a/test/core/smoke.jl +++ b/test/core/smoke.jl @@ -1,141 +1,43 @@ +# test/core/smoke.jl +# Vec, Mat, KSP and MatShell end to end on small problems, against Julia's own +# linear algebra: the quickest check that the library works at all. + using Test using PETSc, MPI, LinearAlgebra, SparseArrays -#PETSc.initialize() - -petsclib = PETSc.petsclibs[1] -PETSc.initialize(petsclib) MPI.Initialized() || MPI.Init() -comm = MPI.COMM_WORLD - -@testset "Old Tests" begin - m,n = 20,20 - x = randn(n) - #V = PETSc.VecSeqWithArray(petsclib,x) - - PetscScalar = petsclib.PetscScalar - PetscInt = petsclib.PetscInt - - bs = PetscInt(1) - V = LibPETSc.VecCreateSeqWithArray(petsclib,comm, bs, PetscInt(length(x)), x) - - @test norm(x) ≈ norm(V) rtol=10eps() - - S = sprand(m,n,0.1) + I - #M = PETSc.PetscMat(petsclib,S) - M = PETSc.PetscMat(petsclib, comm, S) - - - @test norm(S) ≈ norm(M) rtol=10eps() - vec_x = LibPETSc.VecCreateSeqWithArray(petsclib, LibPETSc.PETSC_COMM_SELF, PetscInt(1), PetscInt(length(x)), copy(x)) - - w = M*vec_x - @test w[:] ≈ S*x - - ksp = PETSc.KSP(M; ksp_rtol=1e-8, pc_type="jacobi", ksp_monitor=false) - #PETSc.settolerances!(ksp; rtol=1e-8) - - @test PETSc.type_name(ksp) === :gmres # default - - y = ksp \ w - @test S*y[:] ≈ w[:] rtol=1e-6 - - - #w = M'*x - #@test w ≈ S'*x - - # to be fixed -# y = ksp' \ w -# @test S'*y ≈ w rtol=1e-8 - - f!(y,x) = y .= 2 .*x - - M = PETSc.MatShell(petsclib,f!, MPI.COMM_SELF, 10,10) - - x = rand(10) - - @test M*x ≈ 2x - @test PETSc.KSP(M) \ x ≈ x/2 - - - function F!(cfx, snes, cx) - fx = PETSc.unsafe_local_array(cfx; read = false, write = true) - x = PETSc.unsafe_local_array(cx; read = true, write = false) - - fx[1] = x[1]^2 + x[1] * x[2] - 3 - fx[2] = x[1] * x[2] + x[2]^2 - 6 - - finalize(fx) - finalize(x) - - return 0 - end - - J = zeros(2,2) - PJ = LibPETSc.MatCreateSeqDense(petsclib, comm, PetscInt(size(J,1)), PetscInt(size(J,2)), J[:]) - - - - function updateJ!(J, snes, x) - PETSc.unsafe_local_array(x; read = true, write = false) - - J[1, 1] = 2x[1] + x[2] - J[1, 2] = x[1] - J[2, 1] = x[2] - J[2, 2] = x[1] + 2x[2] - - PETSc.assemble!(J) - Base.finalize(x) - - return 0 # needs to be zero! - end - - S = PETSc.SNES(petsclib, MPI.COMM_SELF; ksp_rtol=1e-4, pc_type="none") - r = LibPETSc.VecCreateSeqWithArray(petsclib, LibPETSc.PETSC_COMM_SELF, PetscInt(1), PetscInt(2), zeros(PetscScalar, 2)) - - - # You can do this to set the callback functions. - # Please be aware that the functions above MUST return 0 - PETSc.set_function!(F!, S, r) - PETSc.set_snes_jacobian!(updateJ!, S, PJ, PJ) - - # The alternative is to do this (tested below): - #PETSc.set_function!(S, r) do cfx, snes, cx - # F!(cfx, snes, cx) - # return 0 - #end - - #PETSc.set_snes_jacobian!(S, PJ) do J, S, x - # updateJ!(J, S, x) - # return 0 - #end - - #a = PETSc.VecSeqWithArray(petsclib,[2.0,3.0]) - a = LibPETSc.VecCreateSeqWithArray(petsclib, LibPETSc.PETSC_COMM_SELF, PetscInt(1), PetscInt(2), PetscScalar.([2.0,3.0])) - - sol = PETSc.solve!(a, S) - @test sol[:] ≈ [1.0,2.0] rtol=1e-4 - - - # Test the alternative is to do this: - PETSc.set_function!(S, r) do cfx, snes, cx - F!(cfx, snes, cx) - return 0 - end - - PETSc.set_snes_jacobian!(S, PJ) do J, S, x - updateJ!(J, S, x) - return 0 - end - sol1 = PETSc.solve!(a, S) - @test sol1[:] ≈ [1.0,2.0] rtol=1e-4 - - PETSc.destroy!(S) - PETSc.destroy!(M) - PETSc.destroy!(ksp) - PETSc.destroy!(V) - PETSc.destroy!(r) +@testset "Vec, Mat and KSP end to end" begin + petsclib = PETSc.petsclibs[1] + PETSc.initialize(petsclib) + PetscInt = petsclib.PetscInt + comm = MPI.COMM_SELF + + n = 20 + x = randn(n) + V = LibPETSc.VecCreateSeqWithArray(petsclib, comm, PetscInt(1), PetscInt(n), x) + @test norm(x) ≈ norm(V) rtol = 10eps() + + S = sprand(n, n, 0.1) + I + M = PETSc.PetscMat(petsclib, comm, S) + @test norm(S) ≈ norm(M) rtol = 10eps() + + vec_x = LibPETSc.VecCreateSeqWithArray(petsclib, comm, PetscInt(1), PetscInt(n), copy(x)) + w = M * vec_x + @test w[:] ≈ S * x + + ksp = PETSc.KSP(M; ksp_rtol = 1e-8, pc_type = "jacobi", ksp_monitor = false) + @test PETSc.type_name(ksp) === :gmres # the default + y = ksp \ w + @test S * y[:] ≈ w[:] rtol = 1e-6 + + # a matrix-free operator + f!(y, x) = y .= 2 .* x + shell = PETSc.MatShell(petsclib, f!, comm, 10, 10) + z = rand(10) + @test shell * z ≈ 2z + @test PETSc.KSP(shell) \ z ≈ z / 2 + + foreach(PETSc.destroy!, (ksp, shell, M, vec_x, V)) + PETSc.finalize(petsclib) end - -PETSc.finalize(petsclib) \ No newline at end of file diff --git a/test/lowlevel/readers.jl b/test/lowlevel/readers.jl new file mode 100644 index 000000000..65d9206db --- /dev/null +++ b/test/lowlevel/readers.jl @@ -0,0 +1,27 @@ +# test/lowlevel/readers.jl +# LibPETSc readers on an object that has not solved anything return plain values, +# not handles or references. + +using Test +using PETSc + +@testset "LibPETSc readers before a solve" begin + petsclib = PETSc.petsclibs[1] + PETSc.initialize(petsclib) + comm = LibPETSc.PETSC_COMM_SELF + + snes = LibPETSc.SNESCreate(petsclib, comm) + LibPETSc.SNESSetFromOptions(petsclib, snes) + @test LibPETSc.SNESGetConvergedReason(petsclib, snes) isa LibPETSc.SNESConvergedReason + @test LibPETSc.SNESGetIterationNumber(petsclib, snes) == 0 + LibPETSc.SNESDestroy(petsclib, snes) + + # Tao objects work only where the Tao types survive a PETSc cycle (not on Windows) + if PETSc.tao_usable_after_reinitialize() + tao = LibPETSc.TaoCreate(petsclib, comm) + @test LibPETSc.TaoGetConvergedReason(petsclib, tao) isa LibPETSc.TaoConvergedReason + LibPETSc.TaoDestroy(petsclib, tao) + end + + PETSc.finalize(petsclib) +end diff --git a/test/lowlevel/snes_helpers.jl b/test/lowlevel/snes_helpers.jl deleted file mode 100644 index 009a239f1..000000000 --- a/test/lowlevel/snes_helpers.jl +++ /dev/null @@ -1,18 +0,0 @@ -using PETSc - -# Minimal SNES helper test -petsclib = PETSc.petsclibs[1] -PETSc.initialize(petsclib) - -snes = LibPETSc.SNESCreate(petsclib, LibPETSc.PETSC_COMM_SELF) -LibPETSc.SNESSetFromOptions(petsclib, snes) - -# Call helpers (should not MethodError) -reason = LibPETSc.SNESGetConvergedReason(petsclib, snes) -iters = LibPETSc.SNESGetIterationNumber(petsclib, snes) - -@assert typeof(reason) <: Integer || typeof(reason) <: Enum -@assert typeof(iters) <: Integer - -LibPETSc.SNESDestroy(petsclib, snes) -PETSc.finalize(petsclib) diff --git a/test/lowlevel/tao_helpers.jl b/test/lowlevel/tao_helpers.jl deleted file mode 100644 index 0bcc7edff..000000000 --- a/test/lowlevel/tao_helpers.jl +++ /dev/null @@ -1,19 +0,0 @@ -using PETSc - -# Minimal TAO helper test -if !PETSc.tao_usable_after_reinitialize() - @info "Skipping Tao tests: PETSc 3.25.x loses the TaoTerm types at PetscFinalize and the workaround is not possible with these binaries (Windows)" -else -petsclib = PETSc.petsclibs[1] -PETSc.initialize(petsclib) - -tao = LibPETSc.TaoCreate(petsclib, LibPETSc.PETSC_COMM_SELF) -# Avoid calling TaoSetType string wrapper; keep minimal - -# Call helper (should not MethodError) -reason = LibPETSc.TaoGetConvergedReason(petsclib, tao) -@assert typeof(reason) <: Integer || typeof(reason) <: Enum - -LibPETSc.TaoDestroy(petsclib, tao) -PETSc.finalize(petsclib) -end diff --git a/test/runtests.jl b/test/runtests.jl index 6e8451b14..b11e9b29d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -68,7 +68,6 @@ if selected("solvers") include("solvers/ksp.jl") include("solvers/pc.jl") # high-level PC include("solvers/snes.jl") - include("solvers/snes_callbacks.jl") include("solvers/solver_api.jl") # KSP/SNES/TS/PC readers, operators, prefixes, set_from_options! include("solvers/ts.jl") # high-level TS interface include("solvers/ts_long_runs.jl") # equation type, step number, pre/post-step hooks, failure limits @@ -90,7 +89,7 @@ if selected("dm") end if selected("lowlevel") - include("lowlevel/snes_helpers.jl") # SNES return-style wrappers + include("lowlevel/readers.jl") # LibPETSc readers return plain values include("lowlevel/wrapper_signatures.jl") # wrapper arguments take the abstract types include("lowlevel/wrapper_quality.jl") # every generated method infers a concrete return type; no allocations include("lowlevel/wrapper_leaks.jl") # repeated create/destroy and Get/Restore pairs do not grow memory @@ -100,7 +99,6 @@ if selected("lowlevel") include("lowlevel/petscsection.jl") include("lowlevel/petscsf.jl") # graph and communication functions include("lowlevel/tao.jl") - include("lowlevel/tao_helpers.jl") end if selected("regression") diff --git a/test/solvers/snes.jl b/test/solvers/snes.jl index d661a201f..223856f38 100644 --- a/test/solvers/snes.jl +++ b/test/solvers/snes.jl @@ -384,3 +384,53 @@ MPI.Initialized() || MPI.Init() end end + +# The same 2x2 system with a Jacobian, set in the two ways a user writes it: +# named functions, and do-blocks. The callbacks return nothing; since 0.5.1 a +# callback's return value is ignored and it fails by throwing. +@testset "SNES with a Jacobian: named functions and do-blocks" begin + petsclib = PETSc.petsclibs[1] + PETSc.initialize(petsclib) + PetscScalar = petsclib.PetscScalar + PetscInt = petsclib.PetscInt + comm = MPI.COMM_SELF + + function residual!(fx, snes, x) + fx[1] = x[1]^2 + x[1] * x[2] - 3 + fx[2] = x[1] * x[2] + x[2]^2 - 6 + return nothing + end + function jacobian!(J, snes, x) + J[1, 1] = 2x[1] + x[2] + J[1, 2] = x[1] + J[2, 1] = x[2] + J[2, 2] = x[1] + 2x[2] + PETSc.assemble!(J) + return nothing + end + + J = LibPETSc.MatCreateSeqDense(petsclib, comm, PetscInt(2), PetscInt(2), zeros(PetscScalar, 4)) + r = PETSc.PetscVec(petsclib, zeros(PetscScalar, 2)) + + snes = PETSc.SNES(petsclib, comm; ksp_rtol = 1e-4, pc_type = "none") + snes.user_ctx = (label = "anything",) # a user context survives the solve + PETSc.set_function!(residual!, snes, r) + PETSc.set_snes_jacobian!(jacobian!, snes, J, J) + x = PETSc.PetscVec(petsclib, PetscScalar[2, 3]) + PETSc.solve!(x, snes) + @test x[:] ≈ [1.0, 2.0] rtol = 1e-4 + @test snes.user_ctx.label == "anything" + + PETSc.set_function!(snes, r) do fx, snes, x + residual!(fx, snes, x) + end + PETSc.set_snes_jacobian!(snes, J) do J, snes, x + jacobian!(J, snes, x) + end + y = PETSc.PetscVec(petsclib, PetscScalar[2, 3]) + PETSc.solve!(y, snes) + @test y[:] ≈ [1.0, 2.0] rtol = 1e-4 + + foreach(PETSc.destroy!, (snes, y, x, r, J)) + PETSc.finalize(petsclib) +end diff --git a/test/solvers/snes_callbacks.jl b/test/solvers/snes_callbacks.jl deleted file mode 100644 index b36ae758b..000000000 --- a/test/solvers/snes_callbacks.jl +++ /dev/null @@ -1,89 +0,0 @@ -using Test -using PETSc, MPI, LinearAlgebra, SparseArrays - -MPI.Initialized() || MPI.Init() - -@testset "test_snes" begin - - comm = MPI.COMM_WORLD - mpirank = MPI.Comm_rank(comm) - mpisize = MPI.Comm_size(comm) - - # structure with which we can pass data to the user-routines above - mutable struct Data - vec - julia - end - - for petsclib in PETSc.petsclibs - #petsclib = PETSc.petsclibs[1] - PETSc.initialize(petsclib) - PetscScalar = PETSc.scalartype(petsclib) - PetscInt = PETSc.inttype(petsclib) - - # This shows some examples of how SNES can be used. - # Note that you will receive pointers to PETSc vectors within your user routines. - # That is important for parallel simulations, where global residual - # and solution vectors are passed to the user-routines, but we work with - # local vectors - - function fn!(fx, snes, x, user_ctx) - fx[1] = x[1]^2 + x[1] * x[2] - 3 - fx[2] = x[1] * x[2] + x[2]^2 - 6 - - return PetscInt(0) # success code of PETSc - end - - - function update_jac!(J1, snes, x, user_ctx) - J1[1,1] = 2x[1] + x[2] - J1[1,2] = x[1] - J1[2,1] = x[2] - J1[2,2] = x[1] + 2x[2] - PETSc.assemble!(J1) - return PetscInt(0) - end - - - - julia_vec = 0; # we want pointers to local vectors - - # NOTE: for some reason, snes_monitor and ksp_monitor is not working if we specify that here. - # To be sorted out why that is (converged_reason does work) - S = PETSc.SNES(petsclib,comm; - ksp_rtol=1e-4, - pc_type="none", - ksp_monitor=false, - snes_monitor=false, - snes_converged_reason=false, - ksp_converged_reason=false) - - data = Data(PetscScalar.([100;2]), 1) - S.user_ctx = data; # we can pack anything we need in this struct - - #PJ = PETSc.PetscMat(zeros(PetscScalar,(2,2))) - PJ = LibPETSc.MatCreateSeqDense(petsclib,comm, PetscInt(2), PetscInt(2), zeros(PetscScalar,4)) - - r = LibPETSc.VecCreateSeqWithArray(petsclib,comm, PetscInt(1), PetscInt(2), zeros(PetscScalar, 2)) - PETSc.set_function!(fn!, S, r) - PETSc.set_snes_jacobian!(update_jac!, S, PJ, PJ) - - x = LibPETSc.VecCreateSeqWithArray(petsclib,comm, PetscInt(1), PetscInt(2), PetscScalar.([2, 3])) - b = LibPETSc.VecCreateSeqWithArray(petsclib,comm, PetscInt(1), PetscInt(2), PetscScalar.([0, 0])) - PETSc.solve!(x, S, b) - - #sol = PETSc.unsafe_local_array(PetscScalar, x.ptr) - sol = x[:] - @test sol ≈ [1.0,2.0] rtol=1e-4 - - # cleanup - destroy the SNES first, then the vectors/matrices it references - PETSc.destroy!(S); - PETSc.destroy!(x); - PETSc.destroy!(b); - PETSc.destroy!(r); - PETSc.destroy!(PJ); - - PETSc.finalize(petsclib) - GC.gc() # Force garbage collection to clean up any remaining objects - end -end From 13123612d49d9a363a9f4cc4f7b91e067a07e769 Mon Sep 17 00:00:00 2001 From: filoferra <66474175+filoferra@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:45:17 +0200 Subject: [PATCH 5/5] Tests: take the loaded library from PETSc.petsclibs[1] getlib(PetscScalar = Float64) assumed an Int64 build; the tests now use whichever library is loaded. --- test/core/petscbool.jl | 4 ++-- test/dm/dmnetwork.jl | 2 +- test/dm/dmplex.jl | 2 +- test/dm/dmproduct.jl | 2 +- test/dm/dmshell.jl | 2 +- test/examples/manual_is.jl | 2 +- test/examples/manual_tao.jl | 2 +- test/examples/manual_ts.jl | 2 +- test/examples/manual_viewer.jl | 2 +- test/lowlevel/is.jl | 2 +- test/lowlevel/petscsection.jl | 2 +- test/lowlevel/petscsf.jl | 2 +- test/lowlevel/tao.jl | 2 +- test/lowlevel/ts.jl | 2 +- test/lowlevel/viewer.jl | 2 +- test/regression/ts_ex16.jl | 2 +- test/regression/ts_ex51.jl | 2 +- test/regression/ts_ex51_implicit.jl | 2 +- test/solvers/ts_scenarios.jl | 2 +- 19 files changed, 20 insertions(+), 20 deletions(-) diff --git a/test/core/petscbool.jl b/test/core/petscbool.jl index cf29a3f5e..58f3de9f5 100644 --- a/test/core/petscbool.jl +++ b/test/core/petscbool.jl @@ -11,7 +11,7 @@ MPI.Initialized() || MPI.Init() @test Bool(LibPETSc.PETSC_FALSE) === false && Bool(LibPETSc.PETSC_TRUE) === true @test LibPETSc.PetscBool(false) == LibPETSc.PETSC_FALSE - petsclib = PETSc.getlib() + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) # false answers must read as false, many times over (fresh Refs each call) opts = LibPETSc.PetscOptions{typeof(petsclib)}() @@ -36,7 +36,7 @@ end # A sentinel goes into the byte after each flag, and is restored afterwards. # The flags are not exported on Windows, so there is nothing to check there. @testset "RegisterAllCalled reset writes one byte" begin - petsclib = PETSc.getlib() + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) handle, _ = PETSc.ensure_library_handle(petsclib) lib = PETSc.library_ptr(handle) diff --git a/test/dm/dmnetwork.jl b/test/dm/dmnetwork.jl index 307e05eb5..fa7ac34bb 100644 --- a/test/dm/dmnetwork.jl +++ b/test/dm/dmnetwork.jl @@ -8,7 +8,7 @@ if !MPI.Initialized() mpi_started = true end try - local petsclib = PETSc.getlib() + local petsclib = PETSc.petsclibs[1] petsc_started = false if !PETSc.isinitialized(petsclib) PETSc.initialize(petsclib) diff --git a/test/dm/dmplex.jl b/test/dm/dmplex.jl index d4ed67174..c02e5e310 100644 --- a/test/dm/dmplex.jl +++ b/test/dm/dmplex.jl @@ -16,7 +16,7 @@ MPI.Initialized() || MPI.Init() # time, so they MUST be module-level names before the macros are invoked. # We define them once for the Float64/Int64 lib that owns the FEM callbacks. -const _dmplex_petsclib = PETSc.getlib(PetscScalar = Float64) +const _dmplex_petsclib = PETSc.petsclibs[1] PETSc.initialize(_dmplex_petsclib) const PetscInt = _dmplex_petsclib.PetscInt diff --git a/test/dm/dmproduct.jl b/test/dm/dmproduct.jl index c5732005b..f58ffc428 100644 --- a/test/dm/dmproduct.jl +++ b/test/dm/dmproduct.jl @@ -8,7 +8,7 @@ if !MPI.Initialized() mpi_started = true end try - local petsclib = PETSc.getlib() + local petsclib = PETSc.petsclibs[1] petsc_started = false if !PETSc.isinitialized(petsclib) PETSc.initialize(petsclib) diff --git a/test/dm/dmshell.jl b/test/dm/dmshell.jl index cca362b26..68c67772f 100644 --- a/test/dm/dmshell.jl +++ b/test/dm/dmshell.jl @@ -8,7 +8,7 @@ using PETSc, MPI mpi_started = true end try - local petsclib = PETSc.getlib() + local petsclib = PETSc.petsclibs[1] petsc_started = false if !PETSc.isinitialized(petsclib) PETSc.initialize(petsclib) diff --git a/test/examples/manual_is.jl b/test/examples/manual_is.jl index 44cea84ab..069140fc5 100644 --- a/test/examples/manual_is.jl +++ b/test/examples/manual_is.jl @@ -3,7 +3,7 @@ using PETSc using MPI @testset "Documentation examples for IS" begin - petsclib = PETSc.getlib(PetscScalar=Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) test_comm = MPI.COMM_SELF PetscInt = PETSc.LibPETSc.PetscInt diff --git a/test/examples/manual_tao.jl b/test/examples/manual_tao.jl index 40443ddce..f7cf965c4 100644 --- a/test/examples/manual_tao.jl +++ b/test/examples/manual_tao.jl @@ -6,7 +6,7 @@ if !PETSc.tao_usable_after_reinitialize() @info "Skipping Tao tests: PETSc 3.25.x loses the TaoTerm types at PetscFinalize and the workaround is not possible with these binaries (Windows)" else @testset "Documentation examples for Tao" begin - petsclib = PETSc.getlib(PetscScalar=Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) test_comm = MPI.COMM_SELF PetscInt = PETSc.LibPETSc.PetscInt diff --git a/test/examples/manual_ts.jl b/test/examples/manual_ts.jl index 35c65b717..c0f461417 100644 --- a/test/examples/manual_ts.jl +++ b/test/examples/manual_ts.jl @@ -3,7 +3,7 @@ using PETSc using MPI @testset "Documentation examples for TS" begin - petsclib = PETSc.getlib(PetscScalar=Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) test_comm = MPI.COMM_SELF diff --git a/test/examples/manual_viewer.jl b/test/examples/manual_viewer.jl index 54782de10..5ba0e225f 100644 --- a/test/examples/manual_viewer.jl +++ b/test/examples/manual_viewer.jl @@ -3,7 +3,7 @@ using PETSc using MPI @testset "Documentation examples for PetscViewer" begin - petsclib = PETSc.getlib(PetscScalar=Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) test_comm = MPI.COMM_SELF diff --git a/test/lowlevel/is.jl b/test/lowlevel/is.jl index 4c712b938..1c3b2ecec 100644 --- a/test/lowlevel/is.jl +++ b/test/lowlevel/is.jl @@ -3,7 +3,7 @@ using PETSc using MPI @testset "Low-level IS (Index Set) functions" begin - petsclib = PETSc.getlib(PetscScalar=Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) PetscInt = PETSc.LibPETSc.PetscInt test_comm = MPI.COMM_SELF diff --git a/test/lowlevel/petscsection.jl b/test/lowlevel/petscsection.jl index 21f00d7bf..d14330d8a 100644 --- a/test/lowlevel/petscsection.jl +++ b/test/lowlevel/petscsection.jl @@ -3,7 +3,7 @@ using PETSc using MPI # Initialize PETSc -petsclib = PETSc.getlib() +petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) test_comm = MPI.COMM_SELF diff --git a/test/lowlevel/petscsf.jl b/test/lowlevel/petscsf.jl index 9b731248e..dad7b962a 100644 --- a/test/lowlevel/petscsf.jl +++ b/test/lowlevel/petscsf.jl @@ -7,7 +7,7 @@ using PETSc: LibPETSc MPI.Initialized() || MPI.Init() @testset "Low-level PetscSF communication" begin - petsclib = PETSc.getlib() + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) PetscInt = petsclib.PetscInt diff --git a/test/lowlevel/tao.jl b/test/lowlevel/tao.jl index 512945b2d..f52279254 100644 --- a/test/lowlevel/tao.jl +++ b/test/lowlevel/tao.jl @@ -6,7 +6,7 @@ if !PETSc.tao_usable_after_reinitialize() @info "Skipping Tao tests: PETSc 3.25.x loses the TaoTerm types at PetscFinalize and the workaround is not possible with these binaries (Windows)" else @testset "Low-level Tao (optimization) functions" begin - petsclib = PETSc.getlib(PetscScalar=Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) test_comm = MPI.COMM_SELF diff --git a/test/lowlevel/ts.jl b/test/lowlevel/ts.jl index 242f7ec56..421c6fc87 100644 --- a/test/lowlevel/ts.jl +++ b/test/lowlevel/ts.jl @@ -3,7 +3,7 @@ using PETSc using MPI @testset "Low-level TS (Time Stepping) functions" begin - petsclib = PETSc.getlib(PetscScalar=Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) test_comm = MPI.COMM_SELF diff --git a/test/lowlevel/viewer.jl b/test/lowlevel/viewer.jl index 64b29062e..9f32050f6 100644 --- a/test/lowlevel/viewer.jl +++ b/test/lowlevel/viewer.jl @@ -3,7 +3,7 @@ using PETSc using MPI @testset "Low-level PetscViewer convenience functions" begin - petsclib = PETSc.getlib(PetscScalar=Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) test_comm = MPI.COMM_SELF diff --git a/test/regression/ts_ex16.jl b/test/regression/ts_ex16.jl index 2ccaca7d8..9cb13e38e 100644 --- a/test/regression/ts_ex16.jl +++ b/test/regression/ts_ex16.jl @@ -19,7 +19,7 @@ function capture_stdout_to_string(f::Function) end @testset "TS ex16 example" begin - petsclib = PETSc.getlib(PetscScalar = Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) try function solve_arkimex(method::String) diff --git a/test/regression/ts_ex51.jl b/test/regression/ts_ex51.jl index a3427afba..c75907f91 100644 --- a/test/regression/ts_ex51.jl +++ b/test/regression/ts_ex51.jl @@ -4,7 +4,7 @@ using PETSc include(joinpath(pkgdir(PETSc), "examples", "ex51.jl")) @testset "TS ex51 example" begin - petsclib = PETSc.getlib(PetscScalar = Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) try # `examples.jl` covers the default `save_trajectory = true` path in a diff --git a/test/regression/ts_ex51_implicit.jl b/test/regression/ts_ex51_implicit.jl index f9d0d8709..58d4dc0ae 100644 --- a/test/regression/ts_ex51_implicit.jl +++ b/test/regression/ts_ex51_implicit.jl @@ -4,7 +4,7 @@ using PETSc include(joinpath(pkgdir(PETSc), "examples", "ex51_implicit.jl")) @testset "TS ex51 implicit example" begin - petsclib = PETSc.getlib(PetscScalar = Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) try result_stage_1 = solve_ex51_implicit(; diff --git a/test/solvers/ts_scenarios.jl b/test/solvers/ts_scenarios.jl index 7b304948c..c3cc7e8ad 100644 --- a/test/solvers/ts_scenarios.jl +++ b/test/solvers/ts_scenarios.jl @@ -17,7 +17,7 @@ include(joinpath(@__DIR__, "..", "..", "examples", "ex16.jl")) end @testset "High-level TS scenarios" begin - petsclib = PETSc.getlib(PetscScalar = Float64) + petsclib = PETSc.petsclibs[1] PETSc.initialize(petsclib) PetscScalar = petsclib.PetscScalar PetscInt = petsclib.PetscInt