From 29cf2936859fc06d75447d24f42cf3f97086ee6b Mon Sep 17 00:00:00 2001 From: Iddingsite Date: Mon, 23 Feb 2026 14:11:51 +0100 Subject: [PATCH 1/6] correct MatDenseGetArray and RestoreArray wrappers --- src/autowrapped/Mat_wrappers.jl | 101 +++++++++++++++++------------- test/mat.jl | 105 ++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+), 41 deletions(-) diff --git a/src/autowrapped/Mat_wrappers.jl b/src/autowrapped/Mat_wrappers.jl index 2709a80c..ecb8b552 100644 --- a/src/autowrapped/Mat_wrappers.jl +++ b/src/autowrapped/Mat_wrappers.jl @@ -11570,8 +11570,9 @@ $(_doc_external("Mat/MatDenseGetArray")) function MatDenseGetArray(petsclib::PetscLibType, A::PetscMat) end @for_petsc function MatDenseGetArray(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() + array_ = Ref{Ptr{$PetscScalar}}() + # 1. Get the raw pointer from PETSc @chk ccall( (:MatDenseGetArray, $petsc_library), PetscErrorCode, @@ -11579,9 +11580,15 @@ function MatDenseGetArray(petsclib::PetscLibType, A::PetscMat) end A, array_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) + # 2. Use the existing helper to get dimensions (no Refs needed here!) + m, n = MatGetLocalSize(petsclib, A) - return array + # 3. Wrap the pointer in a Julia Array. + # PETSc dense matrices are column-major, matching Julia's layout perfectly. + array = unsafe_wrap(Array, array_[], (Int(m), Int(n)); own = false) + + + return array end """ @@ -11610,13 +11617,23 @@ function MatDenseRestoreArray(petsclib::PetscLibType, A::PetscMat) end (:MatDenseRestoreArray, $petsc_library), PetscErrorCode, (CMat, Ptr{Ptr{$PetscScalar}}), - A, array_, + A, ptr_ref, ) + return nothing +end - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) - - return array -end +@for_petsc function MatDenseRestoreArray(petsclib::$UnionPetscLib, A::PetscMat, array::Array{$PetscScalar}) + # Create a temporary Ref to the array's internal pointer to satisfy the ** signature + ptr_ref = Ref(pointer(array)) + + @chk ccall( + (:MatDenseRestoreArray, $petsc_library), + PetscErrorCode, + (CMat, Ptr{Ptr{$PetscScalar}}), + A, ptr_ref, + ) + return nothing +end """ array::Vector{PetscScalar} = MatDenseGetArrayRead(petsclib::PetscLibType,A::PetscMat) @@ -11640,7 +11657,7 @@ $(_doc_external("Mat/MatDenseGetArrayRead")) function MatDenseGetArrayRead(petsclib::PetscLibType, A::PetscMat) end @for_petsc function MatDenseGetArrayRead(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() + array_ = Ref{Ptr{$PetscScalar}}() @chk ccall( (:MatDenseGetArrayRead, $petsc_library), @@ -11649,9 +11666,10 @@ function MatDenseGetArrayRead(petsclib::PetscLibType, A::PetscMat) end A, array_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) + m, n = MatGetLocalSize(petsclib, A) + array = unsafe_wrap(Array, array_[], (Int(m), Int(n)); own = false) - return array + return array end """ @@ -11674,7 +11692,7 @@ $(_doc_external("Mat/MatDenseRestoreArrayRead")) function MatDenseRestoreArrayRead(petsclib::PetscLibType, A::PetscMat) end @for_petsc function MatDenseRestoreArrayRead(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() + array_ = Ref{Ptr{$PetscScalar}}() @chk ccall( (:MatDenseRestoreArrayRead, $petsc_library), @@ -11683,9 +11701,10 @@ function MatDenseRestoreArrayRead(petsclib::PetscLibType, A::PetscMat) end A, array_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) + m, n = MatGetLocalSize(petsclib, A) + array = unsafe_wrap(Array, array_[], (Int(m), Int(n)); own = false) - return array + return array end """ @@ -11710,7 +11729,7 @@ $(_doc_external("Mat/MatDenseGetArrayWrite")) function MatDenseGetArrayWrite(petsclib::PetscLibType, A::PetscMat) end @for_petsc function MatDenseGetArrayWrite(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() + array_ = Ref{Ptr{$PetscScalar}}() @chk ccall( (:MatDenseGetArrayWrite, $petsc_library), @@ -11719,9 +11738,10 @@ function MatDenseGetArrayWrite(petsclib::PetscLibType, A::PetscMat) end A, array_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) + m, n = MatGetLocalSize(petsclib, A) + array = unsafe_wrap(Array, array_[], (Int(m), Int(n)); own = false) - return array + return array end """ @@ -11744,7 +11764,7 @@ $(_doc_external("Mat/MatDenseRestoreArrayWrite")) function MatDenseRestoreArrayWrite(petsclib::PetscLibType, A::PetscMat) end @for_petsc function MatDenseRestoreArrayWrite(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() + array_ = Ref{Ptr{$PetscScalar}}() @chk ccall( (:MatDenseRestoreArrayWrite, $petsc_library), @@ -11753,9 +11773,10 @@ function MatDenseRestoreArrayWrite(petsclib::PetscLibType, A::PetscMat) end A, array_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) + m, n = MatGetLocalSize(petsclib, A) + array = unsafe_wrap(Array, array_[], (Int(m), Int(n)); own = false) - return array + return array end """ @@ -11782,8 +11803,8 @@ $(_doc_external("Mat/MatDenseGetArrayAndMemType")) function MatDenseGetArrayAndMemType(petsclib::PetscLibType, A::PetscMat) end @for_petsc function MatDenseGetArrayAndMemType(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() - mtype_ = Ref{PetscMemType}() + array_ = Ref{Ptr{$PetscScalar}}() + mtype_ = Ref{PetscMemType}() @chk ccall( (:MatDenseGetArrayAndMemType, $petsc_library), @@ -11792,10 +11813,9 @@ function MatDenseGetArrayAndMemType(petsclib::PetscLibType, A::PetscMat) end A, array_, mtype_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) - mtype = unsafe_string(mtype_[]) - - return array,mtype + m, n = MatGetLocalSize(petsclib, A) + array = unsafe_wrap(Array, array_[], (Int(m), Int(n)); own = false) + return array, mtype_[] end """ @@ -11818,7 +11838,7 @@ $(_doc_external("Mat/MatDenseRestoreArrayAndMemType")) function MatDenseRestoreArrayAndMemType(petsclib::PetscLibType, A::PetscMat) end @for_petsc function MatDenseRestoreArrayAndMemType(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() + array_ = Ref{Ptr{$PetscScalar}}() @chk ccall( (:MatDenseRestoreArrayAndMemType, $petsc_library), @@ -11827,9 +11847,10 @@ function MatDenseRestoreArrayAndMemType(petsclib::PetscLibType, A::PetscMat) end A, array_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) + m, n = MatGetLocalSize(petsclib, A) + array = unsafe_wrap(Array, array_[], (Int(m), Int(n)); own = false) - return array + return array end """ @@ -11856,8 +11877,8 @@ $(_doc_external("Mat/MatDenseGetArrayReadAndMemType")) function MatDenseGetArrayReadAndMemType(petsclib::PetscLibType, A::PetscMat) end @for_petsc function MatDenseGetArrayReadAndMemType(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() - mtype_ = Ref{PetscMemType}() + array_ = Ref{Ptr{$PetscScalar}}() + mtype_ = Ref{PetscMemType}() @chk ccall( (:MatDenseGetArrayReadAndMemType, $petsc_library), @@ -11866,10 +11887,9 @@ function MatDenseGetArrayReadAndMemType(petsclib::PetscLibType, A::PetscMat) end A, array_, mtype_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) - mtype = unsafe_string(mtype_[]) - - return array,mtype + m, n = MatGetLocalSize(petsclib, A) + array = unsafe_wrap(Array, array_[], (Int(m), Int(n)); own = false) + return array, mtype_[] end """ @@ -11930,8 +11950,8 @@ $(_doc_external("Mat/MatDenseGetArrayWriteAndMemType")) function MatDenseGetArrayWriteAndMemType(petsclib::PetscLibType, A::PetscMat) end @for_petsc function MatDenseGetArrayWriteAndMemType(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() - mtype_ = Ref{PetscMemType}() + array_ = Ref{Ptr{$PetscScalar}}() + mtype_ = Ref{PetscMemType}() @chk ccall( (:MatDenseGetArrayWriteAndMemType, $petsc_library), @@ -11940,10 +11960,9 @@ function MatDenseGetArrayWriteAndMemType(petsclib::PetscLibType, A::PetscMat) en A, array_, mtype_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) - mtype = unsafe_string(mtype_[]) - - return array,mtype + m, n = MatGetLocalSize(petsclib, A) + array = unsafe_wrap(Array, array_[], (Int(m), Int(n)); own = false) + return array, mtype_[] end """ diff --git a/test/mat.jl b/test/mat.jl index 7f6dbbe8..b41d722a 100644 --- a/test/mat.jl +++ b/test/mat.jl @@ -309,6 +309,111 @@ end PETSc.destroy(vec_y) PETSc.destroy(A) + PETSc.finalize(petsclib) + end +end + +@testset "MatDenseGetArray and RestoreArray" begin + for petsclib in PETSc.petsclibs + PETSc.initialize(petsclib) + PetscScalar = petsclib.PetscScalar + + n, m = 5, 3 + # 1. Create a Dense Matrix + Ajl = zeros(PetscScalar, n, m) + A = PETSc.MatSeqDense(petsclib, Ajl) + + # 2. Test GetArray + # This should return a Julia Matrix view pointing to PETSc's memory + jl_view = LibPETSc.MatDenseGetArray(petsclib, A) + + @test size(jl_view) == (n, m) + @test jl_view isa Matrix{PetscScalar} + + # 3. Test Mutability: Writing to the Julia view should update PETSc + test_val = PetscScalar(42.0) + jl_view[2, 2] = test_val + + # 4. Test RestoreArray + # Passing the array back to PETSc to unlock it + LibPETSc.MatDenseRestoreArray(petsclib, A, jl_view) + + # 5. Verify the value is actually in PETSc now + # assembly! is good practice after direct memory modification + PETSc.assemble!(A) + @test A[2, 2] == test_val + + # 6. Test copyto! + A2_jl = PetscScalar.(rand(n, m)) + jl_view2 = LibPETSc.MatDenseGetArray(petsclib, A) + try + copyto!(jl_view2, A2_jl) + finally + LibPETSc.MatDenseRestoreArray(petsclib, A, jl_view2) + end + PETSc.assemble!(A) + + @test A[:, :] ≈ A2_jl + + PETSc.destroy(A) + PETSc.finalize(petsclib) + end +end + +@testset "MatDenseGetArray/RestoreArray variants" begin + for petsclib in PETSc.petsclibs + PETSc.initialize(petsclib) + PetscScalar = petsclib.PetscScalar + n, m = 4, 3 + Ajl = reshape(PetscScalar.(1:(n*m)), n, m) + A = PETSc.MatSeqDense(petsclib, Ajl) + + # MatDenseGetArray + arr = LibPETSc.MatDenseGetArray(petsclib, A) + @test size(arr) == (n, m) + @test arr isa Matrix{PetscScalar} + arr[1,1] = PetscScalar(123) + LibPETSc.MatDenseRestoreArray(petsclib, A, arr) + PETSc.assemble!(A) + @test A[1,1] == PetscScalar(123) + + # MatDenseGetArrayRead + arr_read = LibPETSc.MatDenseGetArrayRead(petsclib, A) + @test size(arr_read) == (n, m) + @test arr_read[2,2] == A[2,2] + LibPETSc.MatDenseRestoreArrayRead(petsclib, A) + + # MatDenseGetArrayWrite + arr_write = LibPETSc.MatDenseGetArrayWrite(petsclib, A) + @test size(arr_write) == (n, m) + arr_write[3,1] = PetscScalar(456) + LibPETSc.MatDenseRestoreArrayWrite(petsclib, A) + PETSc.assemble!(A) + @test A[3,1] == PetscScalar(456) + + # MatDenseGetArrayAndMemType + arr_and_mem, mtype = LibPETSc.MatDenseGetArrayAndMemType(petsclib, A) + @test size(arr_and_mem) == (n, m) + arr_and_mem[4,2] = PetscScalar(789) + LibPETSc.MatDenseRestoreArrayAndMemType(petsclib, A) + PETSc.assemble!(A) + @test A[4,2] == PetscScalar(789) + + # MatDenseGetArrayReadAndMemType + arr_read_mem, mtype2 = LibPETSc.MatDenseGetArrayReadAndMemType(petsclib, A) + @test size(arr_read_mem) == (n, m) + @test arr_read_mem[1,2] == A[1,2] + # No explicit restore needed for read test here + + # MatDenseGetArrayWriteAndMemType + arr_write_mem, mtype3 = LibPETSc.MatDenseGetArrayWriteAndMemType(petsclib, A) + @test size(arr_write_mem) == (n, m) + arr_write_mem[2,3] = PetscScalar(321) + LibPETSc.MatDenseRestoreArrayWrite(petsclib, A) + PETSc.assemble!(A) + @test A[2,3] == PetscScalar(321) + + PETSc.destroy(A) PETSc.finalize(petsclib) end end \ No newline at end of file From 6034fe1e2d9d989c8ee220344c96ad984c840013 Mon Sep 17 00:00:00 2001 From: Iddingsite Date: Mon, 23 Feb 2026 15:04:39 +0100 Subject: [PATCH 2/6] add a bit more functions --- src/autowrapped/Mat_wrappers.jl | 72 ++++++++++++++++++++------------- test/mat.jl | 50 +++++++++++++++++++++++ 2 files changed, 95 insertions(+), 27 deletions(-) diff --git a/src/autowrapped/Mat_wrappers.jl b/src/autowrapped/Mat_wrappers.jl index ecb8b552..a3c6a6d5 100644 --- a/src/autowrapped/Mat_wrappers.jl +++ b/src/autowrapped/Mat_wrappers.jl @@ -1136,10 +1136,10 @@ function MatGetGhosts(petsclib::PetscLibType, mat::PetscMat) end mat, nghosts_, ghosts_, ) - nghosts = nghosts_[] - ghosts = unsafe_wrap(Array, ghosts_[], VecGetLocalSize(petsclib, x); own = false) + nghosts = nghosts_[] + ghosts = unsafe_wrap(Array, ghosts_[], Int(nghosts); own = false) - return nghosts,ghosts + return nghosts,ghosts end """ @@ -1250,11 +1250,11 @@ function MatGetRow(petsclib::PetscLibType, mat::PetscMat, row::PetscInt) end mat, row, ncols_, cols_, vals_, ) - ncols = ncols_[] - cols = unsafe_wrap(Array, cols_[], VecGetLocalSize(petsclib, x); own = false) - vals = unsafe_wrap(Array, vals_[], VecGetLocalSize(petsclib, x); own = false) + ncols = ncols_[] + cols = unsafe_wrap(Array, cols_[], Int(ncols); own = false) + vals = unsafe_wrap(Array, vals_[], Int(ncols); own = false) - return ncols,cols,vals + return ncols,cols,vals end """ @@ -1322,11 +1322,11 @@ function MatRestoreRow(petsclib::PetscLibType, mat::PetscMat, row::PetscInt) end mat, row, ncols_, cols_, vals_, ) - ncols = ncols_[] - cols = unsafe_wrap(Array, cols_[], VecGetLocalSize(petsclib, x); own = false) - vals = unsafe_wrap(Array, vals_[], VecGetLocalSize(petsclib, x); own = false) + ncols = ncols_[] + cols = unsafe_wrap(Array, cols_[], Int(ncols); own = false) + vals = unsafe_wrap(Array, vals_[], Int(ncols); own = false) - return ncols,cols,vals + return ncols,cols,vals end """ @@ -5357,20 +5357,27 @@ $(_doc_external("Mat/MatGetOwnershipRanges")) """ function MatGetOwnershipRanges(petsclib::PetscLibType, mat::PetscMat) end -@for_petsc function MatGetOwnershipRanges(petsclib::$UnionPetscLib, mat::PetscMat ) - ranges_ = Ref{Ptr{$PetscInt}}() - - @chk ccall( - (:MatGetOwnershipRanges, $petsc_library), - PetscErrorCode, - (CMat, Ptr{Ptr{$PetscInt}}), - mat, ranges_, - ) - - ranges = unsafe_wrap(Array, ranges_[], VecGetLocalSize(petsclib, x); own = false) - - return ranges -end +@for_petsc function MatGetOwnershipRanges(petsclib::$UnionPetscLib, mat::PetscMat) + ranges_ = Ref{Ptr{$PetscInt}}() + @chk ccall( + (:MatGetOwnershipRanges, $petsc_library), + PetscErrorCode, + (CMat, Ptr{Ptr{$PetscInt}}), + mat, ranges_, + ) + # Get the MPI communicator directly from the PETSc object via ccall + comm_ref = Ref{MPI.MPI_Comm}() + @chk ccall( + (:PetscObjectGetComm, $petsc_library), + PetscErrorCode, + (CMat, Ptr{MPI.MPI_Comm}), + mat, comm_ref, + ) + comm = MPI.Comm(comm_ref[]) + nproc = MPI.Comm_size(comm) + ranges = unsafe_wrap(Array, ranges_[], nproc + 1; own = false) + return ranges +end """ ranges::Vector{PetscInt} = MatGetOwnershipRangesColumn(petsclib::PetscLibType,mat::PetscMat) @@ -5406,9 +5413,20 @@ function MatGetOwnershipRangesColumn(petsclib::PetscLibType, mat::PetscMat) end mat, ranges_, ) - ranges = unsafe_wrap(Array, ranges_[], VecGetLocalSize(petsclib, x); own = false) + # Get the MPI communicator directly from the PETSc object via ccall + comm_ref = Ref{MPI.MPI_Comm}() + @chk ccall( + (:PetscObjectGetComm, $petsc_library), + PetscErrorCode, + (CMat, Ptr{MPI.MPI_Comm}), + mat, comm_ref, + ) + comm = MPI.Comm(comm_ref[]) + + nproc = MPI.Comm_size(comm) + ranges = unsafe_wrap(Array, ranges_[], nproc + 1; own = false) - return ranges + return ranges end """ diff --git a/test/mat.jl b/test/mat.jl index b41d722a..e56e2f96 100644 --- a/test/mat.jl +++ b/test/mat.jl @@ -413,6 +413,56 @@ end PETSc.assemble!(A) @test A[2,3] == PetscScalar(321) + PETSc.destroy(A) + PETSc.finalize(petsclib) + end +end + +@testset "MatGetGhosts, MatGetRow, MatRestoreRow, MatGetOwnershipRanges" begin + for petsclib in PETSc.petsclibs + PETSc.initialize(petsclib) + PetscScalar = petsclib.PetscScalar + PetscInt = petsclib.PetscInt + # Use a small matrix for ghost/row tests + n, m = 4, 4 + Ajl = PetscScalar.([1 2 0 0; 0 3 4 0; 0 0 5 6; 7 0 0 8]) + A = PETSc.MatSeqAIJ(petsclib, n, m, 2) + for i in 1:n, j in 1:m + if Ajl[i,j] != 0 + A[i,j] = Ajl[i,j] + end + end + PETSc.assemble!(A) + + # # MatGetRow and MatRestoreRow + for row in 1:n + ncols, cols, vals = LibPETSc.MatGetRow(petsclib, A, PetscInt(row - 1)) + @test ncols == count(!iszero, Ajl[row,:]) + @test length(cols) == ncols + @test length(vals) == ncols + # PETSc uses 0-based indices, Julia uses 1-based + @test all(Ajl[row, cols .+ 1] .== vals) + # MatRestoreRow only releases resources; it does not return row data + LibPETSc.MatRestoreRow(petsclib, A, PetscInt(row - 1)) + end + + # MatGetOwnershipRanges and MatGetOwnershipRangesColumn + # These are meaningful for parallel, but should return [0, n] for sequential + ranges = LibPETSc.MatGetOwnershipRanges(petsclib, A) + @test length(ranges) == 2 + @test ranges[1] == 0 + @test ranges[2] == n + ranges_col = LibPETSc.MatGetOwnershipRangesColumn(petsclib, A) + @test length(ranges_col) == 2 + @test ranges_col[1] == 0 + @test ranges_col[2] == m + + # MatGetGhosts (should work, but for non-parallel, expect empty or zero ghosts) + nghosts, ghosts = LibPETSc.MatGetGhosts(petsclib, A) + @test Int(nghosts) == length(ghosts) + # For sequential, usually zero ghosts + @test Int(nghosts) == 0 || all(isa.(ghosts, Int)) + PETSc.destroy(A) PETSc.finalize(petsclib) end From 1ec5adf68aad720940d82d81bca6e3b1834f9f46 Mon Sep 17 00:00:00 2001 From: Iddingsite Date: Mon, 23 Feb 2026 17:48:24 +0100 Subject: [PATCH 3/6] we need more... --- src/autowrapped/Mat_wrappers.jl | 36 +++++++++++++++++------------ test/mat.jl | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/autowrapped/Mat_wrappers.jl b/src/autowrapped/Mat_wrappers.jl index a3c6a6d5..a8428e29 100644 --- a/src/autowrapped/Mat_wrappers.jl +++ b/src/autowrapped/Mat_wrappers.jl @@ -18086,8 +18086,9 @@ $(_doc_external("Mat/MatSeqAIJGetArray")) function MatSeqAIJGetArray(petsclib::PetscLibType, A::PetscMat) end @for_petsc function MatSeqAIJGetArray(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() + array_ = Ref{Ptr{$PetscScalar}}() + # 1. Call the C function to get the pointer to the sparse value array @chk ccall( (:MatSeqAIJGetArray, $petsc_library), PetscErrorCode, @@ -18095,10 +18096,19 @@ function MatSeqAIJGetArray(petsclib::PetscLibType, A::PetscMat) end A, array_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) + # 2. Fix: Get the matrix dimensions to determine how many elements to wrap + # For Sparse AIJ, GetArray usually provides access to the 'nz' values. + m, n = MatGetLocalSize(petsclib, A) + + # 3. Wrap as a 1D Array (Vector) + # Note: AIJ GetArray provides the raw values buffer. + # We wrap it with length m*n if it's treated as a full buffer, + # but usually, AIJ GetArray is used for internal access to the non-zero values. + # If PETSc intended this to be a flat view of all local entries: + array = unsafe_wrap(Array, array_[], Int(m * n); own = false) - return array -end + return array +end """ array::Vector{PetscScalar} = MatSeqAIJRestoreArray(petsclib::PetscLibType,A::PetscMat) @@ -18117,22 +18127,20 @@ Level: intermediate # External Links $(_doc_external("Mat/MatSeqAIJRestoreArray")) """ -function MatSeqAIJRestoreArray(petsclib::PetscLibType, A::PetscMat) end - -@for_petsc function MatSeqAIJRestoreArray(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() +function MatSeqAIJRestoreArray(petsclib::PetscLibType, A::PetscMat, array::Array) end +@for_petsc function MatSeqAIJRestoreArray(petsclib::$UnionPetscLib, A::PetscMat, array::Array{$PetscScalar}) + # Create a Ref to the pointer of the Julia array to satisfy the ** signature + ptr_ref = Ref(pointer(array)) + @chk ccall( (:MatSeqAIJRestoreArray, $petsc_library), PetscErrorCode, (CMat, Ptr{Ptr{$PetscScalar}}), - A, array_, + A, ptr_ref, ) - - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) - - return array -end + return nothing +end """ array::Vector{PetscScalar} = MatSeqAIJGetArrayRead(petsclib::PetscLibType,A::PetscMat) diff --git a/test/mat.jl b/test/mat.jl index e56e2f96..54195eb4 100644 --- a/test/mat.jl +++ b/test/mat.jl @@ -463,6 +463,46 @@ end # For sequential, usually zero ghosts @test Int(nghosts) == 0 || all(isa.(ghosts, Int)) + PETSc.destroy(A) + PETSc.finalize(petsclib) + end +end + +@testset "MatSeqAIJGetArray and RestoreArray" begin + for petsclib in PETSc.petsclibs + PETSc.initialize(petsclib) + PetscScalar = petsclib.PetscScalar + PetscInt = petsclib.PetscInt + + # 1. Create a simple Sparse AIJ matrix (Diagonal) + n = 5 + A = PETSc.MatSeqAIJ(petsclib, n, n, 1) + for i in 1:n + A[i, i] = PetscScalar(i) + end + PETSc.assemble!(A) + + # 2. Test GetArray (Fixed implementation) + # For AIJ, this returns a 1D view of the non-zero values + val_view = LibPETSc.MatSeqAIJGetArray(petsclib, A) + + # In a diagonal 5x5 matrix, there are 5 non-zeros. + # Note: Depending on PETSc internals, the returned length might be + # the full local buffer size. + @test length(val_view) >= n + @test val_view[1] == PetscScalar(1.0) + + # 3. Test Mutability: Update values through the pointer + new_val = PetscScalar(99.0) + val_view[1] = new_val + + # 4. Test RestoreArray + LibPETSc.MatSeqAIJRestoreArray(petsclib, A, val_view) + PETSc.assemble!(A) + + # 5. Verify PETSc sees the change + @test A[1, 1] == new_val + PETSc.destroy(A) PETSc.finalize(petsclib) end From a3fed7e987bbc30a4f27ad70abea22d4dc201499 Mon Sep 17 00:00:00 2001 From: Iddingsite Date: Mon, 23 Feb 2026 17:49:13 +0100 Subject: [PATCH 4/6] bump version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 3996ac12..6f7e4e22 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "PETSc" uuid = "ace2c81b-2b5f-4b1e-a30d-d662738edfe0" -version = "0.4.5" +version = "0.4.6" authors = ["Boris Kaus ", "Viral B. Shah ", "Valentin Churavy ", "Erik Schnetter ", "Jeremy E. Kozdon ", "Simon Byrne "] [deps] From 301eb4377724ec06127d73318a32b243bd9a4c35 Mon Sep 17 00:00:00 2001 From: Iddingsite Date: Mon, 23 Feb 2026 17:54:23 +0100 Subject: [PATCH 5/6] fix docstring --- src/autowrapped/Mat_wrappers.jl | 37 +++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/autowrapped/Mat_wrappers.jl b/src/autowrapped/Mat_wrappers.jl index a8428e29..0d87cf73 100644 --- a/src/autowrapped/Mat_wrappers.jl +++ b/src/autowrapped/Mat_wrappers.jl @@ -18065,8 +18065,13 @@ function MatSeqAIJKron(petsclib::PetscLibType, A::PetscMat, B::PetscMat, reuse:: end """ - array::Vector{PetscScalar} = MatSeqAIJGetArray(petsclib::PetscLibType,A::PetscMat) -gives read/write access to the array where the data for a `MATSEQAIJ` matrix is stored + array::Vector{PetscScalar} = MatSeqAIJGetArray(petsclib::PetscLibType, A::PetscMat) + +Returns a 1D Julia Array (Vector) providing direct read/write access to the internal +numerical values of a `MATSEQAIJ` (Sparse) matrix. + +Note: This only provides access to the values array. It does not allow changing +the sparsity pattern (row pointers or column indices). Not Collective @@ -18074,11 +18079,11 @@ Input Parameter: - `A` - a `MATSEQAIJ` matrix Output Parameter: -- `array` - pointer to the data +- `array` - A `Vector` view of the non-zero values. Level: intermediate --seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArray()` +See also: `MatSeqAIJRestoreArray()`, `MatDenseGetArray()` # External Links $(_doc_external("Mat/MatSeqAIJGetArray")) @@ -18099,10 +18104,10 @@ function MatSeqAIJGetArray(petsclib::PetscLibType, A::PetscMat) end # 2. Fix: Get the matrix dimensions to determine how many elements to wrap # For Sparse AIJ, GetArray usually provides access to the 'nz' values. m, n = MatGetLocalSize(petsclib, A) - - # 3. Wrap as a 1D Array (Vector) + + # 3. Wrap as a 1D Array (Vector) # Note: AIJ GetArray provides the raw values buffer. - # We wrap it with length m*n if it's treated as a full buffer, + # We wrap it with length m*n if it's treated as a full buffer, # but usually, AIJ GetArray is used for internal access to the non-zero values. # If PETSc intended this to be a flat view of all local entries: array = unsafe_wrap(Array, array_[], Int(m * n); own = false) @@ -18111,18 +18116,24 @@ function MatSeqAIJGetArray(petsclib::PetscLibType, A::PetscMat) end end """ - array::Vector{PetscScalar} = MatSeqAIJRestoreArray(petsclib::PetscLibType,A::PetscMat) -returns access to the array where the data for a `MATSEQAIJ` matrix is stored obtained by `MatSeqAIJGetArray()` + MatSeqAIJRestoreArray(petsclib::PetscLibType, A::PetscMat, array::Array) + +Restores a `MATSEQAIJ` matrix after direct access to its internal data was obtained +via `MatSeqAIJGetArray()`. + +Calling this function is required to "unlock" the matrix and allow PETSc to perform +subsequent operations (like assembly or multiplication). Not Collective Input Parameters: -- `A` - a `MATSEQAIJ` matrix -- `array` - pointer to the data +- `petsclib` - the PETSc library configuration +- `A` - a `MATSEQAIJ` matrix +- `array` - the array obtained from `MatSeqAIJGetArray()` Level: intermediate --seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArray()` +See also: `MatSeqAIJGetArray()`, `MatDenseRestoreArray()` # External Links $(_doc_external("Mat/MatSeqAIJRestoreArray")) @@ -18132,7 +18143,7 @@ function MatSeqAIJRestoreArray(petsclib::PetscLibType, A::PetscMat, array::Array @for_petsc function MatSeqAIJRestoreArray(petsclib::$UnionPetscLib, A::PetscMat, array::Array{$PetscScalar}) # Create a Ref to the pointer of the Julia array to satisfy the ** signature ptr_ref = Ref(pointer(array)) - + @chk ccall( (:MatSeqAIJRestoreArray, $petsc_library), PetscErrorCode, From 7626408ff6b2e6d258b439d068bc3202794f1bdc Mon Sep 17 00:00:00 2001 From: Iddingsite Date: Mon, 23 Feb 2026 18:25:27 +0100 Subject: [PATCH 6/6] fix MatGetInfo --- src/autowrapped/Mat_wrappers.jl | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/autowrapped/Mat_wrappers.jl b/src/autowrapped/Mat_wrappers.jl index 0d87cf73..7f726f56 100644 --- a/src/autowrapped/Mat_wrappers.jl +++ b/src/autowrapped/Mat_wrappers.jl @@ -2802,7 +2802,7 @@ function MatSetFactorType(petsclib::PetscLibType, mat::PetscMat, t::MatFactorTyp end """ - MatGetInfo(petsclib::PetscLibType,mat::PetscMat, flag::MatInfoType, info::MatInfo) + MatGetInfo(petsclib::PetscLibType,mat::PetscMat, flag::MatInfoType, info::Ref{MatInfo}) Returns information about matrix storage (number of nonzeros, memory, etc.). @@ -2825,20 +2825,17 @@ Level: intermediate # External Links $(_doc_external("Mat/MatGetInfo")) """ -function MatGetInfo(petsclib::PetscLibType, mat::PetscMat, flag::MatInfoType, info::MatInfo) end - -@for_petsc function MatGetInfo(petsclib::$UnionPetscLib, mat::PetscMat, flag::MatInfoType, info::MatInfo ) +function MatGetInfo(petsclib::PetscLibType, mat::PetscMat, flag::MatInfoType, info::Ref{MatInfo}) end +@for_petsc function MatGetInfo(petsclib::$UnionPetscLib, mat::PetscMat, flag::MatInfoType, info::Ref{MatInfo}) @chk ccall( (:MatGetInfo, $petsc_library), PetscErrorCode, (CMat, MatInfoType, Ptr{MatInfo}), mat, flag, info, ) - - - return nothing -end + return nothing +end """ MatLUFactor(petsclib::PetscLibType,mat::PetscMat, row::IS, col::IS, info::MatFactorInfo) @@ -18090,10 +18087,10 @@ $(_doc_external("Mat/MatSeqAIJGetArray")) """ function MatSeqAIJGetArray(petsclib::PetscLibType, A::PetscMat) end -@for_petsc function MatSeqAIJGetArray(petsclib::$UnionPetscLib, A::PetscMat ) +@for_petsc function MatSeqAIJGetArray(petsclib::$UnionPetscLib, A::PetscMat) array_ = Ref{Ptr{$PetscScalar}}() - # 1. Call the C function to get the pointer to the sparse value array + # 1. Get the pointer to the numerical values @chk ccall( (:MatSeqAIJGetArray, $petsc_library), PetscErrorCode, @@ -18101,18 +18098,14 @@ function MatSeqAIJGetArray(petsclib::PetscLibType, A::PetscMat) end A, array_, ) - # 2. Fix: Get the matrix dimensions to determine how many elements to wrap - # For Sparse AIJ, GetArray usually provides access to the 'nz' values. - m, n = MatGetLocalSize(petsclib, A) + # 2. Get the matrix info to determine the number of nonzeros + info_ref = Ref{LibPETSc.MatInfo}() + LibPETSc.MatGetInfo(petsclib, A, LibPETSc.MAT_LOCAL, info_ref) - # 3. Wrap as a 1D Array (Vector) - # Note: AIJ GetArray provides the raw values buffer. - # We wrap it with length m*n if it's treated as a full buffer, - # but usually, AIJ GetArray is used for internal access to the non-zero values. - # If PETSc intended this to be a flat view of all local entries: - array = unsafe_wrap(Array, array_[], Int(m * n); own = false) + # 3. Extract the nnz count using the [] syntax to unwrap the Ref + nnz = Int(info_ref[].nz_used) - return array + return unsafe_wrap(Array, array_[], nnz; own = false) end """