Skip to content

Integration pin: #44 + #24 + #12 + #17 (+#9), no new code - #47

Closed
rogeriojorge wants to merge 23 commits into
agent/autodiff-planfrom
agent/psp-chirp
Closed

rogeriojorge wants to merge 23 commits into
agent/autodiff-planfrom
agent/psp-chirp

Conversation

@rogeriojorge

@rogeriojorge rogeriojorge commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Integration branch. Do not merge. This PR is a pin target, not a feature.

This branch combines the unchanged commits of four open PRs:

The merge commit a7ca601 (tree 4e1ad06) is the SPECTRAX version pinned by the Parker Solar Probe chirp study. That study now lives in a separate repository.

Why both #44 and #24 are needed:

No other open PR contains both.

Checks at a7ca601:

  • All 17 existing tests pass.

  • Linear three-Maxwellian ion-acoustic growth rates match independent full-kinetic roots when the high-Hermite sink is ν ≈ 1 ω_pe:

    Hermite modes Growth-rate error
    128 within 0.7%
    256 within 2×10⁻⁶ ω_pc

The last commit on this branch only removes the study files, so the branch tree is identical to a7ca601. When #44 and #24 are in main, close this PR and move the study's pin to main.

rogeriojorge and others added 22 commits July 12, 2026 22:07
…ang inverse-design example

simulation: expose max_steps, adjoint and progress_meter, with Diffrax's
checkpointed discrete adjoint as the default so jax.grad/jvp/vjp compose
with any real scalar of the output. diagnostics: real-valued kinetic
energies. Tests check reverse = forward = finite differences on the
adaptive Dopri8 path, invariance to the checkpoint budget, a reverse-pass
workspace that does not grow with the step count, and a current-density
functional through plasma_current. The example optimises the initial
in-plane magnetic field of the Orszag-Tang vortex for magnetic-energy
conversion or current-sheet intensity and benchmarks gradient cost and
memory against finite differences.
…ang example

validate re-evaluates the frozen initial and optimised controls of an
optimize report at other resolutions and ODE tolerances, with the
total-energy error. --fixed-amplitudes optimises phases only, so every
mode energy stays fixed. Every report records commit, package versions
and device. The objective panel plots accepted L-BFGS iterates over the
line-search trials, and panel (d) adds the peak-current trace.
--tolerances now sets the Dopri8 tolerance for optimize and benchmark
(first value) as well as the validate sweep. Shorter panel (d) title and
no trailing separator when a report has no device recorded.
A long run imports the example once; recording the commit when the
report is written can name a later checkout than the code that ran.
One RTX A4000, float64: a gradient costs about 6.5 forward solves for 4
to 64 parameters; with 8 checkpoints its peak memory is 2.8-2.9x a
forward solve up to 128^2x6^3, and its workspace is flat in the number
of time steps.
Label the log x-axes at the measured values only, and alternate the
resolution labels below and above the workspace curves.
Labels below the forward curve crossed it and the left spine; above the
top curve, at alternating heights, they cross nothing.
Left-align the leftmost label so it does not touch the spine, and show
CPU instead of JAX's internal device name for reports written before
provenance was recorded.
The example gains a mean_conversion objective averaged over --snapshots
saved states and a sensitivity mode: forward-mode (ForwardMode, jacfwd)
logarithmic derivatives of every objective with respect to collision
frequency, mass ratio, guide field and in-plane amplitude at the initial
and optimised controls of an optimize report, checked against centred
differences, with a figure. setup takes these parameters; solve accepts
an adjoint override. A test checks the gradient of a time-averaged
objective against finite differences. No library change.
The scientific offset label collided with the axis label.
orszag_tang_control.py holds the shared control problem (setup, solve,
objectives). 2D_Orszag_Tang_optimization.py optimises and optionally
validates at other resolutions, 2D_Orszag_Tang_sensitivity.py computes
forward-mode sensitivities to physical parameters, and
2D_Orszag_Tang_gradient_benchmark.py measures gradient cost and memory.
Each writes a JSON report and its figure. Outputs match the previous
single script on the same settings.
The helper now owns the plotting style, report writing and figure
saving, and records only commit, device type and JAX version. The four
files total fewer lines than the former single script, with identical
outputs.
Restore README.md to main; the usage is in the example scripts'
docstrings.
…study

Reused unchanged from uwplasma/SPECTRAX PR #24; see that PR for its tests and rationale.
Reused unchanged from uwplasma/SPECTRAX PR #12; see that PR for its tests and rationale.
…hirp study

Reused unchanged from uwplasma/SPECTRAX PR #17 (includes #9); see that PR for its tests and rationale.
Example-local units, free-streaming Gaussian proton pulse initializer built on compute_C_nmp, parallel moments, Gauss residual, continuous probe, finite-baseline antenna voltage, fixed-window spectrogram, and an independent Faddeeva kinetic dispersion root. No library changes.
@rogeriojorge

Copy link
Copy Markdown
Member Author

Collisionless PIC cross-check with JAX-in-Cell: review and plan (no runs yet)

Why this is worth doing

SPECTRAX matches the independent full-kinetic linear roots only with a strong high-Hermite sink, ν ≈ 1 ω_pe; see the G2 update in the description. In linear theory this is harmless, because the sink stands in for the electron Landau resonance, which sits deep inside the truncated electron Hermite spectrum (ζ_e ≈ 0.02). In the nonlinear phase it may not be harmless.

The concern. SPECTRAX has one ν for all populations. The damping it applies to Hermite mode n is ν n³/H³. For protons at H = 128 and n ≈ 40, that is about 0.03 ω_pe, or about 1.4 ω_pc, far above the growth rates of about 0.016 ω_pc.

Why it matters. Proton trapping at saturation creates velocity structure of width v_tr/σ_c = 2(eφ/T_c)^½. That width maps onto exactly those Hermite orders. Saturation level, trapping, phase-space holes and the late-time chirp could therefore be set by the numerical closure rather than by the physics.

The test. A collisionless particle-in-cell (PIC) run has no Hermite truncation and no sink. It is the right independent check of the nonlinear (M2) results, which the kinetic roots cannot supply.

Review of JAX-in-Cell at research-release f42e265 (PR uwplasma/JAX-in-Cell#42, unmerged)

  • Fit for this study:
    • The code is 1D3V, electrostatic or electromagnetic, with any number of Species and SI units.
    • Its vth = sqrt(2kT/m) equals SPECTRAX's α·c exactly.
    • Species(x=..., v=...) accepts arbitrary (n, 3) phase-space arrays. The free-streamed Gaussian pulse can therefore be loaded exactly: sample the age-0 Gaussian in (x, v), then set x ← x + v·a. This needs no library change, and the per-species particle count sets the resolution of the weak beam independently of the core.
    • Collisions are off unless configured.
    • Charge-conserving current deposition keeps the discrete Gauss law.
    • quiet_start and displacement seeding give a controllable noise floor.
    • run(store_every=k, store_particles=False) stores gridded E only, so a probe trace is cheap.
    • jax.vmap over seed gives an ensemble in one compilation.
  • Conventions to match or record:
    • Mean field. Solver(model="electrostatic") forces ⟨E⟩ = 0 in a periodic box. The electromagnetic path with field_solver="ampere" evolves ⟨E⟩ from the mean particle current, as SPECTRAX does (dE₀/dt = −J₀). Use the Ampère path, and record E₀ in both codes.
    • Resolution. The quadratic shape needs Δx ≲ λ_De to avoid finite-grid heating. The time step needs ω_pe Δt ≤ 0.2, and in the electrostatic limit a Courant number above 1 is allowed.
    • Filtering. Use filter_passes=0 for growth rates, or report the compensated-filter response at the resonant k.
    • Noise. PIC noise acts as an extra seed. The seed must dominate the quiet-start noise floor, and several seed amplitudes must bracket the linear window.
  • Not in scope:
    • PIC gradients over long, chaotic runs; the gradient checks (G4) stay with SPECTRAX.
    • Any change to either repository. The PIC driver scripts live in ~/local/spectrax-psp-chirp/scripts/, pinned to f42e265. A JAX-in-Cell example PR can be considered separately later.

Proposed gate G3-PIC, after G2 and before any M2 claim

  1. P1, homogeneous benchmark, linear. The same three plan cases plus the T_b/T_c = 16 stable control, at M = 1836 and a cheaper M = 100.
    • Settings: L = 60 λ_Dc, Nx = 64 (Δx ≈ 0.3 λ_De), ω_pe Δt = 0.2, quiet start, 10⁶ particles per species, and a beam-drift or displacement seed at k₁ with 3 amplitudes.
    • Pass criterion: γ within 1% of the full-kinetic root (and of SPECTRAX at ν = 1, H = 128), fitted over an explicitly chosen linear window.
  2. P2, homogeneous benchmark, nonlinear. This is the decisive test. Run to saturation and past it.
    • Compare with SPECTRAX at ν ∈ {0.3, 1, 3} and H ∈ {128, 256}: the saturation amplitude |E_k1|max, the time of saturation, the bounce frequency, the phase-space trapping width, the proton parallel-variance change including the w(1−w)ΔU² term, and the energy budget.
    • Pass criterion: SPECTRAX within the PIC ensemble spread, from 4 seeds, and independent of ν in its plateau. If it fails, the M2 claims must be limited to the linear or early nonlinear window, or ν must be lowered with H raised. That is a stop condition, not a tuning knob.
  3. P3, the Gaussian-pulse pilot. Use the same initial state as the SPECTRAX M2 pilot from next step 4: exact particle sampling and the same seed spectrum through displacement.
    • Compare the synthetic probe trace, the spectrogram ridge (slope and frequency range), the envelope and the growth history along the trajectory.
    • Pass criterion: ridge slope and frequency within the observational uncertainty (about 7% on the slope), and the envelope within the PIC ensemble spread.

Cost, estimated only (office A4000, float64, about 11 ns per particle-step from the JAX-in-Cell #42 profile)

Run Particles Steps Estimated time per seed
P1/P2, M = 1836 (to 2× saturation) 3×10⁶ about 3×10⁵ about 3 h
P1/P2, M = 100 3×10⁶ about 7×10⁴ about 40 min
P3 pilot (L ≈ 2 km, Nx = 512) about 1.5×10⁶ about 10⁵ about 30 min

That is roughly one to two days of GPU time for the full gate with 4-seed ensembles. Run M = 100 first. If P2 already shows the sink bias there, M = 1836 is confirmation only. Wait for an idle card, because other users' jobs distort timing, and check the office disk (it was nearly full on 2026-09-13).

Deliverables, local only

  • scripts/pic_benchmark.py: P1 and P2.
  • scripts/pic_pulse.py: P3.
  • runs/pic_*: manifests with the commit, seed, particle counts, Δt, Δx, filter settings, E₀ history and energy error.
  • One comparison figure for the research note: the growth and saturation history, SPECTRAX at three values of ν against the PIC ensemble band, plus phase-space snapshots.

The study scripts now live in a separate repository pinned to a7ca601. This branch keeps only the unchanged merges of #44, #24, #12 and #17 (with #9).
@rogeriojorge rogeriojorge changed the title PSP chirp study: impulsive-proton model helpers, G0–G2 progress (draft, paused) Integration pin: #44 + #24 + #12 + #17 (+#9), no new code Sep 23, 2026
@rogeriojorge

Copy link
Copy Markdown
Member Author

The study code moved out of SPECTRAX; this branch now only integrates #44, #24, #12 and #17 (+#9). The earlier description and comments above describe the study as it was at the pause; its handoff continues in the separate study repository.

@rogeriojorge

Copy link
Copy Markdown
Member Author

Integration pin with no new code; its parts are reviewed individually in #9, #12, #51 (replaces #24) and #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