|
|
|
@ -3,14 +3,9 @@ |
|
|
|
module HYPRE |
|
|
|
module HYPRE |
|
|
|
|
|
|
|
|
|
|
|
using MPI: MPI |
|
|
|
using MPI: MPI |
|
|
|
using PartitionedArrays: IndexRange, MPIData, PSparseMatrix, PVector, PartitionedArrays, |
|
|
|
|
|
|
|
SequentialData, map_parts |
|
|
|
|
|
|
|
using SparseArrays: SparseArrays, AbstractSparseMatrixCSC, SparseMatrixCSC, nnz, nonzeros, nzrange, rowvals |
|
|
|
|
|
|
|
using SparseMatricesCSR: SparseMatrixCSR, colvals, getrowptr |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export HYPREMatrix, HYPREVector |
|
|
|
export HYPREMatrix, HYPREVector |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Clang.jl auto-generated bindings and some manual methods |
|
|
|
# Clang.jl auto-generated bindings and some manual methods |
|
|
|
include("LibHYPRE.jl") |
|
|
|
include("LibHYPRE.jl") |
|
|
|
using .LibHYPRE |
|
|
|
using .LibHYPRE |
|
|
|
@ -38,7 +33,12 @@ function Init(; finalize_atexit=true) |
|
|
|
if finalize_atexit |
|
|
|
if finalize_atexit |
|
|
|
# TODO: MPI only calls the finalizer if not exiting due to a Julia exeption. Does |
|
|
|
# TODO: MPI only calls the finalizer if not exiting due to a Julia exeption. Does |
|
|
|
# the same reasoning apply here? |
|
|
|
# the same reasoning apply here? |
|
|
|
atexit(HYPRE_Finalize) |
|
|
|
atexit() do |
|
|
|
|
|
|
|
# Finalize any HYPRE objects that are still alive |
|
|
|
|
|
|
|
foreach(finalize, keys(Internals.HYPRE_OBJECTS)) |
|
|
|
|
|
|
|
# Finalize the library |
|
|
|
|
|
|
|
HYPRE_Finalize() |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
return nothing |
|
|
|
return nothing |
|
|
|
end |
|
|
|
end |
|
|
|
@ -49,28 +49,43 @@ end |
|
|
|
############### |
|
|
|
############### |
|
|
|
|
|
|
|
|
|
|
|
mutable struct HYPREMatrix # <: AbstractMatrix{HYPRE_Complex} |
|
|
|
mutable struct HYPREMatrix # <: AbstractMatrix{HYPRE_Complex} |
|
|
|
#= const =# comm::MPI.Comm |
|
|
|
const comm::MPI.Comm |
|
|
|
#= const =# ilower::HYPRE_BigInt |
|
|
|
const ilower::HYPRE_BigInt |
|
|
|
#= const =# iupper::HYPRE_BigInt |
|
|
|
const iupper::HYPRE_BigInt |
|
|
|
#= const =# jlower::HYPRE_BigInt |
|
|
|
const jlower::HYPRE_BigInt |
|
|
|
#= const =# jupper::HYPRE_BigInt |
|
|
|
const jupper::HYPRE_BigInt |
|
|
|
ijmatrix::HYPRE_IJMatrix |
|
|
|
ijmatrix::HYPRE_IJMatrix |
|
|
|
parmatrix::HYPRE_ParCSRMatrix |
|
|
|
parmatrix::HYPRE_ParCSRMatrix |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function HYPREMatrix(comm::MPI.Comm, ilower::Integer, iupper::Integer, |
|
|
|
# Defining unsafe_convert enables ccall to automatically convert A::HYPREMatrix to |
|
|
|
jlower::Integer=ilower, jupper::Integer=iupper) |
|
|
|
# HYPRE_IJMatrix and HYPRE_ParCSRMatrix while also making sure A won't be GC'd and |
|
|
|
|
|
|
|
# finalized. |
|
|
|
|
|
|
|
Base.unsafe_convert(::Type{HYPRE_IJMatrix}, A::HYPREMatrix) = A.ijmatrix |
|
|
|
|
|
|
|
Base.unsafe_convert(::Type{HYPRE_ParCSRMatrix}, A::HYPREMatrix) = A.parmatrix |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function HYPREMatrix( |
|
|
|
|
|
|
|
comm::MPI.Comm, |
|
|
|
|
|
|
|
ilower::Integer, iupper::Integer, |
|
|
|
|
|
|
|
jlower::Integer = ilower, jupper::Integer = iupper |
|
|
|
|
|
|
|
) |
|
|
|
# Create the IJ matrix |
|
|
|
# Create the IJ matrix |
|
|
|
A = HYPREMatrix(comm, ilower, iupper, jlower, jupper, C_NULL, C_NULL) |
|
|
|
A = HYPREMatrix(comm, ilower, iupper, jlower, jupper, C_NULL, C_NULL) |
|
|
|
ijmatrix_ref = Ref{HYPRE_IJMatrix}(C_NULL) |
|
|
|
ijmatrix_ref = Ref{HYPRE_IJMatrix}(C_NULL) |
|
|
|
@check HYPRE_IJMatrixCreate(comm, ilower, iupper, ilower, iupper, ijmatrix_ref) |
|
|
|
@check HYPRE_IJMatrixCreate(comm, ilower, iupper, ilower, iupper, ijmatrix_ref) |
|
|
|
A.ijmatrix = ijmatrix_ref[] |
|
|
|
A.ijmatrix = ijmatrix_ref[] |
|
|
|
# Attach a finalizer |
|
|
|
# Attach a finalizer |
|
|
|
finalizer(x -> HYPRE_IJMatrixDestroy(x.ijmatrix), A) |
|
|
|
finalizer(A) do x |
|
|
|
|
|
|
|
if x.ijmatrix != C_NULL |
|
|
|
|
|
|
|
HYPRE_IJMatrixDestroy(x) |
|
|
|
|
|
|
|
x.ijmatrix = x.parmatrix = C_NULL |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
push!(Internals.HYPRE_OBJECTS, A => nothing) |
|
|
|
# Set storage type |
|
|
|
# Set storage type |
|
|
|
@check HYPRE_IJMatrixSetObjectType(A.ijmatrix, HYPRE_PARCSR) |
|
|
|
@check HYPRE_IJMatrixSetObjectType(A, HYPRE_PARCSR) |
|
|
|
# Initialize to make ready for setting values |
|
|
|
# Initialize to make ready for setting values |
|
|
|
@check HYPRE_IJMatrixInitialize(A.ijmatrix) |
|
|
|
@check HYPRE_IJMatrixInitialize(A) |
|
|
|
return A |
|
|
|
return A |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
@ -78,10 +93,10 @@ end |
|
|
|
# This should be called after setting all the values |
|
|
|
# This should be called after setting all the values |
|
|
|
function Internals.assemble_matrix(A::HYPREMatrix) |
|
|
|
function Internals.assemble_matrix(A::HYPREMatrix) |
|
|
|
# Finalize after setting all values |
|
|
|
# Finalize after setting all values |
|
|
|
@check HYPRE_IJMatrixAssemble(A.ijmatrix) |
|
|
|
@check HYPRE_IJMatrixAssemble(A) |
|
|
|
# Fetch the assembled CSR matrix |
|
|
|
# Fetch the assembled CSR matrix |
|
|
|
parmatrix_ref = Ref{Ptr{Cvoid}}(C_NULL) |
|
|
|
parmatrix_ref = Ref{Ptr{Cvoid}}(C_NULL) |
|
|
|
@check HYPRE_IJMatrixGetObject(A.ijmatrix, parmatrix_ref) |
|
|
|
@check HYPRE_IJMatrixGetObject(A, parmatrix_ref) |
|
|
|
A.parmatrix = convert(Ptr{HYPRE_ParCSRMatrix}, parmatrix_ref[]) |
|
|
|
A.parmatrix = convert(Ptr{HYPRE_ParCSRMatrix}, parmatrix_ref[]) |
|
|
|
return A |
|
|
|
return A |
|
|
|
end |
|
|
|
end |
|
|
|
@ -91,13 +106,18 @@ end |
|
|
|
############### |
|
|
|
############### |
|
|
|
|
|
|
|
|
|
|
|
mutable struct HYPREVector # <: AbstractVector{HYPRE_Complex} |
|
|
|
mutable struct HYPREVector # <: AbstractVector{HYPRE_Complex} |
|
|
|
#= const =# comm::MPI.Comm |
|
|
|
const comm::MPI.Comm |
|
|
|
#= const =# ilower::HYPRE_BigInt |
|
|
|
const ilower::HYPRE_BigInt |
|
|
|
#= const =# iupper::HYPRE_BigInt |
|
|
|
const iupper::HYPRE_BigInt |
|
|
|
ijvector::HYPRE_IJVector |
|
|
|
ijvector::HYPRE_IJVector |
|
|
|
parvector::HYPRE_ParVector |
|
|
|
parvector::HYPRE_ParVector |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Defining unsafe_convert enables ccall to automatically convert b::HYPREVector to |
|
|
|
|
|
|
|
# HYPRE_IJVector and HYPRE_ParVector while also making sure b won't be GC'd and finalized. |
|
|
|
|
|
|
|
Base.unsafe_convert(::Type{HYPRE_IJVector}, b::HYPREVector) = b.ijvector |
|
|
|
|
|
|
|
Base.unsafe_convert(::Type{HYPRE_ParVector}, b::HYPREVector) = b.parvector |
|
|
|
|
|
|
|
|
|
|
|
function HYPREVector(comm::MPI.Comm, ilower::Integer, iupper::Integer) |
|
|
|
function HYPREVector(comm::MPI.Comm, ilower::Integer, iupper::Integer) |
|
|
|
# Create the IJ vector |
|
|
|
# Create the IJ vector |
|
|
|
b = HYPREVector(comm, ilower, iupper, C_NULL, C_NULL) |
|
|
|
b = HYPREVector(comm, ilower, iupper, C_NULL, C_NULL) |
|
|
|
@ -105,20 +125,26 @@ function HYPREVector(comm::MPI.Comm, ilower::Integer, iupper::Integer) |
|
|
|
@check HYPRE_IJVectorCreate(comm, ilower, iupper, ijvector_ref) |
|
|
|
@check HYPRE_IJVectorCreate(comm, ilower, iupper, ijvector_ref) |
|
|
|
b.ijvector = ijvector_ref[] |
|
|
|
b.ijvector = ijvector_ref[] |
|
|
|
# Attach a finalizer |
|
|
|
# Attach a finalizer |
|
|
|
finalizer(x -> HYPRE_IJVectorDestroy(x.ijvector), b) |
|
|
|
finalizer(b) do x |
|
|
|
|
|
|
|
if x.ijvector != C_NULL |
|
|
|
|
|
|
|
HYPRE_IJVectorDestroy(x) |
|
|
|
|
|
|
|
x.ijvector = x.parvector = C_NULL |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
push!(Internals.HYPRE_OBJECTS, b => nothing) |
|
|
|
# Set storage type |
|
|
|
# Set storage type |
|
|
|
@check HYPRE_IJVectorSetObjectType(b.ijvector, HYPRE_PARCSR) |
|
|
|
@check HYPRE_IJVectorSetObjectType(b, HYPRE_PARCSR) |
|
|
|
# Initialize to make ready for setting values |
|
|
|
# Initialize to make ready for setting values |
|
|
|
@check HYPRE_IJVectorInitialize(b.ijvector) |
|
|
|
@check HYPRE_IJVectorInitialize(b) |
|
|
|
return b |
|
|
|
return b |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function Internals.assemble_vector(b::HYPREVector) |
|
|
|
function Internals.assemble_vector(b::HYPREVector) |
|
|
|
# Finalize after setting all values |
|
|
|
# Finalize after setting all values |
|
|
|
@check HYPRE_IJVectorAssemble(b.ijvector) |
|
|
|
@check HYPRE_IJVectorAssemble(b) |
|
|
|
# Fetch the assembled vector |
|
|
|
# Fetch the assembled vector |
|
|
|
parvector_ref = Ref{Ptr{Cvoid}}(C_NULL) |
|
|
|
parvector_ref = Ref{Ptr{Cvoid}}(C_NULL) |
|
|
|
@check HYPRE_IJVectorGetObject(b.ijvector, parvector_ref) |
|
|
|
@check HYPRE_IJVectorGetObject(b, parvector_ref) |
|
|
|
b.parvector = convert(Ptr{HYPRE_ParVector}, parvector_ref[]) |
|
|
|
b.parvector = convert(Ptr{HYPRE_ParVector}, parvector_ref[]) |
|
|
|
return b |
|
|
|
return b |
|
|
|
end |
|
|
|
end |
|
|
|
@ -126,7 +152,7 @@ end |
|
|
|
function Internals.get_proc_rows(b::HYPREVector) |
|
|
|
function Internals.get_proc_rows(b::HYPREVector) |
|
|
|
# ilower_ref = Ref{HYPRE_BigInt}() |
|
|
|
# ilower_ref = Ref{HYPRE_BigInt}() |
|
|
|
# iupper_ref = Ref{HYPRE_BigInt}() |
|
|
|
# iupper_ref = Ref{HYPRE_BigInt}() |
|
|
|
# @check HYPRE_IJVectorGetLocalRange(b.ijvector, ilower_ref, iupper_ref) |
|
|
|
# @check HYPRE_IJVectorGetLocalRange(b, ilower_ref, iupper_ref) |
|
|
|
# ilower = ilower_ref[] |
|
|
|
# ilower = ilower_ref[] |
|
|
|
# iupper = iupper_ref[] |
|
|
|
# iupper = iupper_ref[] |
|
|
|
# return ilower, iupper |
|
|
|
# return ilower, iupper |
|
|
|
@ -152,105 +178,24 @@ function Base.zero(b::HYPREVector) |
|
|
|
nvalues = jupper - jlower + 1 |
|
|
|
nvalues = jupper - jlower + 1 |
|
|
|
indices = collect(HYPRE_BigInt, jlower:jupper) |
|
|
|
indices = collect(HYPRE_BigInt, jlower:jupper) |
|
|
|
values = zeros(HYPRE_Complex, nvalues) |
|
|
|
values = zeros(HYPRE_Complex, nvalues) |
|
|
|
@check HYPRE_IJVectorSetValues(x.ijvector, nvalues, indices, values) |
|
|
|
@check HYPRE_IJVectorSetValues(x, nvalues, indices, values) |
|
|
|
# Finalize and return |
|
|
|
# Finalize and return |
|
|
|
Internals.assemble_vector(x) |
|
|
|
Internals.assemble_vector(x) |
|
|
|
return x |
|
|
|
return x |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
###################################### |
|
|
|
|
|
|
|
# SparseMatrixCS(C|R) -> HYPREMatrix # |
|
|
|
######################### |
|
|
|
###################################### |
|
|
|
# Vector -> HYPREVector # |
|
|
|
|
|
|
|
######################### |
|
|
|
|
|
|
|
|
|
|
|
function Internals.check_n_rows(A, ilower, iupper) |
|
|
|
function Internals.check_n_rows(A, ilower, iupper) |
|
|
|
if size(A, 1) != (iupper - ilower + 1) |
|
|
|
if size(A, 1) != (iupper - ilower + 1) |
|
|
|
throw(ArgumentError("number of rows in matrix does not match global start/end rows ilower and iupper")) |
|
|
|
throw(ArgumentError("number of rows in matrix does not match global start/end rows ilower and iupper")) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
return |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function Internals.to_hypre_data(A::SparseMatrixCSC, ilower, iupper) |
|
|
|
|
|
|
|
Internals.check_n_rows(A, ilower, iupper) |
|
|
|
|
|
|
|
nnz = SparseArrays.nnz(A) |
|
|
|
|
|
|
|
A_rows = rowvals(A) |
|
|
|
|
|
|
|
A_vals = nonzeros(A) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Initialize the data buffers HYPRE wants |
|
|
|
|
|
|
|
nrows = HYPRE_Int(iupper - ilower + 1) # Total number of rows |
|
|
|
|
|
|
|
ncols = zeros(HYPRE_Int, nrows) # Number of colums for each row |
|
|
|
|
|
|
|
rows = collect(HYPRE_BigInt, ilower:iupper) # The row indices |
|
|
|
|
|
|
|
cols = Vector{HYPRE_BigInt}(undef, nnz) # The column indices |
|
|
|
|
|
|
|
values = Vector{HYPRE_Complex}(undef, nnz) # The values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# First pass to count nnz per row |
|
|
|
|
|
|
|
@inbounds for j in 1:size(A, 2) |
|
|
|
|
|
|
|
for i in nzrange(A, j) |
|
|
|
|
|
|
|
row = A_rows[i] |
|
|
|
|
|
|
|
ncols[row] += 1 |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Keep track of the last index used for every row |
|
|
|
|
|
|
|
lastinds = zeros(Int, nrows) |
|
|
|
|
|
|
|
cumsum!((@view lastinds[2:end]), (@view ncols[1:end-1])) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Second pass to populate the output |
|
|
|
|
|
|
|
@inbounds for j in 1:size(A, 2) |
|
|
|
|
|
|
|
for i in nzrange(A, j) |
|
|
|
|
|
|
|
row = A_rows[i] |
|
|
|
|
|
|
|
k = lastinds[row] += 1 |
|
|
|
|
|
|
|
val = A_vals[i] |
|
|
|
|
|
|
|
cols[k] = j |
|
|
|
|
|
|
|
values[k] = val |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
return nrows, ncols, rows, cols, values |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function Internals.to_hypre_data(A::SparseMatrixCSR, ilower, iupper) |
|
|
|
|
|
|
|
Internals.check_n_rows(A, ilower, iupper) |
|
|
|
|
|
|
|
nnz = SparseArrays.nnz(A) |
|
|
|
|
|
|
|
A_cols = colvals(A) |
|
|
|
|
|
|
|
A_vals = nonzeros(A) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Initialize the data buffers HYPRE wants |
|
|
|
|
|
|
|
nrows = HYPRE_Int(iupper - ilower + 1) # Total number of rows |
|
|
|
|
|
|
|
ncols = Vector{HYPRE_Int}(undef, nrows) # Number of colums for each row |
|
|
|
|
|
|
|
rows = collect(HYPRE_BigInt, ilower:iupper) # The row indices |
|
|
|
|
|
|
|
cols = Vector{HYPRE_BigInt}(undef, nnz) # The column indices |
|
|
|
|
|
|
|
values = Vector{HYPRE_Complex}(undef, nnz) # The values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Loop over the rows and collect all values |
|
|
|
|
|
|
|
k = 0 |
|
|
|
|
|
|
|
@inbounds for i in 1:size(A, 1) |
|
|
|
|
|
|
|
nzr = nzrange(A, i) |
|
|
|
|
|
|
|
ncols[i] = length(nzr) |
|
|
|
|
|
|
|
for j in nzr |
|
|
|
|
|
|
|
k += 1 |
|
|
|
|
|
|
|
col = A_cols[j] |
|
|
|
|
|
|
|
val = A_vals[j] |
|
|
|
|
|
|
|
cols[k] = col |
|
|
|
|
|
|
|
values[k] = val |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
@assert nnz == k |
|
|
|
|
|
|
|
return nrows, ncols, rows, cols, values |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function HYPREMatrix(comm::MPI.Comm, B::Union{SparseMatrixCSC,SparseMatrixCSR}, ilower, iupper) |
|
|
|
|
|
|
|
A = HYPREMatrix(comm, ilower, iupper) |
|
|
|
|
|
|
|
nrows, ncols, rows, cols, values = Internals.to_hypre_data(B, ilower, iupper) |
|
|
|
|
|
|
|
@check HYPRE_IJMatrixSetValues(A.ijmatrix, nrows, ncols, rows, cols, values) |
|
|
|
|
|
|
|
Internals.assemble_matrix(A) |
|
|
|
|
|
|
|
return A |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HYPREMatrix(B::Union{SparseMatrixCSC,SparseMatrixCSR}, ilower=1, iupper=size(B, 1)) = |
|
|
|
|
|
|
|
HYPREMatrix(MPI.COMM_SELF, B, ilower, iupper) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
######################### |
|
|
|
|
|
|
|
# Vector -> HYPREVector # |
|
|
|
|
|
|
|
######################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function Internals.to_hypre_data(x::Vector, ilower, iupper) |
|
|
|
function Internals.to_hypre_data(x::Vector, ilower, iupper) |
|
|
|
Internals.check_n_rows(x, ilower, iupper) |
|
|
|
Internals.check_n_rows(x, ilower, iupper) |
|
|
|
indices = collect(HYPRE_BigInt, ilower:iupper) |
|
|
|
indices = collect(HYPRE_BigInt, ilower:iupper) |
|
|
|
@ -262,13 +207,14 @@ end |
|
|
|
function HYPREVector(comm::MPI.Comm, x::Vector, ilower, iupper) |
|
|
|
function HYPREVector(comm::MPI.Comm, x::Vector, ilower, iupper) |
|
|
|
b = HYPREVector(comm, ilower, iupper) |
|
|
|
b = HYPREVector(comm, ilower, iupper) |
|
|
|
nvalues, indices, values = Internals.to_hypre_data(x, ilower, iupper) |
|
|
|
nvalues, indices, values = Internals.to_hypre_data(x, ilower, iupper) |
|
|
|
@check HYPRE_IJVectorSetValues(b.ijvector, nvalues, indices, values) |
|
|
|
@check HYPRE_IJVectorSetValues(b, nvalues, indices, values) |
|
|
|
Internals.assemble_vector(b) |
|
|
|
Internals.assemble_vector(b) |
|
|
|
return b |
|
|
|
return b |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
HYPREVector(x::Vector, ilower=1, iupper=length(x)) = |
|
|
|
function HYPREVector(x::Vector, ilower = 1, iupper = length(x)) |
|
|
|
HYPREVector(MPI.COMM_SELF, x, ilower, iupper) |
|
|
|
return HYPREVector(MPI.COMM_SELF, x, ilower, iupper) |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
# TODO: Other eltypes could be support by using a intermediate buffer |
|
|
|
# TODO: Other eltypes could be support by using a intermediate buffer |
|
|
|
function Base.copy!(dst::Vector{HYPRE_Complex}, src::HYPREVector) |
|
|
|
function Base.copy!(dst::Vector{HYPRE_Complex}, src::HYPREVector) |
|
|
|
@ -278,7 +224,7 @@ function Base.copy!(dst::Vector{HYPRE_Complex}, src::HYPREVector) |
|
|
|
throw(ArgumentError("length of dst and src does not match")) |
|
|
|
throw(ArgumentError("length of dst and src does not match")) |
|
|
|
end |
|
|
|
end |
|
|
|
indices = collect(HYPRE_BigInt, ilower:iupper) |
|
|
|
indices = collect(HYPRE_BigInt, ilower:iupper) |
|
|
|
@check HYPRE_IJVectorGetValues(src.ijvector, nvalues, indices, dst) |
|
|
|
@check HYPRE_IJVectorGetValues(src, nvalues, indices, dst) |
|
|
|
return dst |
|
|
|
return dst |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
@ -289,242 +235,187 @@ function Base.copy!(dst::HYPREVector, src::Vector{HYPRE_Complex}) |
|
|
|
throw(ArgumentError("length of dst and src does not match")) |
|
|
|
throw(ArgumentError("length of dst and src does not match")) |
|
|
|
end |
|
|
|
end |
|
|
|
# Re-initialize the vector |
|
|
|
# Re-initialize the vector |
|
|
|
@check HYPRE_IJVectorInitialize(dst.ijvector) |
|
|
|
@check HYPRE_IJVectorInitialize(dst) |
|
|
|
# Set all the values |
|
|
|
# Set all the values |
|
|
|
indices = collect(HYPRE_BigInt, ilower:iupper) |
|
|
|
indices = collect(HYPRE_BigInt, ilower:iupper) |
|
|
|
@check HYPRE_IJVectorSetValues(dst.ijvector, nvalues, indices, src) |
|
|
|
@check HYPRE_IJVectorSetValues(dst, nvalues, indices, src) |
|
|
|
# TODO: It shouldn't be necessary to assemble here since we only set owned rows (?) |
|
|
|
# TODO: It shouldn't be necessary to assemble here since we only set owned rows (?) |
|
|
|
# @check HYPRE_IJVectorAssemble(dst.ijvector) |
|
|
|
# @check HYPRE_IJVectorAssemble(dst) |
|
|
|
# TODO: Necessary to recreate the ParVector? Running some examples it seems like it is |
|
|
|
# TODO: Necessary to recreate the ParVector? Running some examples it seems like it is |
|
|
|
# not needed. |
|
|
|
# not needed. |
|
|
|
return dst |
|
|
|
return dst |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
################################################## |
|
|
|
|
|
|
|
# PartitionedArrays.PSparseMatrix -> HYPREMatrix # |
|
|
|
#################### |
|
|
|
################################################## |
|
|
|
## HYPREAssembler ## |
|
|
|
|
|
|
|
#################### |
|
|
|
# TODO: This has some duplicated code with to_hypre_data(::SparseMatrixCSC, ilower, iupper) |
|
|
|
|
|
|
|
function Internals.to_hypre_data(A::SparseMatrixCSC, r::IndexRange, c::IndexRange) |
|
|
|
struct HYPREMatrixAssembler |
|
|
|
@assert r.oid_to_lid isa UnitRange && r.oid_to_lid.start == 1 |
|
|
|
A::HYPREMatrix |
|
|
|
|
|
|
|
ncols::Vector{HYPRE_Int} |
|
|
|
ilower = r.lid_to_gid[r.oid_to_lid.start] |
|
|
|
rows::Vector{HYPRE_BigInt} |
|
|
|
iupper = r.lid_to_gid[r.oid_to_lid.stop] |
|
|
|
cols::Vector{HYPRE_BigInt} |
|
|
|
a_rows = rowvals(A) |
|
|
|
values::Vector{HYPRE_Complex} |
|
|
|
a_vals = nonzeros(A) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Initialize the data buffers HYPRE wants |
|
|
|
|
|
|
|
nrows = HYPRE_Int(iupper - ilower + 1) # Total number of rows |
|
|
|
|
|
|
|
ncols = zeros(HYPRE_Int, nrows) # Number of colums for each row |
|
|
|
|
|
|
|
rows = collect(HYPRE_BigInt, ilower:iupper) # The row indices |
|
|
|
|
|
|
|
# cols = Vector{HYPRE_BigInt}(undef, nnz) # The column indices |
|
|
|
|
|
|
|
# values = Vector{HYPRE_Complex}(undef, nnz) # The values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# First pass to count nnz per row (note that the fact that columns are permuted |
|
|
|
|
|
|
|
# doesn't matter for this pass) |
|
|
|
|
|
|
|
a_rows = rowvals(A) |
|
|
|
|
|
|
|
a_vals = nonzeros(A) |
|
|
|
|
|
|
|
@inbounds for j in 1:size(A, 2) |
|
|
|
|
|
|
|
for i in nzrange(A, j) |
|
|
|
|
|
|
|
row = a_rows[i] |
|
|
|
|
|
|
|
row > r.oid_to_lid.stop && continue # Skip ghost rows |
|
|
|
|
|
|
|
# grow = r.lid_to_gid[lrow] |
|
|
|
|
|
|
|
ncols[row] += 1 |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Initialize remaining buffers now that nnz is known |
|
|
|
|
|
|
|
nnz = sum(ncols) |
|
|
|
|
|
|
|
cols = Vector{HYPRE_BigInt}(undef, nnz) |
|
|
|
|
|
|
|
values = Vector{HYPRE_Complex}(undef, nnz) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Keep track of the last index used for every row |
|
|
|
|
|
|
|
lastinds = zeros(Int, nrows) |
|
|
|
|
|
|
|
cumsum!((@view lastinds[2:end]), (@view ncols[1:end-1])) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Second pass to populate the output -- here we need to take care of the permutation |
|
|
|
|
|
|
|
# of columns. TODO: Problem that they are not sorted? |
|
|
|
|
|
|
|
@inbounds for j in 1:size(A, 2) |
|
|
|
|
|
|
|
for i in nzrange(A, j) |
|
|
|
|
|
|
|
row = a_rows[i] |
|
|
|
|
|
|
|
row > r.oid_to_lid.stop && continue # Skip ghost rows |
|
|
|
|
|
|
|
k = lastinds[row] += 1 |
|
|
|
|
|
|
|
val = a_vals[i] |
|
|
|
|
|
|
|
cols[k] = c.lid_to_gid[j] |
|
|
|
|
|
|
|
values[k] = val |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
return nrows, ncols, rows, cols, values |
|
|
|
|
|
|
|
|
|
|
|
struct HYPREVectorAssembler |
|
|
|
|
|
|
|
b::HYPREVector |
|
|
|
|
|
|
|
indices::Vector{HYPRE_BigInt} |
|
|
|
|
|
|
|
values::Vector{HYPRE_Complex} |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
# TODO: Possibly this can be optimized if it is possible to pass overlong vectors to HYPRE. |
|
|
|
struct HYPREAssembler |
|
|
|
# At least values should be possible to directly share, but cols needs to translated |
|
|
|
A::HYPREMatrixAssembler |
|
|
|
# to global ids. |
|
|
|
b::HYPREVectorAssembler |
|
|
|
function Internals.to_hypre_data(A::SparseMatrixCSR, r::IndexRange, c::IndexRange) |
|
|
|
|
|
|
|
@assert r.oid_to_lid isa UnitRange && r.oid_to_lid.start == 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ilower = r.lid_to_gid[r.oid_to_lid.start] |
|
|
|
|
|
|
|
iupper = r.lid_to_gid[r.oid_to_lid.stop] |
|
|
|
|
|
|
|
a_cols = colvals(A) |
|
|
|
|
|
|
|
a_vals = nonzeros(A) |
|
|
|
|
|
|
|
nnz = getrowptr(A)[r.oid_to_lid.stop + 1] - 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Initialize the data buffers HYPRE wants |
|
|
|
|
|
|
|
nrows = HYPRE_Int(iupper - ilower + 1) # Total number of rows |
|
|
|
|
|
|
|
ncols = zeros(HYPRE_Int, nrows) # Number of colums for each row |
|
|
|
|
|
|
|
rows = collect(HYPRE_BigInt, ilower:iupper) # The row indices |
|
|
|
|
|
|
|
cols = Vector{HYPRE_BigInt}(undef, nnz) # The column indices |
|
|
|
|
|
|
|
values = Vector{HYPRE_Complex}(undef, nnz) # The values |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Loop over the (owned) rows and collect all values |
|
|
|
|
|
|
|
k = 0 |
|
|
|
|
|
|
|
@inbounds for i in r.oid_to_lid |
|
|
|
|
|
|
|
nzr = nzrange(A, i) |
|
|
|
|
|
|
|
ncols[i] = length(nzr) |
|
|
|
|
|
|
|
for j in nzr |
|
|
|
|
|
|
|
k += 1 |
|
|
|
|
|
|
|
col = a_cols[j] |
|
|
|
|
|
|
|
val = a_vals[j] |
|
|
|
|
|
|
|
cols[k] = c.lid_to_gid[col] |
|
|
|
|
|
|
|
values[k] = val |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
@assert nnz == k |
|
|
|
|
|
|
|
return nrows, ncols, rows, cols, values |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function Internals.get_comm(A::Union{PSparseMatrix{<:Any,<:M}, PVector{<:Any,<:M}}) where M <: MPIData |
|
|
|
""" |
|
|
|
return A.rows.partition.comm |
|
|
|
HYPRE.start_assemble!(A::HYPREMatrix) -> HYPREMatrixAssembler |
|
|
|
|
|
|
|
HYPRE.start_assemble!(b::HYPREVector) -> HYPREVectorAssembler |
|
|
|
|
|
|
|
HYPRE.start_assemble!(A::HYPREMatrix, b::HYPREVector) -> HYPREAssembler |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Initialize a new assembly for matrix `A`, vector `b`, or for both. This zeroes out any |
|
|
|
|
|
|
|
previous data in the arrays. Return a `HYPREAssembler` with allocated data buffers needed to |
|
|
|
|
|
|
|
perform the assembly efficiently. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
See also: [`HYPRE.assemble!`](@ref), [`HYPRE.finish_assemble!`](@ref). |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
start_assemble! |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function start_assemble!(A::HYPREMatrix) |
|
|
|
|
|
|
|
if A.parmatrix != C_NULL |
|
|
|
|
|
|
|
# This matrix have been assembled before, reset to 0 |
|
|
|
|
|
|
|
@check HYPRE_IJMatrixSetConstantValues(A, 0) |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
@check HYPRE_IJMatrixInitialize(A) |
|
|
|
|
|
|
|
return HYPREMatrixAssembler(A, HYPRE_Int[], HYPRE_BigInt[], HYPRE_BigInt[], HYPRE_Complex[]) |
|
|
|
end |
|
|
|
end |
|
|
|
Internals.get_comm(_::Union{PSparseMatrix,PVector}) = MPI.COMM_SELF |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function Internals.get_proc_rows(A::Union{PSparseMatrix{<:Any,<:M}, PVector{<:Any,<:M}}) where M <: MPIData |
|
|
|
function start_assemble!(b::HYPREVector) |
|
|
|
r = A.rows.partition.part |
|
|
|
if b.parvector != C_NULL |
|
|
|
ilower::HYPRE_BigInt = r.lid_to_gid[r.oid_to_lid[1]] |
|
|
|
# This vector have been assembled before, reset to 0 |
|
|
|
iupper::HYPRE_BigInt = r.lid_to_gid[r.oid_to_lid[end]] |
|
|
|
# See https://github.com/hypre-space/hypre/pull/689 |
|
|
|
return ilower, iupper |
|
|
|
# @check HYPRE_IJVectorSetConstantValues(b, 0) |
|
|
|
end |
|
|
|
end |
|
|
|
function Internals.get_proc_rows(A::Union{PSparseMatrix{<:Any,<:S}, PVector{<:Any,<:S}}) where S <: SequentialData |
|
|
|
@check HYPRE_IJVectorInitialize(b) |
|
|
|
ilower::HYPRE_BigInt = typemax(HYPRE_BigInt) |
|
|
|
if b.parvector != C_NULL |
|
|
|
iupper::HYPRE_BigInt = typemin(HYPRE_BigInt) |
|
|
|
nvalues = HYPRE_Int(b.iupper - b.ilower + 1) |
|
|
|
for r in A.rows.partition.parts |
|
|
|
indices = collect(HYPRE_BigInt, b.ilower:b.iupper) |
|
|
|
ilower = min(r.lid_to_gid[r.oid_to_lid[1]], ilower) |
|
|
|
values = zeros(HYPRE_Complex, nvalues) |
|
|
|
iupper = max(r.lid_to_gid[r.oid_to_lid[end]], iupper) |
|
|
|
@check HYPRE_IJVectorSetValues(b, nvalues, indices, values) |
|
|
|
|
|
|
|
# TODO: Do I need to assemble here? |
|
|
|
end |
|
|
|
end |
|
|
|
return ilower, iupper |
|
|
|
return HYPREVectorAssembler(b, HYPRE_BigInt[], HYPRE_Complex[]) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function HYPREMatrix(B::PSparseMatrix) |
|
|
|
function start_assemble!(A::HYPREMatrix, b::HYPREVector) |
|
|
|
# Use the same communicator as the matrix |
|
|
|
return HYPREAssembler(start_assemble!(A), start_assemble!(b)) |
|
|
|
comm = Internals.get_comm(B) |
|
|
|
|
|
|
|
# Fetch rows owned by this process |
|
|
|
|
|
|
|
ilower, iupper = Internals.get_proc_rows(B) |
|
|
|
|
|
|
|
# Create the IJ matrix |
|
|
|
|
|
|
|
A = HYPREMatrix(comm, ilower, iupper) |
|
|
|
|
|
|
|
# Set all the values |
|
|
|
|
|
|
|
map_parts(B.values, B.rows.partition, B.cols.partition) do Bv, Br, Bc |
|
|
|
|
|
|
|
nrows, ncols, rows, cols, values = Internals.to_hypre_data(Bv, Br, Bc) |
|
|
|
|
|
|
|
@check HYPRE_IJMatrixSetValues(A.ijmatrix, nrows, ncols, rows, cols, values) |
|
|
|
|
|
|
|
return nothing |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
# Finalize |
|
|
|
|
|
|
|
Internals.assemble_matrix(A) |
|
|
|
|
|
|
|
return A |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
############################################ |
|
|
|
""" |
|
|
|
# PartitionedArrays.PVector -> HYPREVector # |
|
|
|
HYPRE.assemble!(A::HYPREMatrixAssembler, i, j, a::Matrix) |
|
|
|
############################################ |
|
|
|
HYPRE.assemble!(A::HYPREVectorAssembler, i, b::Vector) |
|
|
|
|
|
|
|
HYPRE.assemble!(A::HYPREAssembler, ij, a::Matrix, b::Vector) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assemble (by adding) matrix contribution `a`, vector contribution `b`, into the underlying |
|
|
|
|
|
|
|
array(s) of the assembler at global row indices `i` and column indices `j`. |
|
|
|
|
|
|
|
|
|
|
|
function HYPREVector(v::PVector) |
|
|
|
This is roughly equivalent to: |
|
|
|
# Use the same communicator as the matrix |
|
|
|
```julia |
|
|
|
comm = Internals.get_comm(v) |
|
|
|
# A.A::HYPREMatrix |
|
|
|
# Fetch rows owned by this process |
|
|
|
A.A[i, j] += a |
|
|
|
ilower, iupper = Internals.get_proc_rows(v) |
|
|
|
|
|
|
|
# Create the IJ vector |
|
|
|
# A.b::HYPREVector |
|
|
|
b = HYPREVector(comm, ilower, iupper) |
|
|
|
A.b[i] += b |
|
|
|
# Set all the values |
|
|
|
``` |
|
|
|
map_parts(v.values, v.owned_values, v.rows.partition) do _, vo, vr |
|
|
|
|
|
|
|
ilower_part = vr.lid_to_gid[vr.oid_to_lid.start] |
|
|
|
See also: [`HYPRE.start_assemble!`](@ref), [`HYPRE.finish_assemble!`](@ref). |
|
|
|
iupper_part = vr.lid_to_gid[vr.oid_to_lid.stop] |
|
|
|
""" |
|
|
|
|
|
|
|
assemble! |
|
|
|
# Option 1: Set all values |
|
|
|
|
|
|
|
nvalues = HYPRE_Int(iupper_part - ilower_part + 1) |
|
|
|
function assemble!(A::HYPREMatrixAssembler, i::Vector, j::Vector, a::Matrix) |
|
|
|
indices = collect(HYPRE_BigInt, ilower_part:iupper_part) |
|
|
|
nrows, ncols, rows, cols, values = Internals.to_hypre_data(A, a, i, j) |
|
|
|
# TODO: Could probably just pass the full vector even if it is too long |
|
|
|
@check HYPRE_IJMatrixAddToValues(A.A, nrows, ncols, rows, cols, values) |
|
|
|
# values = convert(Vector{HYPRE_Complex}, vv) |
|
|
|
return A |
|
|
|
values = collect(HYPRE_Complex, vo) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# # Option 2: Set only non-zeros |
|
|
|
|
|
|
|
# indices = HYPRE_BigInt[] |
|
|
|
|
|
|
|
# values = HYPRE_Complex[] |
|
|
|
|
|
|
|
# for (i, vi) in zip(ilower_part:iupper_part, vo) |
|
|
|
|
|
|
|
# if !iszero(vi) |
|
|
|
|
|
|
|
# push!(indices, i) |
|
|
|
|
|
|
|
# push!(values, vi) |
|
|
|
|
|
|
|
# end |
|
|
|
|
|
|
|
# end |
|
|
|
|
|
|
|
# nvalues = length(indices) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@check HYPRE_IJVectorSetValues(b.ijvector, nvalues, indices, values) |
|
|
|
|
|
|
|
return nothing |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
# Finalize |
|
|
|
@deprecate assemble!(A::HYPREMatrixAssembler, ij::Vector, a::Matrix) assemble!(A, ij, ij, a) false |
|
|
|
Internals.assemble_vector(b) |
|
|
|
|
|
|
|
return b |
|
|
|
function assemble!(A::HYPREVectorAssembler, ij::Vector, a::Vector) |
|
|
|
|
|
|
|
nvalues, indices, values = Internals.to_hypre_data(A, a, ij) |
|
|
|
|
|
|
|
@check HYPRE_IJVectorAddToValues(A.b, nvalues, indices, values) |
|
|
|
|
|
|
|
return A |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function Internals.copy_check(dst::HYPREVector, src::PVector) |
|
|
|
function assemble!(A::HYPREAssembler, ij::Vector, a::Matrix, b::Vector) |
|
|
|
il_dst, iu_dst = Internals.get_proc_rows(dst) |
|
|
|
assemble!(A.A, ij, ij, a) |
|
|
|
il_src, iu_src = Internals.get_proc_rows(src) |
|
|
|
assemble!(A.b, ij, b) |
|
|
|
if il_dst != il_src && iu_dst != iu_src |
|
|
|
return A |
|
|
|
# TODO: Why require this? |
|
|
|
|
|
|
|
throw(ArgumentError( |
|
|
|
|
|
|
|
"row owner mismatch between dst ($(il_dst:iu_dst)) and src ($(il_dst:iu_dst))" |
|
|
|
|
|
|
|
)) |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function Internals.to_hypre_data(A::HYPREMatrixAssembler, a::Matrix, I::Vector, J::Vector) |
|
|
|
|
|
|
|
size(a, 1) == length(I) || error("mismatching number of rows") |
|
|
|
|
|
|
|
size(a, 2) == length(J) || error("mismatching number of cols") |
|
|
|
|
|
|
|
nrows = HYPRE_Int(length(I)) |
|
|
|
|
|
|
|
# Resize cache vectors |
|
|
|
|
|
|
|
ncols = resize!(A.ncols, nrows) |
|
|
|
|
|
|
|
rows = resize!(A.rows, nrows) |
|
|
|
|
|
|
|
cols = resize!(A.cols, length(a)) |
|
|
|
|
|
|
|
values = resize!(A.values, length(a)) |
|
|
|
|
|
|
|
# Fill vectors |
|
|
|
|
|
|
|
ncols = fill!(ncols, HYPRE_Int(length(J))) |
|
|
|
|
|
|
|
copyto!(rows, I) |
|
|
|
|
|
|
|
idx = 0 |
|
|
|
|
|
|
|
for i in 1:length(I), j in 1:length(J) |
|
|
|
|
|
|
|
idx += 1 |
|
|
|
|
|
|
|
cols[idx] = J[j] |
|
|
|
|
|
|
|
values[idx] = a[i, j] |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
@assert idx == length(a) |
|
|
|
|
|
|
|
@assert nrows == length(ncols) == length(rows) |
|
|
|
|
|
|
|
return nrows, ncols, rows, cols, values |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
# TODO: Other eltypes could be support by using a intermediate buffer |
|
|
|
function Internals.to_hypre_data(A::HYPREVectorAssembler, b::Vector, I::Vector) |
|
|
|
function Base.copy!(dst::PVector{HYPRE_Complex}, src::HYPREVector) |
|
|
|
length(b) == length(I) || error("mismatching number of entries") |
|
|
|
Internals.copy_check(src, dst) |
|
|
|
nvalues = HYPRE_Int(length(I)) |
|
|
|
map_parts(dst.values, dst.owned_values, dst.rows.partition) do vv, _, vr |
|
|
|
# Resize cache vectors |
|
|
|
il_src_part = vr.lid_to_gid[vr.oid_to_lid.start] |
|
|
|
indices = resize!(A.indices, nvalues) |
|
|
|
iu_src_part = vr.lid_to_gid[vr.oid_to_lid.stop] |
|
|
|
values = resize!(A.values, nvalues) |
|
|
|
nvalues = HYPRE_Int(iu_src_part - il_src_part + 1) |
|
|
|
# Fill vectors |
|
|
|
indices = collect(HYPRE_BigInt, il_src_part:iu_src_part) |
|
|
|
copyto!(indices, I) |
|
|
|
|
|
|
|
copyto!(values, b) |
|
|
|
# Assumption: the dst vector is assembled, and should thus have 0s on the ghost |
|
|
|
return nvalues, indices, values |
|
|
|
# entries (??). If this is not true, we must call fill!(vv, 0) here. This should be |
|
|
|
|
|
|
|
# fairly cheap anyway, so might as well do it... |
|
|
|
|
|
|
|
fill!(vv, 0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# TODO: Safe to use vv here? Owned values are always first? |
|
|
|
|
|
|
|
@check HYPRE_IJVectorGetValues(src.ijvector, nvalues, indices, vv) |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
return dst |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
HYPRE.finish_assemble!(A::HYPREMatrixAssembler) |
|
|
|
|
|
|
|
HYPRE.finish_assemble!(A::HYPREVectorAssembler) |
|
|
|
|
|
|
|
HYPRE.finish_assemble!(A::HYPREAssembler) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Finish the assembly. This synchronizes the data between processors. |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
finish_assemble! |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function finish_assemble!(A::HYPREMatrixAssembler) |
|
|
|
|
|
|
|
Internals.assemble_matrix(A.A) |
|
|
|
|
|
|
|
return A.A |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
function Base.copy!(dst::HYPREVector, src::PVector{HYPRE_Complex}) |
|
|
|
function finish_assemble!(A::HYPREVectorAssembler) |
|
|
|
Internals.copy_check(dst, src) |
|
|
|
Internals.assemble_vector(A.b) |
|
|
|
# Re-initialize the vector |
|
|
|
return A.b |
|
|
|
@check HYPRE_IJVectorInitialize(dst.ijvector) |
|
|
|
|
|
|
|
map_parts(src.values, src.owned_values, src.rows.partition) do vv, _, vr |
|
|
|
|
|
|
|
ilower_src_part = vr.lid_to_gid[vr.oid_to_lid.start] |
|
|
|
|
|
|
|
iupper_src_part = vr.lid_to_gid[vr.oid_to_lid.stop] |
|
|
|
|
|
|
|
nvalues = HYPRE_Int(iupper_src_part - ilower_src_part + 1) |
|
|
|
|
|
|
|
indices = collect(HYPRE_BigInt, ilower_src_part:iupper_src_part) |
|
|
|
|
|
|
|
# TODO: Safe to use vv here? Owned values are always first? |
|
|
|
|
|
|
|
@check HYPRE_IJVectorSetValues(dst.ijvector, nvalues, indices, vv) |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
# TODO: It shouldn't be necessary to assemble here since we only set owned rows (?) |
|
|
|
|
|
|
|
# @check HYPRE_IJVectorAssemble(dst.ijvector) |
|
|
|
function finish_assemble!(A::HYPREAssembler) |
|
|
|
# TODO: Necessary to recreate the ParVector? Running some examples it seems like it is |
|
|
|
return finish_assemble!(A.A), finish_assemble!(A.b) |
|
|
|
# not needed. |
|
|
|
|
|
|
|
return dst |
|
|
|
|
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
# Solver interface |
|
|
|
|
|
|
|
|
|
|
|
###################### |
|
|
|
|
|
|
|
## Solver interface ## |
|
|
|
|
|
|
|
###################### |
|
|
|
|
|
|
|
|
|
|
|
include("solvers.jl") |
|
|
|
include("solvers.jl") |
|
|
|
include("solver_options.jl") |
|
|
|
include("solver_options.jl") |
|
|
|
|
|
|
|
|
|
|
|
|