Skip to content

Add a compatible relaxation CF splitting (-pc_air_cf_splitting_type cr) - #261

Merged
stevendargaville merged 11 commits into
mainfrom
cr_cf_splitting
Aug 1, 2026
Merged

Add a compatible relaxation CF splitting (-pc_air_cf_splitting_type cr)#261
stevendargaville merged 11 commits into
mainfrom
cr_cf_splitting

Conversation

@stevendargaville

Copy link
Copy Markdown
Collaborator

Adds a compatible relaxation (CR) CF splitting as a new splitting type, CF_CR / -pc_air_cf_splitting_type cr.

What it does

Classic from-scratch CR coarsening (Brandt / Brannick–Falgout form): all points start as F, and each pass promotes an independent set of the F rows where the relaxed error remains largest (the hypre candidate measure), until one application of the F-point smoothing contracts a random error on Aff by the target rate carried in -pc_air_strong_threshold (~0.1 recommended). It never forms a strength matrix or S+S^T — the independent set uses PMISR with the implicit transpose, and all heavy numerics are stock PETSc Mat/Vec ops, so aijkokkos runs the setup on device with no new Kokkos kernels.

Design points

  • The CR relaxation mirrors the PCAIR Aff inverse settings (-pc_air_inverse_type, -pc_air_poly_order, -pc_air_inverse_sparsity_order, -pc_air_diag_scale_polys), passed through new optional arguments on compute_cf_splitting (standalone C/Python API unchanged; defaults match a default-configured PCAIR).
  • One relaxation application per pass (nu=1), always assembled. AIR applies its F-solve once per smoothing step, so the one-application contraction ||I - M Aff|| is what gates convergence — multi-sweep asymptotic rates look good for any splitting on near-triangular advective Aff and hide growing iteration counts. Similarly the ideal restrictor is always built from the assembled sparsified inverse even with -pc_air_matrix_free_polys, making it the binding constraint: certifying with the matrix-free polynomial under-coarsens and iterations grow (16/21/27 over 100^2-400^2), while certifying with the assembled inverse stays flat and the matrix-free smoother simply does better than predicted.
  • Row-scaling robust with -pc_air_diag_scale_polys (the relaxation operator p(D^-1 Aff) D^-1 Aff is row-scaling invariant); tested on the poorly scaled SUPG problem.

Results (steady upwind FD advection, -pc_air_inverse_type power, target 0.1)

n 100^2 200^2 400^2 800^2 400^2 (4 ranks)
AIRG iterations 9 10 11 12 11
grid / op complexity 1.91 / 3.7 2.00 / 4.4 1.93 / 4.3 1.99 / 4.8

For reference pmisr_ddc is 6 iterations flat at operator complexity ~14 — the CR hierarchies are ~3x cheaper per cycle. DG advection: 14 -> 18 over refine 2 -> 3.

Also included

  • Fix for a latent segfault in calculate_and_build_approximate_inverse: present(x) .AND. associated(x) in one expression — Fortran does not short-circuit, so any caller omitting the optional dereferenced a null descriptor.
  • New tests: serial + parallel cr runs of adv_diff_fd and adv_dg_upwind, the poorly scaled SUPG problem with diagonal scaling, and a CF_CR block in ex6_cf_splitting. All pass on CPU, aijkokkos, and under PFLARE_KOKKOS_DEBUG=1; make check and make tests_short pass.
  • Docs updated (new_methods.md, options.md, faq.md, man pages) and a CHANGELOG entry.

🤖 Generated with Claude Code

stevendargaville and others added 11 commits August 1, 2026 00:35
Fortran does not short-circuit .AND., so
present(coefficients) .AND. associated(coefficients) dereferences a null
descriptor and segfaults whenever the optional is omitted. No existing
caller omitted it, so this was latent until the CR splitting called it
without coefficients.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…_type cr)

Coarsens from scratch with no strength matrix: all points start as F and
each pass promotes an independent set (PMISR with implicit transpose, so
no S+S^T is ever formed) of the F rows where the relaxed error remains
largest, until one application of AIR's own F-point smoothing - an
assembled power-basis GMRES polynomial with sparsity order 1 - contracts
a random error on Aff by the target rate carried in the strong threshold
(around 0.1 recommended).

nu=1 relaxation applications per pass is deliberate: AIR applies its
F-solve once per smoothing step, so the one-application contraction
||I - M Aff|| is what gates convergence; multi-sweep asymptotic rates
look good for any splitting on near-triangular advective Aff and hide
growing iteration counts. The candidate measure is hypre's normalized
remaining error, which cannot stall short of the target the way per-row
convergence factors can.

On steady upwind advection this gives near-flat AIRG iterations
(9/10/11/12 at 100^2 to 800^2) with operator complexity ~4.5 vs ~14 for
pmisr_ddc, in serial and parallel. All heavy numerics are stock PETSc
Mat/Vec ops so aijkokkos runs the setup on device with no custom Kokkos
kernels; host marker logic only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The CR relaxation now uses the same inverse type, polynomial order,
sparsity order and diagonal scaling as the hierarchy's Aff inverse,
passed as optional arguments through compute_cf_splitting (the
standalone C/Python API is unchanged and keeps the previous power/6/1
defaults). Jacobi inverse types route to the inline Jacobi path, which
also respects unweighted Jacobi.

matrix_free_polys is deliberately NOT mirrored - the CR inverse is
always assembled. The ideal restrictor is always built from the
assembled sparsified inverse even when matrix-free smoothing is on
(AIR_Operators_Setup), so the assembled inverse is the binding
constraint on splitting quality. Certifying with the matrix-free
polynomial under-coarsens and iterations grow with problem size
(16/21/27 at 100^2-400^2 with -pc_air_matrix_free_polys) even though
the F-smoother is then exactly what was certified - the growth comes
from the restrictor. Certifying with the assembled inverse stays flat
(9/10/11) and the matrix-free smoother simply does better than
predicted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ling

Adds serial and parallel runs of the existing poorly scaled SUPG CG FEM
advection problem (curved non-unit velocity) with the cr splitting and
-pc_air_diag_scale_polys. The CR relaxation mirrors the diagonal scaling
of the hierarchy's Aff inverse, making the splitting robust to bad row
scaling - the relaxation operator p(D^-1 Aff) D^-1 Aff is row-scaling
invariant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When compute_cf_splitting is called without the optional cr_* arguments
(the standalone C/Python API), the CR relaxation now defaults to an
assembled arnoldi-basis GMRES polynomial, matching the default
-pc_air_inverse_type, so the standalone splitting matches what a
default-configured PCAIR produces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The CR rate estimates sit near thresholds, so optimized builds can
produce slightly different splittings than debug builds - the DG cr test
took 15 iterations on the gnu_opt CI build against a bound of 14 tuned
on a debug build. Bounds now cover both builds measured in the CI image
plus a margin of 1-2 for the other CI platforms.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The intel_opt CI job needs up to 15 iterations on the parallel poorly
scaled SUPG cr test against a bound of 12 - the CR splittings vary a
few iterations across compilers as the rate estimates sit near
thresholds. Bounds are now the worst observed across the gnu debug,
gnu opt and intel CI images plus a margin of 2-3 for the macos jobs:
10x10 -> 4, 100x100 -> 12, DG -> 18, SUPG -> 18. All no_load test
groups verified inside both the gnu opt and intel CI images (with the
intel power->arnoldi parallel substitutions applied as in CI).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@stevendargaville
stevendargaville merged commit fe89ca6 into main Aug 1, 2026
19 checks passed
@stevendargaville
stevendargaville deleted the cr_cf_splitting branch August 1, 2026 11:48
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