Repository navigation
Conversation
…ymmetric operators) as precond option Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…onditioner StiffnessPreconditioner for ShearAlfven with polar splines no longer falls back to the polar mass matrix preconditioner: C T~ (Kronecker approximation on the parent tensor-product spaces) is assembled poloidally (exact in the poloidal plane, components 1-2 coupled), eta_3 factors diagonalized (PolarKronSum2Dx1DSolver). No E x B correction needed (its sigma=0 part is indefinite with polar splines). Lowmode TAE polar 16x18x8: 14 PCG iterations/step instead of ~160. ToroidalFourierPreconditioner stays an explicit option (exact for axisymmetric equilibria). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rierPreconditioner, docs, tests - ToroidalFourierSolver: Cholesky only for Hermitian Fourier blocks (else LU), transpose only for symmetric operators, Allreduce with buffers, log on rank 0 - ShearAlfvenCurrentCoupling5D: reject precond="ToroidalFourierPreconditioner"; docstring (polar) - dev-feec.rst: automodule struphy.feec.toroidal_fourier - test_toroidal_fourier.py (TP/polar, symmetric/non-symmetric, eta_3/eta_1 decompositions); polar ShearAlfven test uses mpi_out_folder Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The Fourier solver fails on CuPy due to implicit device-to-NumPy conversions, and the preconditioner configuration accepts CG even though it does not support preconditioning.
2 open issues
What changed in this PR
This PR extends Struphy’s shear Alfvén solvers to improve polar-spline preconditioning, building on the existing 2D × 1D solver infrastructure. It also adds an optional Fourier solver for shift-invariant operators and fixes polar magnetic-energy calculations.
Changes:
- Makes the polar Kronecker Schur preconditioner the default for supported shear Alfvén configurations.
- Adds a toroidal Fourier solver with serial/MPI tests and propagator integration.
- Uses polar-space equilibrium projections for magnetic-energy diagnostics.
| File | Description |
|---|---|
src/struphy/propagators/tests/test_shear_alfven.py |
Tests polar preconditioner agreement, iteration counts, and energy conservation. |
src/struphy/propagators/shear_alfven_propagator.py |
Integrates the Fourier option and documents polar preconditioning. |
src/struphy/propagators/shear_alfven_current_coupling_5d.py |
Updates polar documentation and rejects the unsupported Fourier option. |
src/struphy/models/utils.py |
Uses polar equilibrium coefficients in shared magnetic-energy diagnostics. |
src/struphy/models/shear_alfven.py |
Corrects equilibrium coefficients used for magnetic energies. |
src/struphy/io/options.py |
Registers the Fourier preconditioner option. |
src/struphy/fields_background/projected_equils.py |
Exposes magnetic-field projections in polar spaces. |
src/struphy/feec/toroidal_fourier.py |
Adds Fourier-mode factorization and distributed solves. |
src/struphy/feec/tests/test_toroidal_fourier.py |
Tests symmetric and nonsymmetric operators with both spline types. |
src/struphy/feec/preconditioner.py |
Adds polar Kronecker block preconditioning and Schur dispatch. |
src/struphy/feec/kronecker_block.py |
Supports parent-space polar approximations and adds 1D mass assembly. |
doc/sections/subsections/dev-feec.rst |
Includes Fourier solver API documentation. |
Review effort: Balanced
| if precond == "ToroidalFourierPreconditioner": | ||
| assert algo == "implicit", 'precond="ToroidalFourierPreconditioner" needs algo="implicit".' | ||
| assert derham.spl_kind[2], 'precond="ToroidalFourierPreconditioner" needs a periodic eta_3 direction.' | ||
| return precond |
Comment on lines
+101
to
+104
| block[lo - r : e1 - r, s2 : s2 + data.shape[1], s3 : s3 + data.shape[2]] = data[lo - s1 :] | ||
| if self.polar: | ||
| for c, pol in enumerate(v.pol): | ||
| X[self.offsets[c] : self.offsets[c] + self.n_polar[c]] = pol |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
With polar splines, the implicit shear Alfvén step (
ShearAlfvenPropagator) fell back from the Kronecker Schur preconditioner toPolarMassMatrixPreconditioner, which ignores thedt**2/4 T^T C^T M2 C Tpart of the Schur operator. On the low-mode TAE example with polar splines (IGAPolarTorus, 16x18x8, dt = 0.5) this needed about 160 PCG iterations per step, against about 21 with tensor-product splines.This PR adds a polar version of
ShearAlfvenSchurPreconditionerthat does not assume axisymmetry and is now the default with polar splines. It also adds an exact solver for axisymmetric operators as an explicit option, and fixes a crash of the energy scalars with polar splines.Changes
PolarKroneckerBlockPreconditioner(feec/preconditioner.py): a polar 2D x 1D preconditioner forsum_i L_i^T M_i L_i + sigma S, whereL_iareKroneckerBlockOperators on the parent tensor-product spaces (hereL = C T~). It builds on the machinery of #747 and #758.kron(F1, F2)ofLare combined with the poloidal mass matrices (weights reduced in eta_3, as in Polar splines: StiffnessPreconditioner (grad, curl) and stab_average for GyrokineticPoisson #758), and the polar extraction is applied. The components (u1, u2), which are coupled at the pole, are solved together.F3^T M3 G3are replaced by their diagonals in the eigenbasis of a summary stiffness, as in the tensor-product preconditioner. This usesPolarKronSum2Dx1DSolver, with one poloidal factorization per eta_3 mode.T~. It works for any geometry and does not assume axisymmetry.ShearAlfvenSchurPreconditioneruses it with polar splines, andresolve()no longer falls back for polar.kronecker_block.basis_projection_operatoraccepts polar operators (it approximates them on the tensor-product FEM spaces).derivative_operatornow usesderham.{grad,curl,div}_tp. These are the same objects as*_bcfreewithout polar splines.mass_matrix_1d.ToroidalFourierSolver(new modulefeec/toroidal_fourier.py), optionprecond="ToroidalFourierPreconditioner":rfftalong eta_3 and one dense Cholesky or LU factorization per toroidal mode number. The modes are distributed over the processes.ShearAlfvenCurrentCoupling5Drejects this option.Bug fix:
en_B_eqanden_B_totofShearAlfvenand of the linear MHD models (models/utils.MagneticEnergies) paired the tensor-productprojected_equil.b2with the polar mass matrix, which raised anAssertionErrorwith polar splines. The newProjectedFluidEquilibriumWithB.b1_polar/b2_polarreturn the projection in the polar space; without polar splines they are identical tob1/b2, so baselines are unchanged.Results
Low-mode TAE (
examples/ShearAlfven/lowmode_tae,IGAPolarTorus16x18x8, degree 3, dt = 0.5, tol 1e-8, 2 ranks):PolarMassMatrixPreconditioner(before)StiffnessPreconditioner→PolarKroneckerBlockPreconditioner(new default)ToroidalFourierPreconditioner(exact, axisymmetric)HollowTorus16x16x8 (for comparison)Dense check on 6x18x4 (polar, serial), condition number of
P S:ToroidalFourierSolverresidual on a random vector: 2e-13 on the TAE case, and 1e-15 in the unit tests, which cover tensor-product and polar splines and grids decomposed along eta_3 and eta_1.Tests
propagators/tests/test_shear_alfven.py:resolve()is updated (polar keepsStiffnessPreconditioner; checks of the Fourier option). The newtest_shear_alfven_polar_preconditionerschecks that the polar mass preconditioner, the new default and the Fourier preconditioner give the same step (to 1e-8), that the new ones need fewer iterations (Fourier at most 3), and that energy is conserved.feec/tests/test_toroidal_fourier.py: HollowCylinder and IGAPolarCylinder; M2 andM1 + G M0 G^T(Cholesky);M2 + 0.3 M2B(non-symmetric, LU); grid decompositions along eta_3 and eta_1.test_kronecker_block.pyandtest_stiffness_preconditioner.pypass serially (67) and on 2 ranks.ShearAlfvenCurrentCoupling5D. With polar splines it now also gets the polar preconditioner, but the 5D models cannot run with polar splines yet (Polar splines in LinearMHDDriftkineticCC: 5D current-coupling propagators index PolarVectors as BlockVectors #917).Follow-ups
LinearMHDDriftkineticCC).ToroidalFourierSolverat higher poloidal resolution.k_par.🤖 Generated with Claude Code