<claude-ish-text>
Summary
src/particles/spacecharge/PoissonSolve.cpp:153-157 unconditionally multiplies rho by -ε₀ on every level after ablastr::fields::computePhi returns. In the current ablastr, computePhi already restores rho to its original value on both the MLMG and IGF paths, so this post-loop overwrite is wrong.
Code
src/particles/spacecharge/PoissonSolve.cpp:153-157:
// fix side effect on rho from previous call
for (int lev=0; lev<=finest_level; lev++) {
using namespace ablastr::constant::SI;
rho[lev].mult(-1._rt * epsilon_0);
}
Details
In the current ablastr computePhi (warpx/Source/ablastr/fields/PoissonSolver.H), rho is symmetrically scaled and un-scaled on the MLMG path:
- Line 288 (entering MLMG):
rho[lev]->mult(-1._rt / ablastr::constant::SI::epsilon_0);
- Line 446 (after MLMG solve, still inside the per-level loop):
rho[lev]->mult(-ablastr::constant::SI::epsilon_0); // Multiply rho by epsilon again
The IGF path (PoissonSolver.H:277-284) continues before reaching either of those lines, so it never touches rho at all.
Net effect of computePhi on rho:
- IGF path: unchanged
- MLMG path: unchanged (scale and un-scale cancel exactly)
Then ImpactX runs the post-loop at PoissonSolve.cpp:153-157, which multiplies rho by -ε₀ on every level for both paths.
</claude-ish-text>
Reproducer
(boilerplate removed)
sim.track_particles() # one SC slice
R_post = gather(sim.rho(0)) # post-PoissonSolve state
sim.deposit_charge() # re-deposit on same geometry
R_redep = gather(sim.rho(0)) # clean reference
# elementwise ratio on cells with appreciable magnitude:
nz = abs(R_redep) > R_redep_max * 1e-6
median_ratio = numpy.median(R_post[nz] / R_redep[nz])
# observed: -8.854188e-12 (== -EPS0) on both fft and multigrid
Deleting PoissonSolve.cpp:153-157 seems ok
<claude-ish-text>Summary
src/particles/spacecharge/PoissonSolve.cpp:153-157unconditionally multipliesrhoby-ε₀on every level afterablastr::fields::computePhireturns. In the current ablastr,computePhialready restoresrhoto its original value on both the MLMG and IGF paths, so this post-loop overwrite is wrong.Code
src/particles/spacecharge/PoissonSolve.cpp:153-157:Details
In the current ablastr
computePhi(warpx/Source/ablastr/fields/PoissonSolver.H),rhois symmetrically scaled and un-scaled on the MLMG path:rho[lev]->mult(-1._rt / ablastr::constant::SI::epsilon_0);rho[lev]->mult(-ablastr::constant::SI::epsilon_0); // Multiply rho by epsilon againThe IGF path (
PoissonSolver.H:277-284)continues before reaching either of those lines, so it never touchesrhoat all.Net effect of
computePhionrho:Then ImpactX runs the post-loop at
PoissonSolve.cpp:153-157, which multipliesrhoby-ε₀on every level for both paths.</claude-ish-text>Reproducer
(boilerplate removed)
Deleting
PoissonSolve.cpp:153-157seems ok