Skip to content

feat: vlasov1d broadband laser driver + 1D super-Gaussian width normalization (vlasov1d & pic1d) - #337

Open
ManharGupta25 wants to merge 24 commits into
mainfrom
mg/vlasov-broadband
Open

ManharGupta25 wants to merge 24 commits into
mainfrom
mg/vlasov-broadband

Conversation

@ManharGupta25

@ManharGupta25 ManharGupta25 commented Aug 12, 2026 •

Copy link
Copy Markdown
Collaborator

Introducing the broadband changes and the alpha_1D fix for super-gaussian experiments in 1d solvers, mainly vlasov1d. broadband-driver lines plot for amplitude, log(amplitude) and phase are here as well. The additions for mean_e2 metrics and params will be in the existing kinetic-srs PR (https://github.com/ergodicio/kinetic-srs/pull/14)

Claude's detailed comment:

What this PR does

1. Broadband laser driver for vlasov1d (forward pass)

  • New BroadbandConfig / BroadbandDriver: the pump is a comb of num_colors discrete lines at dw_j = linspace(-delta_omega, +delta_omega, N) * w0, each an EMDriver with its own frequency offset and phase.
  • Amplitudes are sum-normalized: A_j = a0 * sqrt(I_j / sum_k I_k), so total power equals base_intensity regardless of N — and an N=1 broadband driver reduces exactly to the monochromatic driver.
  • intensities / phases blocks support init: uniform | random with a seeded RNG and an optional range (defaults: (0, 2) for intensity weights, (0, 2*pi) for phases, the Follett 2019 convention).
  • EMDriver gains phase / dw0; IntensityWavelengthDriverConfig and AKWDriverConfig gain dw0 / phase with 0.0 defaults, so existing monochromatic configs are unchanged.
  • Implementation notes: keyword case patterns (pydantic v2 defines no __match_args__), num_colors as int, driver params passed as a model_dump() dict so the driver stays grad-safe for a later backward pass.

2. 1D super-Gaussian width normalization

  • alpha = sqrt(Gamma(1/m) / Gamma(3/m)) in _initialize_supergaussian_distribution_: the realized variance equals T0/mass for every m, so a species labeled T0 is at temperature T0 for any order (temperature inflation F(m), the init-vs-operator convention split, and the Debye-length consequences).
  • Strict no-op at m=2 (both formulas give sqrt(2)): all Maxwellian configs, fixtures and tests unaffected.
  • Makes the initializer consistent with the Krook target (variance T0/mass) and SuperGaussianDougherty's temperature relation.
  • Restores x0 = lambda_D at all m, so k*lambda_D read from code coordinates is exact across an m-scan.
  • The _pic1d particle loader (both the inverse-CDF and rejection-sampling sites) gets the same one-line fix — no-op at m=2, so Maxwellian PIC runs are unchanged.
  • docs config.md m-row updated; verified <v^2>/T0 = 1.000000 for m in {2, 2.5, 3, 4, 5} in both the vlasov1d initializer and the pic1d pdf form.

3. Driver line-spectrum diagnostic in post_process

  • plots/drivers/{ex,ey}-lines.png: per-line intensity (linear + log10) and phase vs dw_j/w0, read from the live EMDriver objects rather than re-derived from config — so optimized line sets from a future backward pass plot with no extra wiring. Skips single-line drivers; wrapped in a guard so a plotting failure can never cost a completed solve its output.

4. Misc

  • Merged all the updates made to main branch before this. No conflict should be there.
  • Comment cleanup in solvers/pushers/field.py.

Validation

  • N=1 broadband ≡ monochromatic, bit-identical: every probe metric agrees to the last digit (e.g. probe_pump_fluence_at_left = 75.85687287627245 on both paths) — driver units, F0 scale and envelope handling confirmed clean.
  • Power bookkeeping: sum_j I_j = base_intensity by construction; CPU seed test: per-seed fluence within 0.88% of the monochromatic control, 3-seed mean within 0.21%.
  • Even-comb periodicity matches prediction: pulse-train recurrence measured 0.4080 ps vs 0.4098 ps predicted (autocorrelation 0.90).
  • Units sentinel post-merge (on the deployed install): x0(4 keV) = 4.942252 nm, x0(3 keV) = 4.280116 nm, v0 = sqrt(T0/m_e) — fix: Vlasov1d vth conventions #311 conventions intact; monochromatic configs load with dw0 = 0.0, phase = 0.0. The alpha change composes cleanly with the fix: Vlasov1d vth conventions #311 scheme: fix: Vlasov1d vth conventions #311 removed the global sqrt(2) from the unit definition, this removes the m-dependent F(m) from the initializer — together T_phys = T_label for all m.
  • alpha_1D: quadrature on the initializer's exact form gives <v^2>/T0 = 1.000000 for m in {2, 2.5, 3, 4, 5} with correct T0 scaling; test_super_gaussian_fp.py already builds its references with the 1D convention, so the operator tests double as corroboration.
  • In production: this branch powers the broadband SRS threshold campaign (multi-seed ensembles at L_n = 208/416 µm, 0.25/0.5% bandwidth, run on Perlmutter + Colab).

Not in this PR

  • Backward pass / optimization through BroadbandDriver (planned follow-up; the params-as-dict plumbing anticipates it).

@ManharGupta25 ManharGupta25 changed the title Mg/vlasov broadband feat: vlasov1d broadband laser driver + 1D super-Gaussian width normalization (vlasov1d & pic1d) Aug 12, 2026

@joglekara joglekara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work — the core of this is sound and the physics checks out. I checked the branch out, ran the suites, and exercised the broadband path directly. Two things need fixing before merge: one is an unrelated regression, one invalidates the headline validation claim. Everything else is cleanup or docs.

Blocking

1. FokkerPlanckConfig.m was deleted — collateral from a merge

adept/_vlasov1d/datamodel.py drops m: float = Field(default=2.0, ge=1.0), which c2e79e4 (#313, the super-Gaussian FP operator) added. It isn't mentioned in the PR description and disappeared in one of the three Merge branch 'main' commits, so I'm reading it as accidental.

It's silent rather than fatal — fokker_planck.py:329 reads the raw cfg dict, not the validated model, so type: super_gaussian runs still pick up m. But the ge=1.0 bound is gone (an m: 0.5 deck now validates), and the schema no longer documents the option. Should be a pure restore.

2. num_colors: 1 puts the line at -delta_omega * w0, not at w0

jnp.linspace(-Δ, Δ, 1) returns [-Δ], not [0]. Measured on this branch:

N=1: dw0/w0 = [-0.0025]
N=2: dw0/w0 = [-0.0025, 0.0025]
N=3: dw0/w0 = [-0.0025, 0.0, 0.0025]

So the N=1 reduction test isn't testing what the description claims. The amplitude half is genuinely bit-identical — I reproduced a0 = 0.06783401532993676 on both paths with x64 on, as _base_.py enforces — but the single line is red-shifted 0.25%, so this isn't the monochromatic driver.

That matters because the N=1 equivalence is the main evidence that the driver units and F0 scaling are right. Either special-case N == 1 to dw = 0, or re-run the comparison at delta_omega: 0 and restate the claim.

Should fix before merge

3. No config documentation

CLAUDE.md requires docs/source/solvers/vlasov1d/config.md updates for new config options. num_colors, delta_omega, intensities.{init,seed,range,base_intensity} and phases.{init,seed,range,base_phase} are all undocumented — the only doc change here is the m row.

4. delta_omega is a half-width but reads like a bandwidth

linspace(-Δ, +Δ, N) means the full width is 2Δ, and plot_driver_spectra labels 2Δ as "full width Δω/ω0". Someone writing delta_omega: 0.0025 for a "0.25% bandwidth" run gets 0.5%. The kinetic-srs notes already carry a translation table for exactly this (0.25% -> 0.00125), which is a good sign it's a real trip hazard. Worth stating explicitly in the docs, or renaming to half_width / switching the config to full width.

5. intensities: dict and phases: dict are unvalidated

Everything else in datamodel.py is a typed pydantic model. Here init: random without a seed raises a bare KeyError: 'seed' from inside the constructor, and base_intensity is required but undeclared. Two small BaseModels would turn both into proper validation errors.

6. scale_intensities / get_partition_spec / __call__ are unreachable, and two of them raise

I gather these are intended for the optimization follow-up, so this is about wiring rather than deletion. As written they can't be called from a built simulation: BroadbandDriver is a local inside EMDriver.from_config, only broadband_driver.driver_list escapes, and EMDriverSet stores list[EMDriver]. Nothing retains the instance — I checked kinetic-srs too (including mg/vlasov-broadband-and-sup-gauss); no Python there references these, and the campaign decks set only init/seed/base_intensity.

All three also fail if you do reach them. Calling them directly on a BroadbandDriver:

  • __call__ -> TypeError: unsupported operand type(s) for |: 'dict' and 'SpaceTimeEnvelopeFunction' (self.envelope is a module, not a dict)
  • get_partition_spec -> KeyError: 'learned'
  • scale_intensities -> KeyError: 'activation'

__call__ also re-applies jnp.tanh(phases) * jnp.pi to phases already drawn on (0, 2π), which contradicts what's baked into driver_list.

So whichever way you want to go: either keep a reference to the BroadbandDriver on EMDriverSet and fix the three methods now, or leave the methods with an explicit raise NotImplementedError until the backward-pass PR wires them. Right now they read as working API that silently isn't.

7. self.intensities holds amplitudes, not intensities

It's a0 * sqrt(w_j / Σw), and __call__ publishes it under the key "intensities". Worth renaming to amplitudes (keeping the raw weights separate if the optimizer wants them) before the optimization PR builds on the name.

8. No test and no example config

tests/test_vlasov1d/ gets only the EMDriver signature fix. Three cheap ones that would have caught #2:

  • uniform N-line comb -> Σ a_j² == a_mono² (this is exact today, I verified)
  • seeded reproducibility across two builds (also holds today)
  • N=1 comb sits at dw0 == 0

An example deck under configs/vlasov-1d/ would help too, since the kinetic-srs configs are gitignored and the YAML shape currently exists only in that repo's NOTES.md.

Minor

  • # %% cell markers left at datamodel.py:124 and :163
  • gamma_5_over_m in _vlasov1d/helpers.py is now unused (pic1d switched imports; vfp1d has its own)
  • match cfg.params has no case _: — a future params type would silently return None rather than raise
  • plot_driver_spectra hardcodes driver key "0" when reading base_intensity; a driver keyed '1' just loses the absolute axis scale (guarded, so cosmetic)

Physics — this part holds up

The alpha change is correct and I'd take it on its own. With α = sqrt(Γ(1/m)/Γ(3/m)) the variance is v_th² · (Γ(1/m)/Γ(3/m)) · (Γ(3/m)/Γ(1/m)) = T0/mass for every m. And SuperGaussianDougherty's D = β^(-2/m) Γ(3/m)/Γ(1/m) equals exactly that variance — so the initializer is now the operator's fixed point at the labeled temperature, which it wasn't before. vfp1d correctly keeps its own 3D-isotropic sqrt(3Γ(3/m)/(2Γ(5/m))), so configs/vfp-1d/epp-short.yaml (m: 3.4) is untouched. Config-regression and super-Gaussian FP suites pass, and the docs row is updated.

Three notes on it:

  1. It silently changes results for every m != 2 vlasov1d/pic1d run. No in-tree vlasov1d config uses m != 2, so nothing breaks here — but saved runs and in-flight m-scans are now on a different convention with no version marker. Same class of silent drift as #311. Worth a line in the PR description and wherever the m-scan results are recorded.

  2. All comb lines share k0. The source is -factor * ω_j² * a_j * sin(k0*x - ω_j*t + φ_j), so an off-center line isn't launched on its own dispersion branch. That's fine as used — the campaign decks drive through a width: 1.0um point source, where the phase error across the antenna is negligible. It stops being fine for a source extended across the box, where δk*L ~ 10 rad at 0.25% over 200 µm. Worth a docstring sentence noting the comb assumes a localized antenna.

  3. "Same power" is time-averaged, not peak. Σ a_j² = a0² exactly (verified), but a phase-locked comb reaches a0*√N at recurrence — consistent with the 0.408 ps recurrence you measured, and correct physics for a coherent sum. Just worth confirming the threshold campaign's "same intensity" control means the same thing on both sides of the comparison.


Blocking items are only #1 and #2, both small. Happy to look again as soon as those land.

@ManharGupta25

ManharGupta25 commented Aug 21, 2026 •

Copy link
Copy Markdown
Collaborator Author

Broadband driver injestion was changed from breaking it into separate EMDrivers in simulation.py to having the injestion being directly vectorized and array-based within field.py such that when complete optimization loop with loss calculation and training wrappers is added, gradient will be traceable back to the amplitudes and phases in transverse wave sources (or any other parameter of those sources which will require some specific plumbing for the given parameter). More importantly, the BroadbandDriver object now persists throughout the simulation as it is directly made part of EMDriverSet, and its the entire EMDriverSet that is stored in 'args'. Along with that, other concerns mentioned in the above PR comment were addressed as well, apart from #6, which will be addressed in a larger optimization-related PR.

Claude's detailed comment:


Points addressed — 4c45d6d + ea1a394

Everything is addressed except item #6 (deferred, see below). The driver was
also restructured beyond the review asks: broadband no longer expands into N
EMDrivers — it is now a single BroadbandDriver eqx.Module with (N,)
array leaves
(amplitudes, delta_omega, phases, raw intensity_weights),
retained on EMDriverSet.ey. The pusher reads drivers from args["drivers"]
(no silent fallback), computes point-source scales in-trace, and evaluates all
lines vectorized — so the line parameters are differentiable today
(test_gradients_flow_through_args_route: finite nonzero grads w.r.t.
amplitudes/phases, both source types). ea1a394 fixes a latent bug in
BaseVlasov1D.__call__'s trainable-module loop (state unbound, result unused).

Blocking:

  • #1 — FokkerPlanckConfig.m restored with ge=1.0.
  • #2 — num_colors: 1 special-cased to delta_omega = [0]. Claim restated on
    solid ground: test_single_line_is_monochromatic (evaluated source matches
    the mono driver, rtol 1e-12, both source types) and a full-solve control in
    kinetic-srs that reproduces the monochromatic run bitwise in every probe
    metric (on a machine verified bitwise run-to-run deterministic).

Should-fix:

  • #3 — config.md gains a broadband section: YAML example + full key table +
    how the lines are built.
  • #4 — kept the name, documented hard: half-width stated in docs + both
    docstrings with the "0.25% → 0.00125" example; spacing pinned by test.
  • #5 — intensities/phases are typed pydantic models; random-without-seed
    and missing base_intensity are ValidationErrors (tested).
  • #7 — renamed to amplitudes; raw weights kept as intensity_weights.
  • #8 — test_broadband_driver.py (8 cases: your three suggested tests +
    half-width, validation, gradient regression) and
    configs/vlasov-1d/srs-broadband.yaml.

Item #6 — deferred to a dedicated backward-pass PR, which will add
intensities.{learned, activation} / phases.learned, point
get_partition_spec at the raw leaves, fix __call__ (incl. dropping the
double tanh on phases), and add init_modules() so the driver enters the
now-fixed module loop. This PR already provides the retained instance, the
differentiable args route, and the loop fix.

Minors: # %% markers removed; case _: guard added; unused
gamma_5_over_m removed; plot_driver_spectra no longer hardcodes driver key
"0" and reads the array leaves.

Physics notes: (1) agreed on the silent m != 2 change — recorded in the
m-scan campaign notes (old alpha ran m=3/4 at ×1.240/×1.371 the labeled T_e),
isothermal rerun prepared, line going into the PR description; (2) shared-k0
/ localized-antenna caveat now in docstrings + docs; (3) time-averaged-vs-peak
documented and measured: N=8 comb fluence equals mono within 0.9%/seed
(mean +0.2%) while peak intensity is 2.7–3.9× — and the redesign reproduces the
pre-redesign validation matrix to a few ULP.

@ManharGupta25
ManharGupta25 marked this pull request as draft August 22, 2026 00:11
@ManharGupta25
ManharGupta25 marked this pull request as ready for review August 22, 2026 07:17

@ergodic-ludwig ergodic-ludwig Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous blockers on FokkerPlanckConfig.m and the N=1 frequency offset are fixed, and the added documentation/tests cover the main broadband behavior well. I reviewed the complete current diff at eb9447a80806eed8479191c33b41947ea356598d, ran the focused broadband/config suite locally (26 passed), and checked the current GitHub runs (vlasov1d, pic1d, pre-commit, and install all pass).

Two remaining validated-input paths produce runtime-invalid simulations, so I am requesting changes; see the inline comments:

  1. intensities.range can generate invalid weights and silently introduce NaNs into amplitudes.
  2. The schema accepts a broadband driver under drivers.ex, but the longitudinal evaluator crashes on that object.

Both should be rejected during config validation (unless broadband Ex is intentionally implemented).

Comment thread adept/_vlasov1d/datamodel.py
Comment thread adept/_vlasov1d/simulation.py

@ergodic-ludwig ergodic-ludwig Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the complete diff at 95a55159af281094bad498c1617b94d34cc20bfe. Two high-confidence blockers previously identified are still present in this head:

  1. BroadbandIntensitiesConfig.range accepts negative and all-zero ranges. BroadbandDriver then evaluates sqrt(weight / sum(weights)), so validated decks can construct NaN amplitudes and silently contaminate a solve. Reject invalid bounds/realized weights and cover mixed-sign and all-zero cases.
  2. The shared schema still accepts BroadbandConfig under drivers.ex, and EMDriverSet.from_config stores that BroadbandDriver in ex; the longitudinal evaluator expects scalar EMDriver attributes such as dw0, so this validated configuration fails at runtime. Reject broadband Ex during validation or implement longitudinal broadband evaluation.

The latest merge does not address either path, so both should be fixed before merge.

@ergodic-ludwig ergodic-ludwig Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The broadband implementation has one blocking normalization defect: preserving sum(a_j²) does not preserve the configured physical laser intensity when line frequencies differ, because physical field intensity scales with (w_j a_j)². Details and a concrete regression criterion are inline.

Comment thread adept/_vlasov1d/simulation.py

@ergodic-ludwig ergodic-ludwig Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One blocking test-suite regression remains at d18d244d166ef13f01724aed0149a776e6a4f89f: the updated absorbing-wave test references eqx without importing it, causing collection to fail. The previously reported broadband validation and physical-power issues are addressed in this head.

Comment thread tests/test_vlasov1d/test_absorbing_wave.py Outdated

@ergodic-ludwig ergodic-ludwig Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of ba9dea961a06cee2119137fea430abd81b0fdb37

Verdict: changes requested for two remaining P2 input-contract issues. The earlier blockers are fixed; these are separate cases found during this pass, not a reopening of the resolved findings.

Fix before merge

  1. Zero-bandwidth multi-line comb: the schema accepts N > 1 with delta_omega: 0. Coincident-frequency lines sum coherently, so diagonal line-power normalization does not preserve total intensity. The four-line, equal-phase case gives 2x the source amplitude / 4x its squared amplitude at the same base_intensity. Reject that combination or handle the coherent normalization explicitly.
  2. Scalar Ex phase is ignored: phase is now an accepted and stored driver parameter, but the longitudinal evaluator never uses it. A validated phase change from 0 to pi/2 produces identical Ex. Implement the phase or reject nonzero Ex phase.

Both have independently executed failing reviewer-authored regressions on this exact head; details and fixes are inline. Neither finding invalidates the normal finite-bandwidth Ey campaign configuration.

Verified good

  • Previous fixes: FokkerPlanckConfig.m, N=1 centered frequency, invalid intensity ranges, broadband-Ex rejection, frequency-weighted physical line powers, and absorbing-wave test collection/execution.
  • 65 repository tests passed locally, using the frozen uv.lock, CPU JAX and x64: broadband, absorbing wave, super-Gaussian FP, PIC1D, config validation, units, multispecies/quasineutral initialization, and architecture solver-builder tests. One slow case was deselected by the repository's default marker. git diff --check is clean.
  • Independent per-line source sums agree with both point and extended evaluators; phase gradients agree with finite differences.
  • Direct production-initializer moment checks at m = 2, 2.5, 3, 4, 5 confirm the Vlasov variance is T0/mass on a sufficiently wide/resolved grid. Both PIC loading paths agree within deterministic quadrature / sampling error. The super-Gaussian width correction is sound. These checks exercise the changed initializers, rather than relying only on the FP suite's separately constructed reference distributions.
  • A reduced four-color deck completed the production BaseVlasov1D initialization-and-solve lifecycle: 101 steps, all 24 saved arrays finite, including the partial-args route.
  • Current GitHub Vlasov1D and PIC1D checks are successful. I did not rerun the full production SRS campaign or validate its recorded fluence metrics.

Nonblocking cleanup

  • The spectrum diagnostic pools multiple drivers but scales them to only the first driver's intensity; it also counts driver objects rather than spectral lines. Reproduced separately; details inline.
  • Refresh the PR description's old amplitude formula/object-expansion wording. In the new docs/docstrings, use different symbols for intensity weights and line frequencies instead of w_j for both. Backward-pass/optimization support remains explicitly outside this review's acceptance scope.

"""

num_colors: int = Field(ge=1)
delta_omega: float = Field(ge=0.0, lt=1.0) # half-width, fraction of w0; < 1 keeps every line frequency positive

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 — Reject zero-width multi-line combs, or normalize their coherent sum. delta_omega: 0 is accepted with num_colors > 1, so all lines have exactly the same frequency. The new frequency-weighted normalization correctly fixes distinct-line powers, but sum_j (omega_j a_j)^2 is not the total power when frequencies coincide: cross terms never average away. On this head I built num_colors: 4, delta_omega: 0, uniform intensity weights, and phases: {init: uniform, base_phase: 0}. At identical base_intensity, the evaluated point source is exactly 2 times the monochromatic source, with squared amplitude 4 times the control; this persists in time, rather than being a finite-bandwidth recurrence peak. Thus a zero-bandwidth control silently changes pump strength. The smallest fix is a model-level check rejecting num_colors > 1 and delta_omega == 0 and directing users to num_colors: 1. Alternatively combine/normalize equal-frequency complex amplitudes, with an explicit policy for cancellation. Add a regression using the evaluated coherent source, not only the diagonal per-line power sum.

k0: float | None = None
w0: float | None = None
dw0: float
phase: float = 0.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 — Honor the newly accepted scalar phase for Ex, or reject it there. AKWDriverConfig now explicitly accepts phase, the same schema is used under drivers.ex, and EMDriver.from_config retains it. However LongitudinalElectricFieldDriver._single_driver_field (solvers/pushers/field.py:22–27) still evaluates sin(k0*x - (w0 + dw0)*t) without driver.phase. I reproduced this through EMDriverSetConfig and EMDriverSet.from_config: changing a valid Ex deck from phase: 0 to phase: pi/2 produces exactly identical fields, rather than the requested phase shift. This can silently invalidate relative-phase forcing experiments. Please include + driver.phase in the longitudinal evaluator, or reject nonzero Ex phase if the new option is deliberately Ey-only; add a test against the analytic phase-shifted source. The same issue affects the new phase field in IntensityWavelengthDriverConfig.

ints = ((dcfg or {}).get("params", {}) or {}).get("intensities")
if isinstance(ints, dict) and ints.get("base_intensity") is not None:
base = ints["base_intensity"]
break

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nonblocking diagnostic follow-up — don't pool multiple drivers under the first intensity. All lines from the field are concatenated and normalized together, but their absolute scale is taken from only the first broadband entry. I exercised two four-line combs at the same carrier with disjoint frequency sets (delta_omega 0.0025 and 0.00125), each at 2.378e14 W/cm^2: matplotlib received eight intensities summing to 2.378e14, rather than 4.756e14 W/cm^2. The title also says 2 lines because it uses len(dlist) instead of the flattened line count. Plot each configured driver separately or retain per-driver normalization while combining; if carriers differ, retain actual omega_j too, since (1 + dw/w0)^2 * a^2 drops different factors of w0^2. This does not affect the single-comb forward solve.

@ergodic-ludwig

Copy link
Copy Markdown

Re-review complete at ba9dea9: full review and inline findings.

  • All previous blockers are fixed; the super-Gaussian normalization checks out.
  • 65 repository tests passed locally, plus independent initializer/source/gradient checks and a finite-output reduced broadband solve. Current Vlasov1D/PIC1D CI is green.
  • Changes requested for two reproduced P2 cases: zero-width multi-line combs violate the intensity contract, and the newly accepted scalar Ex phase is ignored. Both can be handled with small implementation/validation changes and regressions.
  • Multi-driver spectrum scaling/counting is a separate nonblocking diagnostic follow-up. These findings do not invalidate the normal finite-bandwidth Ey campaign configuration; I did not rerun that campaign.

@ergodic-reviewer ergodic-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the complete diff at f43e172ca5128e065f11b1b9d02c8f4fb589d62f. Changes are still required:

  • P2 — New import-boundary regression: importing the explicit Vlasov1D builder now loads plotting and patches MLflow process-wide. See the new inline comment.
  • P2 — Zero-width multi-line combs remain accepted: BroadbandConfig allows num_colors > 1 with delta_omega == 0, while BroadbandDriver normalizes separate line powers and the pusher sums coincident lines coherently. A zero-bandwidth control therefore need not preserve base_intensity. Reject this combination or normalize the coherent sum (existing finding).
  • P2 — Scalar Ex phase remains ignored: the schema and EMDriver.from_config retain phase, but LongitudinalElectricFieldDriver._single_driver_field never uses it, silently invalidating relative-phase forcing. Implement it or reject nonzero Ex phase (existing finding).

Postprocessing: the single-comb workflow has a reachable line-spectrum plot and existing field/moment/distribution plots, mean_e2, netCDF output, and MLflow artifact export. The explicit analyzer provides datasets without plotting. Existing diagnostics also cover the changed Vlasov/PIC distribution widths. The previously noted multi-driver spectrum scaling issue remains nonblocking.

Static code/test inspection only; I did not execute tests, postprocessing, or campaign validation.

Comment thread adept/_vlasov1d/helpers.py Outdated
from adept.normalization import UREG, PlasmaNormalization, normalize

from .. import patched_mlflow as mlflow

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 — Keep tracking and plotting imports out of shared preparation. adept._vlasov1d.builder imports preparation, which imports this module for _initialize_total_distribution_. The new module-level patched_mlflow import therefore loads MLflow and immediately rewrites its REST endpoint mappings (adept/patched_mlflow.py), even when a caller only resolves/prepares the logging-free solver and never requests tracking. The new module-level matplotlib.pyplot import likewise loads plotting on that path. This breaks the established boundary checked by tests/test_vlasov1d/test_builder.py::test_builder_import_does_not_load_tracking_or_plotting_facades, and can change an embedding application's MLflow behavior without opting in. Remove the unused global MLflow import (the existing local import in post_process is sufficient) and import pyplot locally inside plot_driver_spectra, as post_process already does. This is a code-path finding; I have not run the test.

@ergodic-reviewer ergodic-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the complete diff at 193b7ac645bc5d60cf18795bb1e63a696457d245. The tracking/plotting import-boundary finding is addressed: pyplot and patched MLflow are now imported only inside diagnostic functions.

Two existing P2 blockers remain; linking their inline discussions rather than duplicating them:

  • Zero-width multi-line combs: BroadbandConfig still accepts num_colors > 1 with delta_omega == 0. BroadbandDriver normalizes separate line powers, but TransverseCurrentSourceDriver sums these coincident-frequency sources coherently. Their interference does not average away, so a zero-bandwidth control can silently change pump intensity despite unchanged base_intensity. Reject this combination and direct users to one line, or normalize the coherent sum (inline finding).
  • Ignored scalar Ex phase: both scalar parameter schemas accept phase, and EMDriver.from_config stores it, but LongitudinalElectricFieldDriver._single_driver_field still omits it from the sinusoid. Relative-phase forcing therefore runs with the wrong field without reporting an error. Apply the phase in the longitudinal evaluator or reject nonzero Ex phase (inline finding).

Postprocessing: the single-comb workflow has a reachable spectrum plot, field/wave-decomposition and distribution/moment diagnostics, mean_e2, netCDF persistence, and MLflow artifact export. Existing moment/distribution diagnostics also cover the Vlasov/PIC width change. The explicit analyzer provides datasets without plotting. The previously reported multi-driver spectrum scaling issue remains nonblocking.

Static code and test inspection only; I did not execute tests, postprocessing, or the reported campaign validation.

@ergodic-reviewer ergodic-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the complete diff and relevant call sites/tests at cd588718275481564b61ce91ae7e0974dd090cc2. Two existing P2 blockers remain; linking their inline discussions rather than duplicating them:

  • Zero-width multi-line combs: BroadbandConfig still accepts num_colors > 1 with delta_omega == 0. BroadbandDriver normalizes separate line powers, while TransverseCurrentSourceDriver sums the coincident-frequency sources coherently. Their interference does not average away, so a zero-bandwidth control can silently change pump intensity despite unchanged base_intensity. Reject this combination and direct users to one line, or normalize the coherent sum; cover the evaluated source in a regression (existing inline finding).
  • Ignored scalar Ex phase: AKWDriverConfig and IntensityWavelengthDriverConfig accept phase, and EMDriver.from_config stores it, but LongitudinalElectricFieldDriver._single_driver_field omits it from the sinusoid. Relative-phase forcing therefore runs with the wrong field without reporting an error. Apply the phase in the longitudinal evaluator or reject nonzero Ex phase, with an analytic-source regression (existing inline finding).

Postprocessing: the configured single-comb workflow has a reachable spectrum plot, field/wave-decomposition and distribution/moment diagnostics, mean_e2, netCDF persistence, and MLflow artifact export. Existing moment/distribution diagnostics also cover the Vlasov/PIC width change. The explicit program can run without plotting/artifact writes and exposes a callable dataset analyzer. The previously reported multi-driver spectrum scaling issue remains nonblocking.

Static code and test inspection only; I did not execute tests, postprocessing, or the reported campaign validation.

This branch has not been deployed

No deployments
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.

2 participants