Skip to content

feat(solver): Residual-Aware Dynamic Preconditioning (RAD-P) for Issue #818 - #823

Draft
duushgu wants to merge 5 commits into
proximafusion:mainfrom
duushgu:feature/adaptive-preconditioner-update
Draft

feat(solver): Residual-Aware Dynamic Preconditioning (RAD-P) for Issue #818#823
duushgu wants to merge 5 commits into
proximafusion:mainfrom
duushgu:feature/adaptive-preconditioner-update

Conversation

@duushgu

@duushgu duushgu commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Change

Replaces the fixed 25-iteration preconditioner update interval with a residual-aware decision function (shouldUpdateRadialPreconditioner) controlled by a new VmecInput field adaptive_preconditioner_update (default false).

Cause

kPreconditionerUpdateInterval = 25 is a compile-time constant in ideal_mhd_model.cc. The value is inherited from the original Fortran VMEC without derivation. In early multigrid stages the residual drops orders of magnitude per dozen iterations; a 25-step-old block-tridiagonal factor can misalign the metric and trigger BAD_JACOBIAN resets. In late stages with sub-percent per-step improvement the full refactor is wasted cost.

Evidence

Tested across 21 configurations: 9 standard test suite equilibria (including up_down_asym) and 12 QUASR stellarator configurations.

Suite Baseline iters RAD-P iters Delta
Standard (9 cases) 5,775 5,681 -94 (-1.6%)
QUASR (12 cases) 20,451 19,272 -1,179 (-5.8%)
Total 26,226 24,953 -1,273 (-4.85%)

Notable: quasr_65579 -915 iterations (-27.2%), up_down_asym -105 iterations (-3.3%).

max |Delta_R| < 4e-4 across all 21 configurations relative to baseline with flag off.

Tests

  • vmec_test.cc: AdaptivePreconditionerMatchesEquilibrium -- runs 4 equilibria with flag on and off; asserts max |Delta_R| < 1e-3. Tolerance set to the numerical noise expected from trajectory differences when the converged state is identical.
  • tests/test_iteration.py: test_adaptive_preconditioner_matches_equilibrium -- same 4 configurations at the Python level; same tolerance.

Scope

adaptive_preconditioner_update defaults to false. Execution is bit-identical to current code when false. No configuration in the 21-case benchmark regresses in iteration count.

dush added 5 commits September 7, 2026 18:37
- Replace hardcoded periodic 25-step preconditioner update cadence with
  stagnation and curvature-aware dynamic updates (RAD-P).
- Plumb adaptive_preconditioner_update through VmecINDATA, FlowControl,
  IdealMhdModel, Vmec, PyBind11, and Python VmecInput (default: false).
- Add stagnation detection (res0 plateauing over 15+ steps) and curvature
  jump protection (fsq > 10 * res0) with 5-step quench window and 50-step ceiling.
- Add C++ and Python unit tests verifying exact physical equilibrium fidelity.
- Benchmark across 21 test and QUASR configurations demonstrates a net
  reduction of 1,273 iterations (-4.85% overall, -27.2% on quasr_65579).
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