Skip to content

Hypre solver eliminate boundaries (New API) - #3460

Open
bendudson wants to merge 12 commits into
nextfrom
next-elimBE-new-api
Open

Hypre solver eliminate boundaries (New API)#3460
bendudson wants to merge 12 commits into
nextfrom
next-elimBE-new-api

Conversation

@bendudson

Copy link
Copy Markdown
Contributor

Replaces #3439, using a new API that doesn't require sharing boundary information between matrices, rhs and solution vectors. Avoids hidden mutations that could be hard to reason about.

Includes additional tests and some changes to the boundary row elimination code.

Written almost entirely by Codex/gpt-5.4 with review and iterations.

The vector should be assembled once after importing values.
Assembling twice with elimBE over-corrects the RHS.
row_indexes is free'd using HypreFree, so should be allocated using
HypreMalloc.
The row elimination is now an implementation detail that doesn't
require changes to the HypreMatrix and HypreVector interface.

The elimination is applied to temporary working vectors when
assembling the HypreVector, so the input values are not mutated.

New tests check the boundary elimination.
Fixes the integrated Laplace-Hypre3D tests.

GPT says: The boundary-elimination logic in [src/sys/hypre_interface.cxx (line
48)](/Users/dudson2/code/BOUT-next/src/sys/hypre_interface.cxx:48) was
only removing each boundary variable from one coupled row; in the
hypre3d stencil, the same Y-boundary value can appear in multiple
nearby rows, especially in the SOL case. I changed BoundaryElimination
to collect all representable row couplings for each boundary equation,
store them with per-boundary offsets, and apply them during matrix
reduction, RHS reduction, and matvec reconstruction. The interface
metadata was updated in [include/bout/hypre_interface.hxx (line
103)](/Users/dudson2/code/BOUT-next/include/bout/hypre_interface.hxx:103),
and I added multi-coupling unit coverage in
[tests/unit/include/bout/test_hypre_interface.cxx (line
618)](/Users/dudson2/code/BOUT-next/tests/unit/include/bout/test_hypre_interface.cxx:618).

@ZedThree ZedThree left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't judge the accuracy of the numerics, but I have a few comments on the code.

Comment thread include/bout/hypre_interface.hxx Outdated
Comment on lines +140 to +151
HYPRE_Int nb;
HYPRE_Int* binum_array;
HYPRE_Int* bjnum_array;
HYPRE_Int* bdep_array;
HYPRE_Complex* bii_array;
HYPRE_Complex* bij_array;
HYPRE_Int na;
HYPRE_Int* aoffset_array;
HYPRE_Int* aknum_array;
HYPRE_Complex* aki_array;
std::vector<HYPRE_Int> reduction_order;
std::vector<HYPRE_Int> expansion_order;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason some of these are raw pointers, and some are std::vector? Is this a device/host distinction?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly yes. std::vector can't be used on host and arrays that are passed into Hypre should use HypreMalloc.

Comment thread include/bout/hypre_interface.hxx Outdated
Comment thread src/sys/hypre_interface.cxx Outdated
Comment on lines +58 to +64
std::vector<std::vector<BoundaryOccurrence>> occurrences_by_boundary(nb);
for (HYPRE_Int rownum = 0; rownum < nrows; rownum++) {
const HYPRE_Int row_start = row_indexes[rownum];
for (HYPRE_Int m = 0; m < ncols[rownum]; m++) {
const auto boundary_position = boundary_number_for_row.find(cols[row_start + m]);
if (boundary_position != boundary_number_for_row.end()) {
occurrences_by_boundary[boundary_position->second].push_back({rownum, m});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what this is supposed to be doing, but should occurrences_by_boundary just be std::set?

I think this block could use a comment explaining what it's doing

Comment thread src/sys/hypre_interface.cxx
Comment thread src/sys/hypre_interface.cxx Outdated
HYPRE_BigInt* cols, HYPRE_Complex* values,
HYPRE_Int nb, HYPRE_Int* bi_array)
: nb(nb) {
HYPRE_Int* row_indexes;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this constructor should be executed on the host, so we can use vector here?

Suggested change
HYPRE_Int* row_indexes;
std::vector<HYPRE_Int> row_indexes;
row_indexes.reserve(nrows);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lifetime of this is somewhat complicated: row_indexes is allocated but then assigned to the "out" parameter row_indexes_ptr. Very C-like behavior. This could perhaps be tidied up in future.

BoundaryElimination::BoundaryElimination(HYPRE_Int nrows, HYPRE_Int* ncols,
HYPRE_BigInt* rows, HYPRE_Int** row_indexes_ptr,
HYPRE_BigInt* cols, HYPRE_Complex* values,
HYPRE_Int nb, HYPRE_Int* bi_array)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most of these should at least be const*, but I don't think there's any need for pointers here? Most of them seem to be copied elementwise?

@bendudson bendudson added the feature A PR that adds new capabilities / features label Aug 27, 2026
Corner equations are likely not handled correctly, but it probably
doesn't matter.
Calculation of boundary rows can just use the size of the container.
More descriptive flag. The API member function `setElimBE` is also
renamed to `setUseBoundaryElimination`
@bendudson
bendudson requested a review from ZedThree September 8, 2026 03:51
Many small things. Replaced some raw pointers with shared_ptr.

Added `modernize-use-ranges` to `.clangd`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature A PR that adds new capabilities / features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants