mirror of https://github.com/fredrikekre/HYPRE.jl
38 changed files with 2937 additions and 1833 deletions
@ -0,0 +1,6 @@ |
|||||||
|
# Runic formatting |
||||||
|
# https://github.com/fredrikekre/HYPRE.jl/commit/640d77944e846a1f94e248bf2dea53310314f457 |
||||||
|
640d77944e846a1f94e248bf2dea53310314f457 |
||||||
|
# Switch from ccall() to @ccall in generated output |
||||||
|
# https://github.com/fredrikekre/HYPRE.jl/commit/b4790048a7803298004bde24658ac90215a837a4 |
||||||
|
b4790048a7803298004bde24658ac90215a837a4 |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates |
||||||
|
version: 2 |
||||||
|
updates: |
||||||
|
- package-ecosystem: "github-actions" |
||||||
|
directory: "/" # Location of package manifests |
||||||
|
schedule: |
||||||
|
interval: "monthly" |
||||||
@ -0,0 +1,73 @@ |
|||||||
|
name: Code checks |
||||||
|
|
||||||
|
on: |
||||||
|
pull_request: |
||||||
|
push: |
||||||
|
branches: ["master"] |
||||||
|
|
||||||
|
jobs: |
||||||
|
|
||||||
|
pre-commit: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v4 |
||||||
|
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 |
||||||
|
|
||||||
|
explicit-imports: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
name: "ExplicitImports.jl" |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v4 |
||||||
|
# - uses: julia-actions/setup-julia@v2 |
||||||
|
# with: |
||||||
|
# version: '1' |
||||||
|
- uses: julia-actions/cache@v2 |
||||||
|
# - uses: julia-actions/julia-buildpkg@v1 |
||||||
|
- name: Install dependencies |
||||||
|
shell: julia --project=@explicit-imports {0} |
||||||
|
run: | |
||||||
|
# Add ExplicitImports.jl and packages that HYPRE has extensions for |
||||||
|
using Pkg |
||||||
|
Pkg.develop([ |
||||||
|
PackageSpec(name = "HYPRE", path = pwd()), |
||||||
|
]) |
||||||
|
Pkg.add([ |
||||||
|
PackageSpec(name = "ExplicitImports", version = "1.9"), |
||||||
|
PackageSpec(name = "PartitionedArrays"), |
||||||
|
PackageSpec(name = "SparseArrays"), |
||||||
|
PackageSpec(name = "SparseMatricesCSR"), |
||||||
|
]) |
||||||
|
- name: ExplicitImports.jl code checks |
||||||
|
shell: julia --project=@explicit-imports {0} |
||||||
|
run: | |
||||||
|
using HYPRE, ExplicitImports, PartitionedArrays, SparseArrays, SparseMatricesCSR |
||||||
|
# Check HYPRE |
||||||
|
check_no_implicit_imports(HYPRE) |
||||||
|
check_no_stale_explicit_imports(HYPRE) |
||||||
|
check_all_qualified_accesses_via_owners(HYPRE) |
||||||
|
check_no_self_qualified_accesses(HYPRE) |
||||||
|
# Check extension modules |
||||||
|
for ext in (:HYPREPartitionedArrays, :HYPRESparseArrays, :HYPRESparseMatricesCSR) |
||||||
|
extmod = Base.get_extension(HYPRE, ext) |
||||||
|
if extmod !== nothing |
||||||
|
check_no_implicit_imports(extmod) |
||||||
|
check_no_stale_explicit_imports(extmod) |
||||||
|
check_all_qualified_accesses_via_owners(extmod) |
||||||
|
check_no_self_qualified_accesses(extmod) |
||||||
|
else |
||||||
|
@warn "$(ext) extension not available." |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
runic: |
||||||
|
name: Runic |
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v4 |
||||||
|
- uses: julia-actions/setup-julia@v2 |
||||||
|
with: |
||||||
|
version: '1' |
||||||
|
- uses: julia-actions/cache@v2 |
||||||
|
- uses: fredrikekre/runic-action@v1 |
||||||
|
with: |
||||||
|
version: '1' |
||||||
@ -0,0 +1,27 @@ |
|||||||
|
--- |
||||||
|
name: Documentation |
||||||
|
on: |
||||||
|
push: |
||||||
|
branches: |
||||||
|
- 'master' |
||||||
|
- 'release-' |
||||||
|
tags: ['*'] |
||||||
|
pull_request: |
||||||
|
|
||||||
|
jobs: |
||||||
|
docs: |
||||||
|
name: Julia 1.11 - ubuntu-latest |
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v4 |
||||||
|
- uses: julia-actions/setup-julia@v2 |
||||||
|
with: |
||||||
|
version: '1.11' |
||||||
|
- uses: julia-actions/cache@v2 |
||||||
|
- name: Install dependencies |
||||||
|
run: julia --project=docs -e 'using Pkg; Pkg.instantiate()' |
||||||
|
- name: Build and deploy |
||||||
|
env: |
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
||||||
|
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} |
||||||
|
run: julia --project=docs --color=yes docs/make.jl |
||||||
@ -0,0 +1,41 @@ |
|||||||
|
name: Test |
||||||
|
|
||||||
|
on: |
||||||
|
push: |
||||||
|
branches: |
||||||
|
- 'master' |
||||||
|
- 'release-' |
||||||
|
tags: ['*'] |
||||||
|
pull_request: |
||||||
|
|
||||||
|
jobs: |
||||||
|
test: |
||||||
|
name: Julia ${{ matrix.version }} - ${{ matrix.os }} |
||||||
|
runs-on: ${{ matrix.os }} |
||||||
|
strategy: |
||||||
|
matrix: |
||||||
|
version: |
||||||
|
- '1.10' |
||||||
|
- '1' |
||||||
|
- 'nightly' |
||||||
|
os: |
||||||
|
- ubuntu-latest |
||||||
|
include: |
||||||
|
- os: windows-latest |
||||||
|
version: '1' |
||||||
|
- os: macOS-latest |
||||||
|
version: '1' |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v4 |
||||||
|
- uses: julia-actions/setup-julia@v2 |
||||||
|
with: |
||||||
|
version: ${{ matrix.version }} |
||||||
|
- uses: julia-actions/cache@v2 |
||||||
|
- uses: julia-actions/julia-buildpkg@v1 |
||||||
|
- uses: julia-actions/julia-runtest@v1 |
||||||
|
- uses: julia-actions/julia-processcoverage@v1 |
||||||
|
- uses: codecov/codecov-action@v5 |
||||||
|
with: |
||||||
|
files: lcov.info |
||||||
|
env: |
||||||
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} |
||||||
@ -1,55 +0,0 @@ |
|||||||
name: CI |
|
||||||
|
|
||||||
on: |
|
||||||
push: |
|
||||||
branches: |
|
||||||
- 'master' |
|
||||||
- 'release-' |
|
||||||
tags: '*' |
|
||||||
pull_request: |
|
||||||
|
|
||||||
jobs: |
|
||||||
test: |
|
||||||
name: Julia ${{ matrix.version }} - ${{ matrix.os }} |
|
||||||
runs-on: ${{ matrix.os }} |
|
||||||
strategy: |
|
||||||
matrix: |
|
||||||
version: |
|
||||||
- '1.6' |
|
||||||
- '1' |
|
||||||
- 'nightly' |
|
||||||
os: |
|
||||||
- ubuntu-latest |
|
||||||
include: |
|
||||||
- os: windows-latest |
|
||||||
version: '1' |
|
||||||
- os: macOS-latest |
|
||||||
version: '1' |
|
||||||
steps: |
|
||||||
- uses: actions/checkout@v2 |
|
||||||
- uses: julia-actions/setup-julia@v1 |
|
||||||
with: |
|
||||||
version: ${{ matrix.version }} |
|
||||||
- uses: julia-actions/cache@v1 |
|
||||||
- uses: julia-actions/julia-buildpkg@v1 |
|
||||||
- uses: julia-actions/julia-runtest@v1 |
|
||||||
- uses: julia-actions/julia-processcoverage@v1 |
|
||||||
- uses: codecov/codecov-action@v2 |
|
||||||
with: |
|
||||||
files: ./lcov.info |
|
||||||
docs: |
|
||||||
name: Documentation |
|
||||||
runs-on: ubuntu-latest |
|
||||||
steps: |
|
||||||
- uses: actions/checkout@v2 |
|
||||||
- uses: julia-actions/setup-julia@v1 |
|
||||||
with: |
|
||||||
version: '1' |
|
||||||
- uses: julia-actions/cache@v1 |
|
||||||
- name: Install dependencies |
|
||||||
run: julia --project=docs -e 'using Pkg; Pkg.instantiate()' |
|
||||||
- name: Build and deploy |
|
||||||
env: |
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
|
||||||
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} |
|
||||||
run: julia --project=docs --color=yes docs/make.jl |
|
||||||
@ -0,0 +1,11 @@ |
|||||||
|
repos: |
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks |
||||||
|
rev: v3.2.0 |
||||||
|
hooks: |
||||||
|
- id: check-added-large-files |
||||||
|
- id: check-case-conflict |
||||||
|
- id: check-toml |
||||||
|
- id: check-yaml |
||||||
|
- id: end-of-file-fixer |
||||||
|
- id: mixed-line-ending |
||||||
|
- id: trailing-whitespace |
||||||
@ -0,0 +1,112 @@ |
|||||||
|
# HYPRE.jl changelog |
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file. |
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), |
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
||||||
|
|
||||||
|
## [v1.7.0] - 2024-10-09 |
||||||
|
### Changed |
||||||
|
- Support for Julia 1.6 have been dropped and for this and future releases Julia 1.10 or |
||||||
|
later will be required. ([#27]) |
||||||
|
- Constant struct fields of `HYPREMatrix` and `HYPREVector` are now marked with `const`. |
||||||
|
([#28]) |
||||||
|
|
||||||
|
## [v1.6.0] - 2024-09-29 |
||||||
|
### Changed |
||||||
|
- PartitionedArrays.jl dependency upgraded from release series 0.3.x to release series |
||||||
|
0.5.x. ([#17], [#18]) |
||||||
|
- CEnum.jl dependency upgraded to release series 0.5.x (release series 0.4.x still |
||||||
|
allowed). ([#17], [#18]) |
||||||
|
- PartitionedArrays.jl support (`PSparseMatrix`, `PVector`) is now provided by a package |
||||||
|
extension. ([#23]) |
||||||
|
- SparseMatricesCSR.jl support (`SparseMatrixCSR`) is now provided by a package extension. |
||||||
|
([#24]) |
||||||
|
- SparseArrays.jl support (`SparseMatrixCSC`) is now provided by a package extension. |
||||||
|
([#25]) |
||||||
|
|
||||||
|
## [v1.5.0] - 2023-05-26 |
||||||
|
### Changed |
||||||
|
- PartitionedArrays.jl dependency upgraded from version 0.2.x to version 0.3.x. |
||||||
|
([#16]) |
||||||
|
|
||||||
|
## [v1.4.0] - 2023-01-20 |
||||||
|
### Added |
||||||
|
- New function `HYPRE.GetFinalRelativeResidualNorm(s::HYPRESolver)` for getting the final |
||||||
|
residual norm from a solver. This function dispatches on the solver to the corresponding |
||||||
|
C API wrapper `LibHYPRE.HYPRE_${Solver}GetFinalRelativeResidualNorm`. ([#14]) |
||||||
|
- New function `HYPRE.GetNumIterations(s::HYPRESolver)` for getting the number of |
||||||
|
iterations from a solver. This function dispatches on the solver to the corresponding C |
||||||
|
API wrapper `LibHYPRE.HYPRE_${Solver}GetNumIterations`. ([#14]) |
||||||
|
|
||||||
|
## [v1.3.1] - 2023-01-14 |
||||||
|
### Fixed |
||||||
|
- Solvers now keep an reference to the added preconditioner to make sure the preconditioner |
||||||
|
is not finalized before the solver. This fixes crashes (segfaults) that could happen in |
||||||
|
case no other reference to the preconditioner existed in the program. ([#12]) |
||||||
|
- The proper conversion methods for `ccall` are now defined for `HYPREMatrix`, |
||||||
|
`HYPREVector`, and `HYPRESolver` such that they can be passed direcly to `HYPRE_*` |
||||||
|
functions and let `ccall` guarantee the GC preservation of these objects. Although not |
||||||
|
observed in practice, this fixes a possible race condition where the matrix/vector/solver |
||||||
|
could be finalized too early. ([#13]) |
||||||
|
|
||||||
|
## [v1.3.0] - 2022-12-30 |
||||||
|
### Added |
||||||
|
- Rectangular matrices can now be assembled by the new method |
||||||
|
`HYPRE.assemble!(::HYPREMatrixAssembler, i::Vector, j::Vector, a::Matrix)` where `i` are |
||||||
|
the rows and `j` the columns. ([#7]) |
||||||
|
### Fixed |
||||||
|
- All created HYPRE objects (`HYPREMatrix`, `HYPREVector`, and `HYPRESolver`s) are now kept |
||||||
|
track of internally and explicitly `finalize`d (if they haven't been GC'd) before |
||||||
|
finalizing HYPRE. This fixes a "race condition" where MPI and/or HYPRE would finalize |
||||||
|
before these Julia objects are garbage collected and finalized. ([#8]) |
||||||
|
### Deprecated |
||||||
|
- The method `HYPRE.assemble!(A::HYPREMatrixAssembler, ij::Vector, a::Matrix)` have been |
||||||
|
deprecated in favor of `HYPRE.assemble!(A::HYPREMatrixAssembler, i::Vector, j::Vector, |
||||||
|
a::Matrix)`, i.e. it is now required to explicitly pass rows and column indices |
||||||
|
individually. The motivation behind this is to support assembling of rectangular |
||||||
|
matrices. Note that `HYPRE.assemble!(A::HYPREAssembler, ij::Vector, a::Matrix, |
||||||
|
b::Vector)` is still supported, where `ij` are used as row and column indices for `a`, as |
||||||
|
well as row indices for `b`. ([#6]) |
||||||
|
|
||||||
|
## [v1.2.0] - 2022-10-12 |
||||||
|
### Added |
||||||
|
- Added assembler interface to assemble `HYPREMatrix` and/or `HYPREVector` directly without |
||||||
|
an intermediate sparse structure in Julia. ([#5]) |
||||||
|
|
||||||
|
## [v1.1.0] - 2022-10-05 |
||||||
|
### Added |
||||||
|
- Added support for MPI.jl version 0.20.x (in addition to the existing version 0.19.x |
||||||
|
support). ([#2]) |
||||||
|
|
||||||
|
## [v1.0.0] - 2022-07-28 |
||||||
|
Initial release of HYPRE.jl. |
||||||
|
|
||||||
|
|
||||||
|
<!-- Links generated by Changelog.jl --> |
||||||
|
|
||||||
|
[v1.0.0]: https://github.com/fredrikekre/HYPRE.jl/releases/tag/v1.0.0 |
||||||
|
[v1.1.0]: https://github.com/fredrikekre/HYPRE.jl/releases/tag/v1.1.0 |
||||||
|
[v1.2.0]: https://github.com/fredrikekre/HYPRE.jl/releases/tag/v1.2.0 |
||||||
|
[v1.3.0]: https://github.com/fredrikekre/HYPRE.jl/releases/tag/v1.3.0 |
||||||
|
[v1.3.1]: https://github.com/fredrikekre/HYPRE.jl/releases/tag/v1.3.1 |
||||||
|
[v1.4.0]: https://github.com/fredrikekre/HYPRE.jl/releases/tag/v1.4.0 |
||||||
|
[v1.5.0]: https://github.com/fredrikekre/HYPRE.jl/releases/tag/v1.5.0 |
||||||
|
[v1.6.0]: https://github.com/fredrikekre/HYPRE.jl/releases/tag/v1.6.0 |
||||||
|
[v1.7.0]: https://github.com/fredrikekre/HYPRE.jl/releases/tag/v1.7.0 |
||||||
|
[#2]: https://github.com/fredrikekre/HYPRE.jl/issues/2 |
||||||
|
[#5]: https://github.com/fredrikekre/HYPRE.jl/issues/5 |
||||||
|
[#6]: https://github.com/fredrikekre/HYPRE.jl/issues/6 |
||||||
|
[#7]: https://github.com/fredrikekre/HYPRE.jl/issues/7 |
||||||
|
[#8]: https://github.com/fredrikekre/HYPRE.jl/issues/8 |
||||||
|
[#12]: https://github.com/fredrikekre/HYPRE.jl/issues/12 |
||||||
|
[#13]: https://github.com/fredrikekre/HYPRE.jl/issues/13 |
||||||
|
[#14]: https://github.com/fredrikekre/HYPRE.jl/issues/14 |
||||||
|
[#16]: https://github.com/fredrikekre/HYPRE.jl/issues/16 |
||||||
|
[#17]: https://github.com/fredrikekre/HYPRE.jl/issues/17 |
||||||
|
[#18]: https://github.com/fredrikekre/HYPRE.jl/issues/18 |
||||||
|
[#23]: https://github.com/fredrikekre/HYPRE.jl/issues/23 |
||||||
|
[#24]: https://github.com/fredrikekre/HYPRE.jl/issues/24 |
||||||
|
[#25]: https://github.com/fredrikekre/HYPRE.jl/issues/25 |
||||||
|
[#27]: https://github.com/fredrikekre/HYPRE.jl/issues/27 |
||||||
|
[#28]: https://github.com/fredrikekre/HYPRE.jl/issues/28 |
||||||
@ -1,11 +1,8 @@ |
|||||||
SRCDIR:=$(shell dirname $(abspath $(firstword $(MAKEFILE_LIST)))) |
SRCDIR:=$(shell dirname $(abspath $(firstword $(MAKEFILE_LIST)))) |
||||||
|
|
||||||
default: livedocs |
default: liveserver |
||||||
|
|
||||||
instantiate: |
liveserver: |
||||||
julia --project=${SRCDIR} -e 'using Pkg; Pkg.instantiate()' |
julia --project=${SRCDIR} ${SRCDIR}/liveserver.jl |
||||||
|
|
||||||
livedocs: instantiate |
.PHONY: default liveserver |
||||||
julia --project=${SRCDIR} -e 'using LiveServer; LiveServer.servedocs(; foldername=pwd())' -- liveserver |
|
||||||
|
|
||||||
.PHONY: default instantiate livedocs |
|
||||||
|
|||||||
@ -1,3 +1,4 @@ |
|||||||
[deps] |
[deps] |
||||||
|
Changelog = "5217a498-cd5d-4ec6-b8c2-9b85a09b6e3e" |
||||||
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" |
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" |
||||||
HYPRE = "b5ffcf37-a2bd-41ab-a3da-4bd9bc8ad771" |
HYPRE = "b5ffcf37-a2bd-41ab-a3da-4bd9bc8ad771" |
||||||
|
|||||||
@ -0,0 +1,24 @@ |
|||||||
|
#!/usr/bin/env julia |
||||||
|
|
||||||
|
# Root of the repository |
||||||
|
const repo_root = dirname(@__DIR__) |
||||||
|
|
||||||
|
# Make sure docs environment is active and instantiated |
||||||
|
import Pkg |
||||||
|
Pkg.activate(@__DIR__) |
||||||
|
Pkg.instantiate() |
||||||
|
|
||||||
|
# Communicate with docs/make.jl that we are running in live mode |
||||||
|
push!(ARGS, "liveserver") |
||||||
|
|
||||||
|
# Run LiveServer.servedocs(...) |
||||||
|
import LiveServer |
||||||
|
LiveServer.servedocs(; |
||||||
|
# Documentation root where make.jl and src/ are located |
||||||
|
foldername = joinpath(repo_root, "docs"), |
||||||
|
# Extra source folder to watch for changes |
||||||
|
include_dirs = [ |
||||||
|
# Watch the src folder so docstrings can be Revise'd |
||||||
|
joinpath(repo_root, "src"), |
||||||
|
], |
||||||
|
) |
||||||
@ -0,0 +1,300 @@ |
|||||||
|
module HYPREPartitionedArrays |
||||||
|
|
||||||
|
using HYPRE.LibHYPRE: @check, HYPRE_BigInt, HYPRE_Complex, HYPRE_IJMatrixSetValues, |
||||||
|
HYPRE_IJVectorGetValues, HYPRE_IJVectorInitialize, HYPRE_IJVectorSetValues, HYPRE_Int |
||||||
|
using HYPRE: HYPRE, HYPREMatrix, HYPRESolver, HYPREVector, Internals |
||||||
|
using MPI: MPI |
||||||
|
using PartitionedArrays: PartitionedArrays, AbstractLocalIndices, MPIArray, PSparseMatrix, |
||||||
|
PVector, SplitMatrix, ghost_to_global, local_values, own_to_global, own_values, |
||||||
|
partition |
||||||
|
using SparseArrays: SparseArrays, SparseMatrixCSC, nonzeros, nzrange, rowvals |
||||||
|
using SparseMatricesCSR: SparseMatrixCSR, colvals |
||||||
|
|
||||||
|
################################################## |
||||||
|
# PartitionedArrays.PSparseMatrix -> HYPREMatrix # |
||||||
|
################################################## |
||||||
|
|
||||||
|
function Internals.to_hypre_data( |
||||||
|
A::SplitMatrix{<:SparseMatrixCSC}, r::AbstractLocalIndices, c::AbstractLocalIndices |
||||||
|
) |
||||||
|
# Own/ghost to global index mappings |
||||||
|
own_to_global_row = own_to_global(r) |
||||||
|
own_to_global_col = own_to_global(c) |
||||||
|
ghost_to_global_col = ghost_to_global(c) |
||||||
|
|
||||||
|
# HYPRE requires contiguous row indices |
||||||
|
ilower = own_to_global_row[1] |
||||||
|
iupper = own_to_global_row[end] |
||||||
|
@assert iupper - ilower + 1 == length(own_to_global_row) |
||||||
|
|
||||||
|
# Extract sparse matrices from the SplitMatrix. We are only interested in the owned |
||||||
|
# rows, so only consider own-own and own-ghost blocks. |
||||||
|
Aoo = A.blocks.own_own::SparseMatrixCSC |
||||||
|
Aoo_rows = rowvals(Aoo) |
||||||
|
Aoo_vals = nonzeros(Aoo) |
||||||
|
Aog = A.blocks.own_ghost::SparseMatrixCSC |
||||||
|
Aog_rows = rowvals(Aog) |
||||||
|
Aog_vals = nonzeros(Aog) |
||||||
|
@assert size(Aoo, 1) == size(Aog, 1) == length(own_to_global_row) |
||||||
|
|
||||||
|
# Initialize the data buffers HYPRE wants |
||||||
|
nrows = HYPRE_Int(length(own_to_global_row)) # 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 global column indices and column |
||||||
|
# permutation doesn't matter for this pass) |
||||||
|
@inbounds for own_col in 1:size(Aoo, 2) |
||||||
|
for k in nzrange(Aoo, own_col) |
||||||
|
own_row = Aoo_rows[k] |
||||||
|
ncols[own_row] += 1 |
||||||
|
end |
||||||
|
end |
||||||
|
@inbounds for ghost_col in 1:size(Aog, 2) |
||||||
|
for k in nzrange(Aog, ghost_col) |
||||||
|
own_row = Aog_rows[k] |
||||||
|
ncols[own_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 map column |
||||||
|
# indices from own/ghost to global |
||||||
|
@inbounds for own_col in 1:size(Aoo, 2) |
||||||
|
for k in nzrange(Aoo, own_col) |
||||||
|
own_row = Aoo_rows[k] |
||||||
|
i = lastinds[own_row] += 1 |
||||||
|
values[i] = Aoo_vals[k] |
||||||
|
cols[i] = own_to_global_col[own_col] |
||||||
|
end |
||||||
|
end |
||||||
|
@inbounds for ghost_col in 1:size(Aog, 2) |
||||||
|
for k in nzrange(Aog, ghost_col) |
||||||
|
own_row = Aog_rows[k] |
||||||
|
i = lastinds[own_row] += 1 |
||||||
|
values[i] = Aog_vals[k] |
||||||
|
cols[i] = ghost_to_global_col[ghost_col] |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
# Sanity checks and return |
||||||
|
@assert nrows == length(ncols) == length(rows) |
||||||
|
return nrows, ncols, rows, cols, values |
||||||
|
end |
||||||
|
|
||||||
|
function Internals.to_hypre_data( |
||||||
|
A::SplitMatrix{<:SparseMatrixCSR}, r::AbstractLocalIndices, c::AbstractLocalIndices |
||||||
|
) |
||||||
|
# Own/ghost to global index mappings |
||||||
|
own_to_global_row = own_to_global(r) |
||||||
|
own_to_global_col = own_to_global(c) |
||||||
|
ghost_to_global_col = ghost_to_global(c) |
||||||
|
|
||||||
|
# HYPRE requires contiguous row indices |
||||||
|
ilower = own_to_global_row[1] |
||||||
|
iupper = own_to_global_row[end] |
||||||
|
@assert iupper - ilower + 1 == length(own_to_global_row) |
||||||
|
|
||||||
|
# Extract sparse matrices from the SplitMatrix. We are only interested in the owned |
||||||
|
# rows, so only consider own-own and own-ghost blocks. |
||||||
|
Aoo = A.blocks.own_own::SparseMatrixCSR |
||||||
|
Aoo_cols = colvals(Aoo) |
||||||
|
Aoo_vals = nonzeros(Aoo) |
||||||
|
Aog = A.blocks.own_ghost::SparseMatrixCSR |
||||||
|
Aog_cols = colvals(Aog) |
||||||
|
Aog_vals = nonzeros(Aog) |
||||||
|
@assert size(Aoo, 1) == size(Aog, 1) == length(own_to_global_row) |
||||||
|
|
||||||
|
# Initialize the data buffers HYPRE wants |
||||||
|
nnz = SparseArrays.nnz(Aoo) + SparseArrays.nnz(Aog) |
||||||
|
nrows = HYPRE_Int(iupper - ilower + 1) # Total number of rows |
||||||
|
ncols = zeros(HYPRE_Int, nrows) # Number of columns 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 |
||||||
|
|
||||||
|
# For CSR we only need a single pass to over the owned rows to collect everything |
||||||
|
i = 0 |
||||||
|
for own_row in 1:size(Aoo, 1) |
||||||
|
nzro = nzrange(Aoo, own_row) |
||||||
|
nzrg = nzrange(Aog, own_row) |
||||||
|
ncols[own_row] = length(nzro) + length(nzrg) |
||||||
|
for k in nzro |
||||||
|
i += 1 |
||||||
|
own_col = Aoo_cols[k] |
||||||
|
cols[i] = own_to_global_col[own_col] |
||||||
|
values[i] = Aoo_vals[k] |
||||||
|
end |
||||||
|
for k in nzrg |
||||||
|
i += 1 |
||||||
|
ghost_col = Aog_cols[k] |
||||||
|
cols[i] = ghost_to_global_col[ghost_col] |
||||||
|
values[i] = Aog_vals[k] |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
# Sanity checks and return |
||||||
|
@assert nnz == i |
||||||
|
@assert nrows == length(ncols) == length(rows) |
||||||
|
return nrows, ncols, rows, cols, values |
||||||
|
end |
||||||
|
|
||||||
|
function Internals.get_comm(A::Union{PSparseMatrix{<:Any, <:M}, PVector{<:Any, <:M}}) where {M <: MPIArray} |
||||||
|
return partition(A).comm |
||||||
|
end |
||||||
|
|
||||||
|
Internals.get_comm(_::Union{PSparseMatrix, PVector}) = MPI.COMM_SELF |
||||||
|
|
||||||
|
function Internals.get_proc_rows(A::Union{PSparseMatrix, PVector}) |
||||||
|
ilower::HYPRE_BigInt = typemax(HYPRE_BigInt) |
||||||
|
iupper::HYPRE_BigInt = typemin(HYPRE_BigInt) |
||||||
|
map(partition(axes(A, 1))) do a |
||||||
|
# This is a map over the local process' owned indices. For MPI it will |
||||||
|
# be a single value but for DebugArray / Array it will have multiple |
||||||
|
# values. |
||||||
|
o_to_g = own_to_global(a) |
||||||
|
ilower_part = o_to_g[1] |
||||||
|
iupper_part = o_to_g[end] |
||||||
|
ilower = min(ilower, convert(HYPRE_BigInt, ilower_part)) |
||||||
|
iupper = max(iupper, convert(HYPRE_BigInt, iupper_part)) |
||||||
|
end |
||||||
|
return ilower, iupper |
||||||
|
end |
||||||
|
|
||||||
|
function HYPRE.HYPREMatrix(B::PSparseMatrix) |
||||||
|
# Use the same communicator as the matrix |
||||||
|
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(local_values(B), partition(axes(B, 1)), partition(axes(B, 2))) do Bv, Br, Bc |
||||||
|
nrows, ncols, rows, cols, values = Internals.to_hypre_data(Bv, Br, Bc) |
||||||
|
@check HYPRE_IJMatrixSetValues(A, nrows, ncols, rows, cols, values) |
||||||
|
return nothing |
||||||
|
end |
||||||
|
# Finalize |
||||||
|
Internals.assemble_matrix(A) |
||||||
|
return A |
||||||
|
end |
||||||
|
|
||||||
|
############################################ |
||||||
|
# PartitionedArrays.PVector -> HYPREVector # |
||||||
|
############################################ |
||||||
|
|
||||||
|
function HYPRE.HYPREVector(v::PVector) |
||||||
|
# Use the same communicator as the matrix |
||||||
|
comm = Internals.get_comm(v) |
||||||
|
# Fetch rows owned by this process |
||||||
|
ilower, iupper = Internals.get_proc_rows(v) |
||||||
|
# Create the IJ vector |
||||||
|
b = HYPREVector(comm, ilower, iupper) |
||||||
|
# Set all the values |
||||||
|
map(own_values(v), partition(axes(v, 1))) do vo, vr |
||||||
|
o_to_g = own_to_global(vr) |
||||||
|
|
||||||
|
ilower_part = o_to_g[1] |
||||||
|
iupper_part = o_to_g[end] |
||||||
|
|
||||||
|
# Option 1: Set all values |
||||||
|
nvalues = HYPRE_Int(iupper_part - ilower_part + 1) |
||||||
|
indices = collect(HYPRE_BigInt, ilower_part:iupper_part) |
||||||
|
# TODO: Could probably just pass the full vector even if it is too long |
||||||
|
# values = convert(Vector{HYPRE_Complex}, vv) |
||||||
|
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, nvalues, indices, values) |
||||||
|
return nothing |
||||||
|
end |
||||||
|
# Finalize |
||||||
|
Internals.assemble_vector(b) |
||||||
|
return b |
||||||
|
end |
||||||
|
|
||||||
|
function copy_check(dst::HYPREVector, src::PVector) |
||||||
|
il_dst, iu_dst = Internals.get_proc_rows(dst) |
||||||
|
il_src, iu_src = Internals.get_proc_rows(src) |
||||||
|
if il_dst != il_src && iu_dst != iu_src |
||||||
|
# TODO: Why require this? |
||||||
|
msg = "row owner mismatch between dst ($(il_dst:iu_dst)) and src ($(il_src:iu_src))" |
||||||
|
throw(ArgumentError(msg)) |
||||||
|
end |
||||||
|
return |
||||||
|
end |
||||||
|
|
||||||
|
# TODO: Other eltypes could be support by using a intermediate buffer |
||||||
|
function Base.copy!(dst::PVector{<:AbstractVector{HYPRE_Complex}}, src::HYPREVector) |
||||||
|
copy_check(src, dst) |
||||||
|
map(own_values(dst), partition(axes(dst, 1))) do ov, vr |
||||||
|
o_to_g = own_to_global(vr) |
||||||
|
il_src_part = o_to_g[1] |
||||||
|
iu_src_part = o_to_g[end] |
||||||
|
nvalues = HYPRE_Int(iu_src_part - il_src_part + 1) |
||||||
|
indices = collect(HYPRE_BigInt, il_src_part:iu_src_part) |
||||||
|
values = ov |
||||||
|
@check HYPRE_IJVectorGetValues(src, nvalues, indices, values) |
||||||
|
end |
||||||
|
return dst |
||||||
|
end |
||||||
|
|
||||||
|
function Base.copy!(dst::HYPREVector, src::PVector{<:AbstractVector{HYPRE_Complex}}) |
||||||
|
copy_check(dst, src) |
||||||
|
# Re-initialize the vector |
||||||
|
@check HYPRE_IJVectorInitialize(dst) |
||||||
|
map(own_values(src), partition(axes(src, 1))) do ov, vr |
||||||
|
o_to_g = own_to_global(vr) |
||||||
|
ilower_src_part = o_to_g[1] |
||||||
|
iupper_src_part = o_to_g[end] |
||||||
|
nvalues = HYPRE_Int(iupper_src_part - ilower_src_part + 1) |
||||||
|
indices = collect(HYPRE_BigInt, ilower_src_part:iupper_src_part) |
||||||
|
values = ov |
||||||
|
@check HYPRE_IJVectorSetValues(dst, nvalues, indices, values) |
||||||
|
end |
||||||
|
# TODO: It shouldn't be necessary to assemble here since we only set owned rows (?) |
||||||
|
# @check HYPRE_IJVectorAssemble(dst) |
||||||
|
# TODO: Necessary to recreate the ParVector? Running some examples it seems like it is |
||||||
|
# not needed. |
||||||
|
return dst |
||||||
|
end |
||||||
|
|
||||||
|
###################################### |
||||||
|
# PartitionedArrays solver interface # |
||||||
|
###################################### |
||||||
|
|
||||||
|
# TODO: Would it be useful with a method that copied the solution to b instead? |
||||||
|
|
||||||
|
function HYPRE.solve(solver::HYPRESolver, A::PSparseMatrix, b::PVector) |
||||||
|
hypre_x = HYPRE.solve(solver, HYPREMatrix(A), HYPREVector(b)) |
||||||
|
x = copy!(similar(b, HYPRE_Complex), hypre_x) |
||||||
|
return x |
||||||
|
end |
||||||
|
function HYPRE.solve!(solver::HYPRESolver, x::PVector, A::PSparseMatrix, b::PVector) |
||||||
|
hypre_x = HYPREVector(x) |
||||||
|
HYPRE.solve!(solver, hypre_x, HYPREMatrix(A), HYPREVector(b)) |
||||||
|
copy!(x, hypre_x) |
||||||
|
return x |
||||||
|
end |
||||||
|
|
||||||
|
end # module HYPREPartitionedArrays |
||||||
@ -0,0 +1,86 @@ |
|||||||
|
module HYPRESparseArrays |
||||||
|
|
||||||
|
using HYPRE.LibHYPRE: @check, HYPRE_BigInt, HYPRE_Complex, HYPRE_Int |
||||||
|
using HYPRE: |
||||||
|
HYPRE, HYPREMatrix, HYPRESolver, HYPREVector, HYPRE_IJMatrixSetValues, Internals |
||||||
|
using MPI: MPI |
||||||
|
using SparseArrays: SparseArrays, SparseMatrixCSC, nonzeros, nzrange, rowvals |
||||||
|
|
||||||
|
################################## |
||||||
|
# SparseMatrixCSC -> HYPREMatrix # |
||||||
|
################################## |
||||||
|
|
||||||
|
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 |
||||||
|
@assert nrows == length(ncols) == length(rows) |
||||||
|
return nrows, ncols, rows, cols, values |
||||||
|
end |
||||||
|
|
||||||
|
# Note: keep in sync with the SparseMatrixCSR method |
||||||
|
function HYPRE.HYPREMatrix(comm::MPI.Comm, B::SparseMatrixCSC, ilower, iupper) |
||||||
|
A = HYPREMatrix(comm, ilower, iupper) |
||||||
|
nrows, ncols, rows, cols, values = Internals.to_hypre_data(B, ilower, iupper) |
||||||
|
@check HYPRE_IJMatrixSetValues(A, nrows, ncols, rows, cols, values) |
||||||
|
Internals.assemble_matrix(A) |
||||||
|
return A |
||||||
|
end |
||||||
|
|
||||||
|
# Note: keep in sync with the SparseMatrixCSC method |
||||||
|
function HYPRE.HYPREMatrix(B::SparseMatrixCSC, ilower = 1, iupper = size(B, 1)) |
||||||
|
return HYPREMatrix(MPI.COMM_SELF, B, ilower, iupper) |
||||||
|
end |
||||||
|
|
||||||
|
|
||||||
|
#################################### |
||||||
|
# SparseMatrixCSC solver interface # |
||||||
|
#################################### |
||||||
|
|
||||||
|
# Note: keep in sync with the SparseMatrixCSR method |
||||||
|
function HYPRE.solve(solver::HYPRESolver, A::SparseMatrixCSC, b::Vector) |
||||||
|
hypre_x = HYPRE.solve(solver, HYPREMatrix(A), HYPREVector(b)) |
||||||
|
x = copy!(similar(b, HYPRE_Complex), hypre_x) |
||||||
|
return x |
||||||
|
end |
||||||
|
|
||||||
|
# Note: keep in sync with the SparseMatrixCSR method |
||||||
|
function HYPRE.solve!(solver::HYPRESolver, x::Vector, A::SparseMatrixCSC, b::Vector) |
||||||
|
hypre_x = HYPREVector(x) |
||||||
|
HYPRE.solve!(solver, hypre_x, HYPREMatrix(A), HYPREVector(b)) |
||||||
|
copy!(x, hypre_x) |
||||||
|
return x |
||||||
|
end |
||||||
|
|
||||||
|
end # module HYPRESparseMatricesCSR |
||||||
@ -0,0 +1,80 @@ |
|||||||
|
module HYPRESparseMatricesCSR |
||||||
|
|
||||||
|
using HYPRE.LibHYPRE: @check, HYPRE_BigInt, HYPRE_Complex, HYPRE_Int |
||||||
|
using HYPRE: HYPRE, HYPREMatrix, HYPRESolver, HYPREVector, HYPRE_IJMatrixSetValues, Internals |
||||||
|
using MPI: MPI |
||||||
|
using SparseArrays: SparseArrays, nonzeros, nzrange |
||||||
|
using SparseMatricesCSR: SparseMatrixCSR, colvals |
||||||
|
|
||||||
|
|
||||||
|
################################## |
||||||
|
# SparseMatrixCSR -> HYPREMatrix # |
||||||
|
################################## |
||||||
|
|
||||||
|
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 |
||||||
|
@assert nrows == length(ncols) == length(rows) |
||||||
|
return nrows, ncols, rows, cols, values |
||||||
|
end |
||||||
|
|
||||||
|
|
||||||
|
# Note: keep in sync with the SparseMatrixCSC method |
||||||
|
function HYPRE.HYPREMatrix(comm::MPI.Comm, B::SparseMatrixCSR, ilower, iupper) |
||||||
|
A = HYPREMatrix(comm, ilower, iupper) |
||||||
|
nrows, ncols, rows, cols, values = Internals.to_hypre_data(B, ilower, iupper) |
||||||
|
@check HYPRE_IJMatrixSetValues(A, nrows, ncols, rows, cols, values) |
||||||
|
Internals.assemble_matrix(A) |
||||||
|
return A |
||||||
|
end |
||||||
|
|
||||||
|
# Note: keep in sync with the SparseMatrixCSC method |
||||||
|
function HYPRE.HYPREMatrix(B::SparseMatrixCSR, ilower = 1, iupper = size(B, 1)) |
||||||
|
return HYPREMatrix(MPI.COMM_SELF, B, ilower, iupper) |
||||||
|
end |
||||||
|
|
||||||
|
|
||||||
|
#################################### |
||||||
|
# SparseMatrixCSR solver interface # |
||||||
|
#################################### |
||||||
|
|
||||||
|
# Note: keep in sync with the SparseMatrixCSC method |
||||||
|
function HYPRE.solve(solver::HYPRESolver, A::SparseMatrixCSR, b::Vector) |
||||||
|
hypre_x = HYPRE.solve(solver, HYPREMatrix(A), HYPREVector(b)) |
||||||
|
x = copy!(similar(b, HYPRE_Complex), hypre_x) |
||||||
|
return x |
||||||
|
end |
||||||
|
|
||||||
|
# Note: keep in sync with the SparseMatrixCSC method |
||||||
|
function HYPRE.solve!(solver::HYPRESolver, x::Vector, A::SparseMatrixCSR, b::Vector) |
||||||
|
hypre_x = HYPREVector(x) |
||||||
|
HYPRE.solve!(solver, hypre_x, HYPREMatrix(A), HYPREVector(b)) |
||||||
|
copy!(x, hypre_x) |
||||||
|
return x |
||||||
|
end |
||||||
|
|
||||||
|
end # module HYPRESparseMatricesCSR |
||||||
@ -1,2 +1,14 @@ |
|||||||
default: |
MAKEDIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) |
||||||
julia --project generator.jl |
LIBHYPRE:=$(shell dirname $(MAKEDIR))/lib/LibHYPRE.jl |
||||||
|
|
||||||
|
generate: $(LIBHYPRE) |
||||||
|
|
||||||
|
clean: |
||||||
|
rm -f $(LIBHYPRE) |
||||||
|
|
||||||
|
.PHONY: generate clean |
||||||
|
|
||||||
|
$(LIBHYPRE): Project.toml Manifest.toml $(MAKEDIR)/generator.toml $(MAKEDIR)/generator.jl |
||||||
|
julia --project generator.jl && \
|
||||||
|
sed -i -e '1s/^/local libHYPRE # Silence of the Langs(erver)\n\n/' -e 's/using HYPRE_jll/using HYPRE_jll: HYPRE_jll, libHYPRE/' -e 's/using CEnum/using CEnum: @cenum/' $(LIBHYPRE) && \
|
||||||
|
julia-1.11 --project=@runic -e 'using Runic; exit(Runic.main(ARGS))' -- -i $(LIBHYPRE) |
||||||
|
|||||||
@ -1,6 +1,17 @@ |
|||||||
|
########################### |
||||||
|
## Start gen/prologue.jl ## |
||||||
|
########################### |
||||||
|
|
||||||
using MPI: MPI, MPI_Comm |
using MPI: MPI, MPI_Comm |
||||||
if isdefined(MPI, :API) # MPI >= 0.20.0 |
|
||||||
|
if isdefined(MPI, :API) |
||||||
|
# MPI >= 0.20.0 |
||||||
using MPI.API: MPI_INT, MPI_DOUBLE |
using MPI.API: MPI_INT, MPI_DOUBLE |
||||||
else # MPI < 0.20.0 |
else |
||||||
|
# MPI < 0.20.0 |
||||||
using MPI: MPI_INT, MPI_DOUBLE |
using MPI: MPI_INT, MPI_DOUBLE |
||||||
end |
end |
||||||
|
|
||||||
|
######################### |
||||||
|
## End gen/prologue.jl ## |
||||||
|
######################### |
||||||
|
|||||||
@ -0,0 +1,117 @@ |
|||||||
|
# SPDX-License-Identifier: MIT |
||||||
|
|
||||||
|
using HYPRE |
||||||
|
using MPI |
||||||
|
using Test |
||||||
|
|
||||||
|
MPI.Init() |
||||||
|
HYPRE.Init() |
||||||
|
|
||||||
|
include("test_utils.jl") |
||||||
|
|
||||||
|
comm = MPI.COMM_WORLD |
||||||
|
comm_rank = MPI.Comm_rank(comm) |
||||||
|
comm_size = MPI.Comm_size(comm) |
||||||
|
|
||||||
|
if comm_size != 2 |
||||||
|
error("Must run with 2 ranks.") |
||||||
|
end |
||||||
|
|
||||||
|
if comm_rank == 0 |
||||||
|
ilower = 1 |
||||||
|
iupper = 10 |
||||||
|
N = 2:10 |
||||||
|
else |
||||||
|
ilower = 11 |
||||||
|
iupper = 20 |
||||||
|
N = 11:19 |
||||||
|
end |
||||||
|
|
||||||
|
function values_and_indices(n) |
||||||
|
idx = [n - 1, n, n + 1] |
||||||
|
a = Float64[ |
||||||
|
# runic: off |
||||||
|
n -2n -n |
||||||
|
-2n n -2n |
||||||
|
-n -2n n |
||||||
|
# runic: on |
||||||
|
] |
||||||
|
b = Float64[n, n / 2, n / 3] |
||||||
|
return idx, a, b |
||||||
|
end |
||||||
|
|
||||||
|
########################## |
||||||
|
## HYPREMatrixAssembler ## |
||||||
|
########################## |
||||||
|
|
||||||
|
# Dense local matrix |
||||||
|
|
||||||
|
A = HYPREMatrix(comm, ilower, iupper) |
||||||
|
AM = zeros(20, 20) |
||||||
|
for i in 1:2 |
||||||
|
assembler = HYPRE.start_assemble!(A) |
||||||
|
fill!(AM, 0) |
||||||
|
for n in N |
||||||
|
idx, a, _ = values_and_indices(n) |
||||||
|
HYPRE.assemble!(assembler, idx, idx, a) |
||||||
|
AM[idx, idx] += a |
||||||
|
end |
||||||
|
f = HYPRE.finish_assemble!(assembler) |
||||||
|
@test f === A |
||||||
|
MPI.Allreduce!(AM, +, comm) |
||||||
|
@test getindex_debug(A, ilower:iupper, 1:20) == AM[ilower:iupper, 1:20] |
||||||
|
MPI.Barrier(comm) |
||||||
|
end |
||||||
|
|
||||||
|
########################## |
||||||
|
## HYPREVectorAssembler ## |
||||||
|
########################## |
||||||
|
|
||||||
|
# Dense local vector |
||||||
|
|
||||||
|
b = HYPREVector(comm, ilower, iupper) |
||||||
|
bv = zeros(20) |
||||||
|
for i in 1:2 |
||||||
|
assembler = HYPRE.start_assemble!(b) |
||||||
|
fill!(bv, 0) |
||||||
|
for n in N |
||||||
|
idx, _, a = values_and_indices(n) |
||||||
|
HYPRE.assemble!(assembler, idx, a) |
||||||
|
bv[idx] += a |
||||||
|
end |
||||||
|
f = HYPRE.finish_assemble!(assembler) |
||||||
|
@test f === b |
||||||
|
MPI.Allreduce!(bv, +, comm) |
||||||
|
@test getindex_debug(b, ilower:iupper) == bv[ilower:iupper] |
||||||
|
MPI.Barrier(comm) |
||||||
|
end |
||||||
|
|
||||||
|
#################### |
||||||
|
## HYPREAssembler ## |
||||||
|
#################### |
||||||
|
|
||||||
|
# Dense local arrays |
||||||
|
|
||||||
|
A = HYPREMatrix(comm, ilower, iupper) |
||||||
|
AM = zeros(20, 20) |
||||||
|
b = HYPREVector(comm, ilower, iupper) |
||||||
|
bv = zeros(20) |
||||||
|
for i in 1:2 |
||||||
|
assembler = HYPRE.start_assemble!(A, b) |
||||||
|
fill!(AM, 0) |
||||||
|
fill!(bv, 0) |
||||||
|
for n in N |
||||||
|
idx, a, c = values_and_indices(n) |
||||||
|
HYPRE.assemble!(assembler, idx, a, c) |
||||||
|
AM[idx, idx] += a |
||||||
|
bv[idx] += c |
||||||
|
end |
||||||
|
F, f = HYPRE.finish_assemble!(assembler) |
||||||
|
@test F === A |
||||||
|
@test f === b |
||||||
|
MPI.Allreduce!(AM, +, comm) |
||||||
|
MPI.Allreduce!(bv, +, comm) |
||||||
|
@test getindex_debug(A, ilower:iupper, 1:20) == AM[ilower:iupper, 1:20] |
||||||
|
@test getindex_debug(b, ilower:iupper) == bv[ilower:iupper] |
||||||
|
MPI.Barrier(comm) |
||||||
|
end |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
# SPDX-License-Identifier: MIT |
||||||
|
|
||||||
|
using HYPRE |
||||||
|
using HYPRE.LibHYPRE |
||||||
|
using HYPRE.LibHYPRE: @check |
||||||
|
|
||||||
|
function getindex_debug(A::HYPREMatrix, i::AbstractVector, j::AbstractVector) |
||||||
|
nrows = HYPRE_Int(length(i)) |
||||||
|
ncols = fill(HYPRE_Int(length(j)), length(i)) |
||||||
|
rows = convert(Vector{HYPRE_BigInt}, i) |
||||||
|
cols = convert(Vector{HYPRE_BigInt}, repeat(j, length(i))) |
||||||
|
values = Vector{HYPRE_Complex}(undef, length(i) * length(j)) |
||||||
|
@check HYPRE_IJMatrixGetValues(A.ijmatrix, nrows, ncols, rows, cols, values) |
||||||
|
return permutedims(reshape(values, (length(j), length(i)))) |
||||||
|
end |
||||||
|
|
||||||
|
function getindex_debug(b::HYPREVector, i::AbstractVector) |
||||||
|
nvalues = HYPRE_Int(length(i)) |
||||||
|
indices = convert(Vector{HYPRE_BigInt}, i) |
||||||
|
values = Vector{HYPRE_Complex}(undef, length(i)) |
||||||
|
@check HYPRE_IJVectorGetValues(b.ijvector, nvalues, indices, values) |
||||||
|
return values |
||||||
|
end |
||||||
Loading…
Reference in new issue