Repository navigation
Remove net charge from the rhs of singular (periodic) Poisson solves - #737
Open
max-models wants to merge 1 commit into
Open
max-models wants to merge 1 commit into
max-models wants to merge 1 commit into
Conversation
On a periodic domain (no Dirichlet BCs) the Poisson operator G^T M1 G is singular with the constant functions (coefficient vector of all ones) in its kernel. It was regularized only with stab_eps (default -> 1e-14), so a non-neutral source (e.g. Monte-Carlo noise of the particle charge density) made the constant mode of phi ~ (net charge) / stab_eps ~ 1e13, and E = -grad phi lost most digits to cancellation (2-5 % error). PoissonSolve now enforces the discrete compatibility condition 1^T b = 0 by removing the net charge from the rhs, b <- b - (1^T b)/(1^T M0 1) M0 1 (a uniform neutralizing background), when the operator is singular (no Dirichlet BCs, no polar splines). New option enforce_compatibility (True for PoissonSolve, False for ImplicitDiffusion and PoissonAdiabaticGyrokinetic). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Problem
On a domain without Dirichlet boundary conditions (e.g. fully periodic), the Poisson operator
G^T M1 Gis singular. Its kernel is the constant functions, which have coefficient vector1(all ones, by partition of unity).PoissonSolveonly regularized this withstab_eps * stab_mat, and the defaultstab_eps = 0is bumped to1e-14inallocate. When the source has a nonzero net charge1^T b, the constant mode ofphibecomes(net charge) / stab_eps. In PIC this always happens, because the Monte-Carlo charge density is noisy. That constant is around 1e9 to 1e13, soE = -grad philoses most of its digits to cancellation.This affects the
initial_poissonofVlasovAmpereOneSpecies,VlasovMaxwellOneSpecies,LinearVlasovAmpereOneSpecies,LinearVlasovMaxwellOneSpeciesandColdPlasmaVlasov. It also affects every otherPoissonSolveuser on periodic or Neumann domains (Poisson,HasegawaWakatani,IncompressibleNavierStokesSPH,ToyDrift). The verification tests use the defaultstab_eps, so they are affected too.I found this while writing the GPU end-to-end test for
VlasovAmpereOneSpecies(#734). That test currently setsstab_eps=1e-6as a workaround, which can be removed once this PR is merged.Numbers before the fix
All runs use 1D periodic
Cuboid(r1=12.56), degree (3,1,1) and default options.0.3 + 0.1 cos(kx), 16 cells,stab_mat="Id"stab_mat="M0"stab_eps=1e-6(workaround)pseudo_random, ppc 40, 8 cells (net charge 7.9e-2)stab_eps=1e-6resulttest_verif_VlasovAmpereOneSpeciesinitial solveAfter the fix
IdorM0, defaultstab_epsstab_eps=1e-6(that difference is the O(stab_eps) error of the workaround itself)test_verif_VlasovAmpereOneSpeciesinitial solveFix
New option
enforce_compatibility. It isTrueforPoissonSolveandFalseforImplicitDiffusionandPoissonAdiabaticGyrokinetic, where the mass term is physical. When it is on and the operator is singular (no Dirichlet BCs and no polar splines, seeImplicitDiffusion.operator_is_singular), the rhs is made to satisfy the discrete compatibility condition1^T b = 0before the solve:M0 1is the weak form of a uniform density, so this adds a uniform neutralizing background. A periodic plasma is quasi-neutral, and the net Monte-Carlo charge is noise that must be discarded.phistays O(1).stab_epsnow only fixes the constant ofphi, which is harmless, so its default is unchanged. Withstab_mat="M0"the projection changesphionly by a constant for anystab_eps, soEis the same; the new test checks this.inner, which is a global MPI reduction, andmul_iadd), with1andM0 1precomputed inallocate. There are no host copies, so it should work on both cunumpy backends. The CuPy path is untested.test_poisson_2d_multigrid(periodic, unpreconditioned) it now takes 97 iterations instead of 142.Tests
test_poisson_net_charge_periodic_1d[Id|M0](about 1 s). It uses a non-neutral analytic source with default options and checks:phiis O(1) and matches the exact solution up to a constant;enforce_compatibility=False,|phi| > 1e10;M0with finitestab_eps, the projection only shiftsphiby a constant.test_poisson_dirichlet_not_singular: with Dirichlet BCs the rhs is left unchanged.mpirun -n 2.test_poisson.pybefore the multigrid ones;test_poisson_2d_multigrid[periodic-degree0](about 3 min per run, so the rest of the multigrid set is left to CI);test_implicit_diffusion_multigrid_dt; the 24test_poisson_M1perp_1dcases intest_gyrokinetic_poisson.py;test_verif_VlasovAmpereOneSpecies.py(48 s).🤖 Generated with Claude Code