Skip to content

feat(pic1d): add 1D electrostatic PIC solver#276

Merged
joglekara merged 3 commits into
mainfrom
feat/pic1d
May 20, 2026
Merged

feat(pic1d): add 1D electrostatic PIC solver#276
joglekara merged 3 commits into
mainfrom
feat/pic1d

Conversation

@joglekara
Copy link
Copy Markdown
Member

@joglekara joglekara commented May 20, 2026

Summary

New solver: pic-1d that reuses Vlasov-1D's input deck (units, density profiles, drivers, save schema) so PIC and Vlasov can be compared on the same configs. Adds particle-specific knobs grid.ppc, grid.particle_shape, terms.time, and per-species loading.

Solver

  • B-spline (linear / tsc / cubic) deposit & gather, spectral Poisson on the Vlasov grid, KDK leapfrog + 4th-order Yoshida symplectic compositions.
  • PIC1DVectorField wraps it for diffrax with the same dummy Euler Stepper Vlasov-1D uses.
  • Transverse light wave: when drivers.ey is configured, the same step also advances a transverse vector potential a(x) via the Vlasov-1D wave solver (with the matching 2nd-order ABC), evaluates the TransverseCurrentSourceDriver source (extended or point), and adds the ponderomotive force F_pond = -½ ∂_x(a²) to each species' kick. Particles remain 1D1V. Pure-ES runs (empty ey) skip the wave solve entirely.
  • Quasineutrality: density.quasineutrality: true auto-balances the ion background as -Σ_s q_s n_s, so multi-species electron-only setups (e.g. two cold beams) work without manual ion configuration.

Post-process

  • Storage saves nested per-species moments {n, j, P} computed via the same deposit kernel as the field solver, plus shared e, de, a, prev_a, pond.
  • Plot tree mirrors Vlasov-1D: linear + log10 spacetime and facet lineouts per field, plots/fields/<species>/… and plots/scalars/<species>/… subtrees, and ep/em decomposition when an ey driver is configured.
  • Dist saves write raw particle (x, v) snapshots and phase-space scatter plots (no histogram binning into f).

Tests (tests/test_pic1d/)

  • test_two_stream — seeded cold counter-streaming beams, log-linear fit of γ against ωp/(2√2) for TSC and cubic shapes (~2 s).
  • test_bohm_gross — quietly-loaded Maxwellian at k=0.3, free oscillation, time-FFT peak ω vs the exact kinetic Langmuir dispersion (real root of Re ε via the plasma dispersion function) for both leapfrog and yoshida4 (~3 s).
  • test_landau_damping — driver + noise-subtraction at 1M PPC; marked slow (~6 min wall clock) with factor-of-2 tolerance on the Landau rate.

Configs

  • configs/pic-1d/epw.yaml — direct port of the Vlasov-1D EPW config.
  • configs/pic-1d/two-stream.yaml — cold equal-beam two-stream setup.

Lint

  • Extends ruff.toml's allowed-confusables list with , ×, γ so physics-notation docstrings/assertions pass RUF001/RUF002.

Test plan

  • uv run pytest tests/test_pic1d/test_two_stream.py tests/test_pic1d/test_bohm_gross.py
  • uv run pre-commit run --files <changed files>
  • uv run run.py --cfg configs/pic-1d/epw.yaml (full lifecycle through ergoExo + post-process tree)
  • uv run run.py --cfg configs/pic-1d/two-stream.yaml
  • uv run pytest tests/test_pic1d/test_landau_damping.py -m slow (long; verified the underlying 1M-PPC run manually but not under pytest yet)

🤖 Generated with Claude Code

joglekara and others added 3 commits May 19, 2026 20:34
New ``solver: pic-1d`` module that reuses Vlasov-1D's input deck (units,
density profiles, ex driver, save schema) so PIC and Vlasov can be compared
on the same configs. Drops the Vlasov-only physics (Fokker-Planck, Krook,
transverse light wave); adds particle-specific knobs ``grid.ppc``,
``grid.particle_shape``, ``terms.time``, and per-species ``loading``.

Solver bits
- B-spline shape functions ``linear`` / ``tsc`` / ``cubic`` for deposit and
  gather (``solvers/pushers/shape.py``).
- Spectral Poisson on the same grid as Vlasov-1D and the same ex driver
  evaluation (``solvers/pushers/field.py``).
- KDK leapfrog + 4th-order Yoshida symplectic compositions
  (``solvers/pushers/push.py``).
- ``PIC1DVectorField`` wraps it all and is steppable by diffrax through the
  same dummy Euler ``Stepper`` Vlasov-1D uses; optional ponderomotive force
  from a transverse vector potential is wired up but inert for pure-ES runs.

Quasineutrality
- ``density.quasineutrality: true`` now auto-balances the ion background as
  ``-Σ_s q_s n_s`` so multi-species electron-only setups (e.g. two cold beams)
  work without manual ion configuration.

Post-process
- Storage saves nested per-species moments {n, j, P} computed via the same
  deposit kernel as the field solver, plus shared E, dE, a, prev_a, pond.
- Post-process layout mirrors Vlasov-1D: linear + log10 spacetime plots and
  facet lineouts per field, per-species subdirs under plots/fields/<sp>/ and
  plots/scalars/<sp>/, and ep/em decomposition when an ey driver is
  configured.
- Dist saves write raw particle (x, v) snapshots and phase-space scatter
  plots (no histogram binning into f).

Tests (tests/test_pic1d/)
- ``test_two_stream`` — seeded cold counter-streaming beams, log-linear fit
  of γ for TSC and cubic shapes against the analytic cold growth rate
  ωp/(2√2). Runs in seconds.
- ``test_bohm_gross`` — quietly-loaded Maxwellian at k=0.3, free oscillation,
  time-FFT peak ω compared to the exact kinetic Langmuir dispersion (root of
  Re ε via the plasma dispersion function) for both leapfrog and yoshida4.
- ``test_landau_damping`` — driver + noise-subtraction at 1M PPC; marked
  ``slow`` (~6 min wall clock) with factor-of-2 tolerance on the Landau rate.

Configs
- ``configs/pic-1d/epw.yaml`` — direct port of the Vlasov-1D EPW config.
- ``configs/pic-1d/two-stream.yaml`` — cold equal-beam two-stream setup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-commit reformatted the PIC tests / helpers for consistent style and
flagged several ambiguous-unicode characters used in physics docstrings.
Extends ``ruff.toml``'s ``allowed-confusables`` list with ``−``, ``×``, and
``γ`` so we can keep notation like ``γ = -√(π/8)·…`` and ``1M PPC × 32``
verbatim in docs and assertion messages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Runs ``pytest tests/test_pic1d`` on every PR / push to main, matching the
per-module job layout used for the other solvers. Default pytest config
excludes the ``slow`` marker so only the fast suite (two-stream growth rate
+ EPW kinetic dispersion) runs in CI; the 1M-PPC Landau damping test stays
opt-in via ``-m slow``.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@joglekara joglekara merged commit e5fde4b into main May 20, 2026
7 of 8 checks passed
@joglekara joglekara deleted the feat/pic1d branch May 20, 2026 03:44
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