Skip to content

Hybrid-PIC: checkpoint the electron temperature under the electron energy equation - #7238

Open
clarkse-he wants to merge 1 commit into
BLAST-WarpX:developmentfrom
Helion-Energy:hybrid_checkpoint_electron_temperature
Open

Hybrid-PIC: checkpoint the electron temperature under the electron energy equation#7238
clarkse-he wants to merge 1 commit into
BLAST-WarpX:developmentfrom
Helion-Energy:hybrid_checkpoint_electron_temperature

Conversation

@clarkse-he

@clarkse-he clarkse-he commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

The bug

With hybrid_pic_model.solve_electron_energy_equation = 1, the electron temperature
hybrid_electron_temperature_fp is the evolved state variable of the QDSMC
electron-energy equation — it carries the accumulated Joule heating, the Q_ei
equilibration and the advected entropy. It is not written to the checkpoint, so on
restart it is reconstructed from scratch twice over:

  1. HybridPICModel::InitData fills it with the uniform <hybrid>.elec_temp, and
  2. WarpX::HybridPICInitializeRhoJandB then overwrites it via
    CalculateElectronPressure(floor_density=true), the floored adiabat closure on the
    restored rho.

Every restart therefore silently discards the evolved electron thermal structure, with
no warning. A checkpointed run is not equivalent to an uninterrupted one, and the
divergence feeds straight back into the fields through Pe.

Source/FieldSolver/WarpXPushFieldsHybridPIC.cpp acknowledges this in a comment today
("T_e is not checkpointed either … evolved T_e structure is not preserved across a
restart"), but nothing warns the user at runtime.

Measured impact

On a 2D 48² Ohm's-law deck with the energy equation and Joule heating (checkpoint at
step 5, compared at step 10 — five steps of divergence), restart vs. uninterrupted,
relative max error:

field error
Te 9.1e-02
Ez 1.7e-01
Ex 5.6e-03
jx 6.4e-03
Bx 1.4e-04
rho 2.0e-05

With this PR the same pair is bit-identical (max 1.0e-16, roundoff).

The fix

  • Flag hybrid_electron_temperature_fp with checkpoint_restart when the energy
    equation is on
    . With the equation off it stays unflagged — there it is a pure
    diagnostic mirror of the closure, refilled every step, so checkpoints for the
    algebraic-closure path are unchanged.
  • ablastr::fields::MultiFabRegister::read_restarts now skips a flagged field whose
    file is absent from the checkpoint instead of aborting, and returns the names it
    actually read. This keeps older checkpoints restartable. It is also a latent fix
    independent of this PR: the pre-existing checkpoint_restart field in
    NuclearFusionFunc.H makes a checkpoint written without fusion unrestartable with
    fusion enabled today.
  • WarpX::InitFromCheckpoint sets m_te_restored_from_checkpoint when T_e came back on
    every level, and records a WarnPriority::high warning when the energy equation is on
    but the checkpoint has no T_e — in which case the adiabat re-seed still happens,
    exactly as before, so nothing regresses for existing checkpoints.
  • Both T_e seeds are skipped when that flag is set, and HybridPICInitializeRhoJandB
    emits Pe from the restored T_e via QDSMCFillElectronPressureFromTe (with the
    ApplyElectronPressureBoundary + FillBoundary treatment grad(Pe) needs) instead of
    re-seeding.

This is the electron-energy-equation companion to #7049, which fixed the rho/J/Pe half of
the same restart path.

Testing

Kept source-only to stay light; verified locally against a restart-equivalence deck (see
comment below). The pre-existing non-energy-equation restart pair is untouched and still
matches the stored benchmark test_2d_ohm_solver_checkpoint_picmi.json to 0.00e+00.

Happy to add a test_2d_ohm_solver_ee_checkpoint_picmi{,_restart} pair to
Examples/Tests/ohm_solver_restart if reviewers would like the coverage in CI.

@clarkse-he clarkse-he added bug Something isn't working bug: affects latest release Bug also exists in latest release version component: fluid-ohm Related to the Ohm's law solver (with fluid electrons) component: checkpoint/restart Checkpointing & restarts labels Sep 2, 2026
@clarkse-he
clarkse-he marked this pull request as ready for review September 2, 2026 23:17
…tion

With `hybrid_pic_model.solve_electron_energy_equation = 1`, the electron
temperature `hybrid_electron_temperature_fp` is the evolved state variable
of the QDSMC electron-energy equation: it carries the accumulated Joule
heating, Q_ei equilibration and advected entropy. It was not written to the
checkpoint, so on restart it was reconstructed twice from scratch --
`HybridPICModel::InitData` filled it with the uniform `elec_temp`, and
`WarpX::HybridPICInitializeRhoJandB` then overwrote it with the floored
adiabat closure on the restored rho. Every restart silently discarded the
evolved electron thermal structure, with no warning; a checkpointed run was
not equivalent to an uninterrupted one.

Measured on a 2D 48^2 Ohm's-law deck with Joule heating (10 steps,
checkpoint at step 5), the restarted run differed from the uninterrupted one
at step 10 by 9.1e-2 in Te, 1.7e-1 in Ez and 1.4e-4 in Bx -- five steps
after the checkpoint. With this change the same pair is bit-identical.

Fix:

* Flag `hybrid_electron_temperature_fp` with `checkpoint_restart` when the
  energy equation is on. With the equation off it stays unflagged: there it
  is a pure diagnostic mirror of the closure, refilled every step.
* `MultiFabRegister::read_restarts` now skips a flagged field whose file is
  absent from the checkpoint instead of aborting the restart, and returns
  the names it actually read. Without this, checkpoints written before a
  field was flagged become unrestartable -- which also applies to the
  pre-existing NuclearFusion `checkpoint_restart` field today.
* `WarpX::InitFromCheckpoint` sets `m_te_restored_from_checkpoint` when T_e
  came back on every level, and warns (WarnPriority::high) when the energy
  equation is on but the checkpoint has no T_e, in which case the adiabat
  re-seed still happens as before.
* Both T_e seeds are skipped when that flag is set, and
  `HybridPICInitializeRhoJandB` emits Pe from the restored T_e (with the
  same boundary treatment grad(Pe) needs) instead of re-seeding.

The pre-existing non-energy-equation restart pair is unchanged: its checksum
still matches the stored benchmark to 0.00e+00.
@clarkse-he
clarkse-he force-pushed the hybrid_checkpoint_electron_temperature branch from 765f1d4 to b218e6f Compare September 2, 2026 23:19
@clarkse-he

Copy link
Copy Markdown
Contributor Author

Verification, for the record — run locally rather than added to CI to keep this PR light.

I built a restart-equivalence deck alongside the existing ohm_solver_restart pair: same
grid, drive and restart-hostile ingredients (parsed analytic initial B, split-field
external vector potential with a time envelope, density floor), plus
solve_electron_energy_equation and include_joule_heating with
plasma_resistivity = 1e-3, so T_e reaches ~2.3× its seed value by the checkpoint step.
2D, 48², 10 steps, checkpoint at step 5, compared at step 10 — 2 MPI ranks,
OMP_NUM_THREADS=1, CPU/OMP build.

Before the fix, the restarted arm diverges from the uninterrupted one:

field  Bx: rel err = 1.417e-04
field  By: rel err = 1.543e-05
field  Bz: rel err = 1.823e-05
field  Ex: rel err = 5.600e-03
field  Ey: rel err = 3.843e-03
field  Ez: rel err = 1.680e-01
field  Te: rel err = 9.106e-02
field  jx: rel err = 6.381e-03
field  jy: rel err = 3.495e-05
field  jz: rel err = 1.834e-03
field rho: rel err = 2.012e-05

After the fix, analysis_default_restart.py passes at its 1e-12 tolerance — every
field is at roundoff:

field  Bx: 1.615e-17    field  Ey: 3.862e-17    field  jx: 0.0
field  By: 0.0          field  Ez: 1.036e-16    field  jy: 0.0
field  Bz: 0.0          field  Te: 1.043e-17    field  jz: 0.0
field  Ex: 3.005e-18                            field rho: 0.0

Also checked:

  • Backward compatibility. A build with this fix, restarted from a checkpoint written
    before it (no hybrid_electron_temperature_fp file), runs to completion and emits the
    expected high-priority warning — read_restarts skips the absent field rather than
    aborting.
  • No regression on the algebraic-closure path. The existing
    test_2d_ohm_solver_checkpoint_picmi pair still reproduces the stored benchmark at
    0.00e+00 max relative error, and its restart comparison is unchanged at roundoff.

The deck is a small variant of the existing inputs_test_2d_ohm_solver_checkpoint_picmi.py
and I can push it plus a benchmark JSON as a second commit if you'd rather have this
locked down in CI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug: affects latest release Bug also exists in latest release version bug Something isn't working component: checkpoint/restart Checkpointing & restarts component: fluid-ohm Related to the Ohm's law solver (with fluid electrons)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant