Skip to content

Port to Ginkgo develop and reuse the Multigrid hierarchy - #171

Merged
greole merged 13 commits into
devfrom
update/gko-version
Oct 10, 2026
Merged

greole merged 13 commits into
devfrom
update/gko-version

Conversation

@greole

@greole greole commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

This PR ports OGL to the current Ginkgo develop API and uses the reusable multigrid hierarchy of LinOpFactory::generate_reuse from ginkgo-project/ginkgo#2117, which is merged into Ginkgo develop and supersedes the closed ginkgo-project/ginkgo#2099. It also moves the LRZ GitLab CI to images with Ginkgo develop and OpenFOAM.

Changes

Port to the current Ginkgo API

  • Ginkgo develop removed EnableLinOp and EnablePolymorphicObject: CombinationMatrix, RepartDistMatrix and Adaptive now derive from gko::LinOp and gko::EnableCloneable, and OpenFOAMDistStoppingCriterion derives from gko::stop::Criterion
  • use get_diag_matrix()/get_off_diag_matrix() instead of the deprecated get_local_matrix()/get_non_local_matrix() of the distributed matrix
  • OGL_GINKGO_CHECKOUT_VERSION defaults to develop

Multigrid hierarchy reuse

  • new opt-in Multigrid option reuseHierarchy (default false), for both the Schwarz and Distributed type
  • the preconditioner is generated via LinOpFactory::generate_reuse, and the reuse data is kept in the object registry. Regenerations keep the recorded Pgm aggregates and transfer operators and only recompute the coarse matrices, smoothers and the coarsest solver
  • if the matrix no longer fits the recorded hierarchy, OGL logs the Ginkgo error and records it again
  • new option maxHierarchyReuses (default 0, no limit): once the hierarchy has been reused that many times, the next regeneration records it again from the current matrix. The reuse count is kept per system matrix and reset whenever the hierarchy is recorded

LRZ GitLab CI

  • run on the openfoam-ginkgo-{cuda,rocm,sycl} images of exasim-project/openfoam-conda: OpenFOAM v2512 on the Ginkgo develop images (Ginkgo 0dfd8c5, the merge of Enable PGM to reuse aggregates with the generate_reuse. ginkgo-project/ginkgo#2117). OpenFOAM uses the MPI of the image, so Pstream and Ginkgo load the same MPI. Dated tags, since the runner caches images by name
  • sync the scripts with NeoN: activate OpenFOAM through the image's activate.sh, restore the MPICH/CUDA paths, launch the MPI tests with the MPI of the image and start the ranks locally, port the trigger script, drop the NeoN-specific parts and the Kokkos options
  • trigger workflow: run on pushes to dev (was develop), only in hpsim/OGL and not for PRs from forks, and no longer cancel the pipelines after waiting for them
  • detect the ESI version of OpenFOAM also via FOAM_API, since the conda packages do not install META-INFO

Fixes

  • when the caching period of a preconditioner ran out, the regenerated preconditioner was not stored, so every later caching period reused the very first preconditioner
  • removed the Multigrid value update for cached preconditioners. It was never compiled (guarded by GINKGO_WITH_OGL_EXTENSION, while CMake defines GINKGO_WITH_OGL_EXTENSIONS) and used UpdateMatrixValue, which Ginkgo no longer provides

Usage

preconditioner
{
    preconditioner  Multigrid;
    reuseHierarchy  true;
    maxHierarchyReuses 10;   // optional, record again after 10 reuses
}

The hierarchy is recorded from the first matrix, so reuse only pays off if later matrices are similar to it. maxHierarchyReuses limits how far the matrix can drift from the recorded one.

Compatibility

This branch no longer builds against the previous default Ginkgo (ogl_0600_gko190). It needs Ginkgo develop with ginkgo-project/ginkgo#2117, which is now the default checkout. All sources compile against Ginkgo develop (d5a8402, syntax-only check).

Testing

icoFoam on the 100x100 lid-driven cavity, 2 ranks on 2x AMD MI200 (gfx90a, ROCm 6.4.3), GKOCG with executor hip and scaling -1, run to t = 0.5 (200 pressure solves).

Measured on rebased/pr-2099, before ginkgo-project/ginkgo#2117 was merged; not yet re-run on develop. The new Ginkgo API gives the same results as the previous Ginkgo. Pressure iterations in the last time step:

Preconditioner previous Ginkgo rebased/pr-2099
none (OpenFOAM PCG + diagonal) 453 453
BJ 460 460
Multigrid 77 75
ILU 157 157
ISAI 246 246

Multigrid hierarchy reuse (Multigrid regenerates on every solve unless caching is set):

Variant preconditioner setup per solve last-step p iterations
Schwarz 9.33 ms 75
Schwarz + reuseHierarchy 3.16 ms 73
Distributed 33.87 ms 49
Distributed + reuseHierarchy 7.67 ms 49
Schwarz + reuseHierarchy + caching 5 0.79 ms 73

The final p and U fields at t = 0.5 are identical, to the written precision, with and without reuse and to the OpenFOAM baseline. The re-recording after a sparsity change is not covered, since the cavity mesh is static. maxHierarchyReuses has not been tested on GPUs yet.

The LRZ pipeline on the new images has not run yet; this PR is its first run.

greole added 13 commits October 4, 2026 18:33
Ginkgo develop removed EnableLinOp and EnablePolymorphicObject. Custom
LinOps now derive from gko::LinOp and gko::EnableCloneable, and the
stopping criterion derives from gko::stop::Criterion directly.

- port CombinationMatrix, RepartDistMatrix, Adaptive and
  OpenFOAMDistStoppingCriterion to the new base classes
- use get_diag_matrix/get_off_diag_matrix instead of the deprecated
  get_local_matrix/get_non_local_matrix of the distributed matrix
- default to the Ginkgo branch rebased/pr-2099 (updatable PGM values)
When the caching period of a preconditioner ran out, the new
preconditioner was only assigned to a local copy, so every later caching
period reused the very first preconditioner. Replace the stored
preconditioner instead.

Also remove the Multigrid value update for cached preconditioners. It was
guarded by GINKGO_WITH_OGL_EXTENSION, which is never defined (CMake sets
GINKGO_WITH_OGL_EXTENSIONS), and used UpdateMatrixValue, which Ginkgo no
longer provides.
Add the opt-in Multigrid option reuseHierarchy. If enabled, the
preconditioner is generated via LinOpFactory::generate_reuse and the
reuse data is kept in the object registry, so regenerations keep the
recorded Pgm aggregates and transfer operators and only recompute the
coarse matrices, smoothers and coarsest solver. If the matrix no longer
fits the recorded hierarchy, the recording starts again.

Supported for both the Schwarz and the Distributed Multigrid type.
With reuseHierarchy, the hierarchy recorded from the first matrix was
kept for the whole run. The new option maxHierarchyReuses records it
again from the current matrix after it has been reused that many times
(default 0, never). The number of reuses is kept per system matrix in
the solver properties and reset whenever the hierarchy is recorded.
Ginkgo develop now implements the reuse of the Multigrid hierarchy via
generate_reuse (ginkgo-project/ginkgo#2117), which supersedes the
closed PR #2099. Use develop as the default Ginkgo version and update
the note on the lifetime of the reuse data: the result of
generate_reuse is independent of its reuse data, which stays usable if
generate_reuse throws.
The conda packages of OpenFOAM, as used in the openfoam-ginkgo images
of exasim-project/openfoam-conda, do not install META-INFO, so OGL was
compiled without WITH_ESI_VERSION. FOAM_API is only set by the ESI
version, so accept it as well.
Use the openfoam-ginkgo-{cuda,rocm,sycl} images of
exasim-project/openfoam-conda: OpenFOAM v2512 on the Ginkgo develop
images (Ginkgo 0dfd8c5, including ginkgo-project/ginkgo#2117), where
OpenFOAM uses the MPI of the image, so Pstream and Ginkgo load the same
MPI. Dated tags, since the runner caches the images by name.

Sync the setup with NeoN:
- activate OpenFOAM through the activate.sh of the image instead of
  setting the OpenFOAM environment by hand
- add the MPICH and CUDA paths back to PATH, launch the MPI tests with
  the MPI of the image and start the ranks locally
- port the trigger script and drop the NeoN/NeoFOAM specific parts of
  the cancel script
- drop the Kokkos options copied from NeoN

Also fix the trigger workflow: trigger on pushes to dev instead of
develop, only run in hpsim/OGL and not for PRs from forks, and remove
the step cancelling the pipelines after waiting for them.
Multigrid.hpp creates DevicePersistentBase<ReuseData> in several
translation units, while its typeName is only defined in Base.cpp.
Clang-based compilers warned about this (-Wundefined-var-template), so
declare the explicit specialization in the header.
All MPI unit tests of the SYCL job failed in MPI_Init: the libfabric
provider Intel MPI picks for the interconnect fails in the container
(OFI EP enable failed: Cannot allocate memory). The tests run on one
node, so use FI_PROVIDER=tcp.
OpenFOAM v2506 deprecated UPstream::commIntraHost in favour of
commLocalNode, which every translation unit including
ExecutorHandler.hpp warned about with v2512. Define OPENFOAM to the API
version of the ESI version, as wmake does, and use commLocalNode from
v2506 on.
Silences the CMP0135 developer warning of FetchContent.
After the unit tests, run the icoFoam cavity tutorial on 2 ranks with
the pressure (p and pFinal) solved by GKOCG on the GPU executor of the
job (cuda, hip, sycl). The job fails unless icoFoam completes, every
pressure solve went through GKOCG, and the last pFinal solve reached
its tolerance.
@greole
greole merged commit 7c3ced4 into dev Oct 10, 2026
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant