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] diff --git a/src/autowrapped/Mat_wrappers.jl b/src/autowrapped/Mat_wrappers.jl index 2709a80c..7f726f56 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 """ @@ -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) @@ -5357,20 +5354,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 +5410,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 """ @@ -11570,8 +11585,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 +11595,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 +11632,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 +11672,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 +11681,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 +11707,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 +11716,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 +11744,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 +11753,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 +11779,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 +11788,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 +11818,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 +11828,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 +11853,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 +11862,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 +11892,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 +11902,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 +11965,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 +11975,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 """ @@ -18028,8 +18062,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 @@ -18037,20 +18076,21 @@ 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")) """ function MatSeqAIJGetArray(petsclib::PetscLibType, A::PetscMat) end -@for_petsc function MatSeqAIJGetArray(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() +@for_petsc function MatSeqAIJGetArray(petsclib::$UnionPetscLib, A::PetscMat) + array_ = Ref{Ptr{$PetscScalar}}() + # 1. Get the pointer to the numerical values @chk ccall( (:MatSeqAIJGetArray, $petsc_library), PetscErrorCode, @@ -18058,44 +18098,53 @@ function MatSeqAIJGetArray(petsclib::PetscLibType, A::PetscMat) end A, array_, ) - array = unsafe_wrap(Array, array_[], VecGetLocalSize(petsclib, x); own = false) + # 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) - return array -end + # 3. Extract the nnz count using the [] syntax to unwrap the Ref + nnz = Int(info_ref[].nz_used) + + return unsafe_wrap(Array, array_[], nnz; own = false) +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")) """ -function MatSeqAIJRestoreArray(petsclib::PetscLibType, A::PetscMat) end +function MatSeqAIJRestoreArray(petsclib::PetscLibType, A::PetscMat, array::Array) end -@for_petsc function MatSeqAIJRestoreArray(petsclib::$UnionPetscLib, A::PetscMat ) - array_ = Ref{Ptr{$PetscScalar}}() +@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 7f6dbbe8..54195eb4 100644 --- a/test/mat.jl +++ b/test/mat.jl @@ -309,6 +309,201 @@ 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 + +@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 +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 end \ No newline at end of file