Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Structural Auto API (0.8)

HyBIT’s generic solve_csr32 path remains geometry-free and backward compatible. For 3-D structural SPD systems, callers can provide node coordinates explicitly:

use hybit::{
    HybitSolver, RigidBodyAggregation, SolverOptions, StructuralOptions,
    StructuralPcgVectorPolicy, StructuralPreconditionerPolicy, StructuralSpmvPolicy,
};

let mut solver = HybitSolver::new();
solver.set_options(SolverOptions {
    relative_tolerance: 1.0e-8,
    absolute_tolerance: 0.0,
    max_iterations: 3000,
})?;
solver.set_structural_options(StructuralOptions {
    target_coarse_dimension: 1536,
    aggregation: RigidBodyAggregation::Auto,
    spmv_policy: StructuralSpmvPolicy::Auto,
    preconditioner_policy: StructuralPreconditionerPolicy::Auto,
    pcg_vector_policy: StructuralPcgVectorPolicy::Auto,
})?;

let report = solver.solve_structural_csr32(&a, &coordinates, &b, &mut x)?;

For solve-many workloads, prepare once and reuse the rigid-body coarse factor:

let analysis = solver.analyze_csr32(&a)?;
let mut prepared = solver.prepare_structural_csr32(&a, &analysis, &coordinates)?;
let first = prepared.solve(&a, &b1, &mut x1)?;
let second = prepared.solve(&a, &b2, &mut x2)?;

HybitPreparedStructuralSystem exposes the selected aggregate size, aggregate count, coarse dimension, factor storage, geometry storage, and workspace size.

The structural path currently assumes exactly three displacement DOFs per node and uses six rigid-body modes per aggregate. RigidBodyAggregation::Auto is the default: it tries deterministic graph-connected aggregation first and falls back to the contiguous RCM-order baseline if the graph coarse Cholesky is numerically singular or if the structural node graph contains disconnected components too small to support a six-mode rigid-body aggregate. RigidBodyAggregation::Contiguous preserves the fixed-width baseline, while RigidBodyAggregation::Graph requests graph aggregation without fallback. Coordinate ordering must match the CSR DOF ordering exactly: node i maps to rows 3*i, 3*i+1, 3*i+2.

Measuring prepared reuse

bench-fem-structural-prepared.ps1 prepares the structural context once and then solves the same RHS repeatedly from a fresh zero initial guess. This deliberately prevents warm-start effects from being confused with preconditioner reuse. The first report charges analysis and preparation; later reports must show preconditioner_reused = true with zero analysis/prepare charge.

Example:

.\benchmarks\scripts\bench-fem-structural-prepared.ps1 K.mtx `
  -Coordinates K.coords `
  -Rhs b.txt `
  -TargetCoarseDimension 1536 `
  -Tolerance 1e-8 `
  -MaxIterations 3000 `
  -Repeats 2

Graph aggregation experiment (0.6-r10)

The graph mode keeps the same target coarse dimension and six rigid-body modes, but forms connected node regions from 3x3 block sparsity instead of slicing the RCM node order into fixed-width chunks. This is intended as an A/B experiment before changing the default Structural Auto policy.

.\benchmarks\scripts\bench-fem-structural-auto.ps1 K.mtx `
  -Coordinates K.coords `
  -Rhs b.txt `
  -TargetCoarseDimension 1536 `
  -Aggregation graph `
  -Tolerance 1e-8 `
  -MaxIterations 3000

The benchmark reports actual aggregate count and minimum/maximum aggregate sizes so changes in coarse dimension are visible rather than hidden.

Graph aggregation robustness (0.6-r11)

The initial capped-BFS graph experiment could leave tiny remainder islands after nearby nodes had already been assigned. A six-mode rigid-body basis can become rank deficient or severely ill-conditioned on such islands. r11 therefore merges graph aggregates smaller than one quarter of the requested aggregate size (never below three nodes) into the neighboring aggregate with the strongest edge connection before forming Z^T A Z. No diagonal regularization is added: failure of the coarse Cholesky still indicates a genuine basis/geometry problem rather than being hidden by a shift.

Structural Auto graph policy (0.6-r12)

The L-angle physical-load development benchmark showed that graph-connected aggregation was substantially more effective than contiguous RCM chunks at essentially the same coarse dimension: 220 versus 1370 PCG iterations at a relative tolerance of 1e-8, with coarse dimensions 1398 and 1404 respectively. This is a single development benchmark, not a general performance guarantee.

For that reason r12 makes RigidBodyAggregation::Auto the Structural Auto default. Auto attempts the graph coarse space first. If coarse Cholesky reports a numerical breakdown, or if graph topology leaves a disconnected component with fewer than three nodes, Auto retries with contiguous aggregation. Explicit Graph remains strict so A/B benchmarks still expose graph-basis failures rather than silently hiding them.

Packed coarse Cholesky storage (0.6-r17)

The structural rigid-body path now stores the dense Cholesky lower factor in row-wise packed triangular form. The Galerkin coarse operator, aggregation, rigid-body basis, pivot test, and PCG algorithm are unchanged; only factor storage and triangular-solve addressing change. A coarse dimension m uses m(m+1)/2 stored f64 factor values instead of m^2, with row-start offsets precomputed once during preparation.

This is intentionally an implementation optimization rather than a policy change. Re-run the Graph target-coarse-dimension points at 1536 and 3072 to measure whether the reduced factor footprint improves wall time as well as memory use on the target CPU.

Fine-grid SpMV policy (0.6-r20)

Structural PCG can now select the validated Rayon-parallel CSR operator through StructuralSpmvPolicy. Auto keeps small matrices serial and switches CSR32 systems with at least 1,000,000 nonzeros to parallel row execution. Serial and Parallel remain available for controlled benchmarking; explicit Parallel requires the CSR32 backend. The parallel implementation preserves the same CSR storage and arithmetic ordering within each row, so iteration counts should remain unchanged.

The Rayon pool size is intentionally external to the solver policy. Rust callers can continue to use RAYON_NUM_THREADS. C/C++/Fortran hosts additionally have the 0.8 thread-interoperability API: explicit hybit_set_num_threads(n) takes precedence, followed by RAYON_NUM_THREADS, then OMP_NUM_THREADS, then the Rayon default. OpenMP API users should synchronize omp_get_max_threads() into HyBIT before creating the first solver. See Threading and host-runtime interoperability. On the development L-angle case on a Ryzen 7 7800X3D, 4 threads was the best tested point: CSR SpMV improved from about 13.24 ms to 5.09 ms and the 220-iteration structural PCG solve from about 4.44 s to 2.73 s. This machine-specific result is not used as a hard-coded library thread count.

0.6 structural execution policy (development)

Structural Auto independently resolves StructuralSpmvPolicy, StructuralPreconditionerPolicy, and StructuralPcgVectorPolicy. Large CSR structural systems can therefore use parallel CSR SpMV, parallel 3x3 block-Jacobi/restriction/prolongation, and parallel/fused PCG vector kernels together. Small systems remain serial to avoid Rayon overhead. The packed dense coarse triangular solve remains serial. Rayon thread count is controlled externally (for example RAYON_NUM_THREADS).

PCG dense-vector policy (0.6-r25)

Structural solves expose StructuralPcgVectorPolicy::{Auto, Serial, Parallel} independently from the sparse SpMV and rigid-body preconditioner policies. The parallel path uses the shared Rayon pool for dot/norm reductions, search-direction updates, and a fused x += alpha*p, r -= alpha*Ap, ||r|| traversal.

Auto is deliberately conservative: it selects the parallel/fused path only for at least 131072 unknowns and at least 4 Rayon workers. Explicit Serial remains available for low-thread-count execution and controlled A/B tests.

At the r25 production checkpoint, the physical-load 358065-DOF / 28239653-nnz L-angle case at 8 Rayon workers resolved to Graph aggregation, Parallel SpMV, Parallel preconditioning, and Parallel PCG vectors. It used 233 aggregates and a 1398-dimensional coarse space, converged in 220 iterations, and independently verified a relative residual of 9.378557e-9. Measured solve time was 1.726 s; analysis+prepare+solve was 2.797 s on the Ryzen 7 7800X3D development machine. These timings are a reproducible development reference, not a cross-machine performance guarantee.