Repository navigation
Lawson (integrating-factor) wrapper for the diagonal hypercollision damping (opt-in) - #82
Open
rogeriojorge wants to merge 1 commit into
Open
rogeriojorge wants to merge 1 commit into
rogeriojorge wants to merge 1 commit into
Conversation
…rcollision damping; simulation(integrating_factor=)
rogeriojorge
force-pushed
the
agent/lawson-main
branch
from
October 20, 2026 11:56
a1de022 to
82b9407
Compare
rogeriojorge
added a commit
that referenced
this pull request
Oct 20, 2026
… into the integration lineage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lawson (integrating-factor) wrapper for the diagonal damping — opt-in, bitwise off
Targets
main(bf41830). Self-contained: it needs nothing from the closure PRs (#66 etc.). The older #81 is the same wrapper stacked on the integration lineage (field-scaled closure rate, Dark-SPECTRAX); it is merged intointegration/dark-baselineonly and is kept as the integration variant. This PR is the clean, main-based version.What it is
spectrax.LawsonSolver(solver, rate_fn): wraps any explicit Diffrax Runge-Kutta solver (Dopri8,Heun, ...) so a diagonal damping-r yof the right-hand side is integrated exactly.rate_fn(t, y, args)returns a non-negative pytree likey(zeros for states that must not be damped). It is the hook for any stiff diagonal rate, e.g. the field-scaled closure rate of Field-scaled closure rate for the asymmetric-Hermite top-mode instability #66 (not a dependency).simulation(..., integrating_factor=True): uses the hypercollisionnu * coland hyper-diffusionD k^2rates of the existing right-hand side. DefaultFalseis bitwise unchanged (tested). Steps are clipped onto the save times (see dense output below).hypercollision_rate,simulation_ratehelpers. +171 lines of library code, +138 of tests, +20 ofsimulation, a README section.Derivation (also in the
spectrax/_lawson.pydocstring)Write
f(t, y) = -r y + N(t, y),r = r(y0) >= 0frozen at the step start,N = f + r y0 * y. That is an identity for everyr. Withw = exp(r (tau - t0)) y:w' = exp(r (tau - t0)) (f(tau, exp(-r (tau - t0)) w) + r exp(-r (tau - t0)) w); one step of the wrapped RK tableau onwfromw(t0) = y0, theny1 = exp(-r h) w1.rthis is the classical Lawson-RK method of the wrapped tableau; because the split is an identity for everyr, choosingr = r(y0)(a smooth function of the step-start state, fixed before the stages) does not change the order. Verified numerically: Heun-Lawson order 2, Dopri8-Lawson order 8 with a state-dependent rate.N(arXiv:1910.12720, Section 3, which I read). So-r yno longer enters the stability conditionh r < ~5.17of Dopri8.y_err = exp(-r h) w_err;y(t) = exp(-r (t - t0)) w(t).Nand is treated explicitly (this is whyrshould vary slowly on the step, as the field-scaled closure does through|E|).w(t)is a polynomial;y = exp(-r (t - t0)) wis accurate only forr hof order one. Saves on step ends are exact.simulation(integrating_factor=True)therefore wraps the controller inClipStepSizeController(step_ts=save_times)(users ofLawsonSolverdirectly should do the same when the rate is stiff).exp(r h)overflows nearr h ~ 700. An adaptive controller will happily propose such a step (the stiff mode is exactly resolved so the error estimate is tiny); the candidate is theninf, Diffrax's scaleatol + rtol max(|y0|, |y1|)becomesinf, the scaled error 0, and the garbage step is accepted. Now a non-finite candidate is returned asy0with a finite huge error (1e30; an infinite one poisons the PID memory and the next step becomesinf), so it is rejected and the step shrinks. Finite steps are bitwise untouched. Regression test included; without the guard thenu = 4000run below never finishes (20 000 rejected steps).Evidence (this machine, CPU, x64;
simulation(Nx=17, Nn=24, Ns=2, timesteps=5, t_max=2, nu=...), wall after warm-up)nuCkdifference at saves(t_max = 5 for the
nu = 3row.) Larger gains are limited byr h < ~700and by forced-mode accuracy (below). In the Dark-SPECTRAX study (field-scaled closure rate,Nx 64, Nn 128, GPU/CPU records in that repo) the same wrapper gave 5.0x fewer steps at c = 64 to the t = 500 mark and no gain at c = 4 (closure not stiff before ~540); ordinary-dispersion B10 case: 4.6x fewer steps but 1.5x wall (small state, per-step cost 3x), and a ledger defect that is 1e-9 instead of 1e-11 because the plain run over-resolves. Those are in the Dark repodocs/results.md; they are reported, not re-derived here.When it helps and when it does not
nu * h,D k^2 h, or a field-scaled closure damping that grows with the field).nu(3), where the step is accuracy-limited. 18 -> 20 steps above.w' ~ exp(r tau) N. If the stiff row is driven by a smooth source, the transformed integrand is far from polynomial and the step remains limited by accuracy forr hbeyond a few tens. On the toyy' = -4000 y + sin t(rtol 1e-6) it needs 1 143 steps (the plain stability bound alone would be ~1 600; plain not run). This is the known drawback of Lawson relative to phi-function (ETD/Rosenbrock) integrators; see literature.n <= 2).ODETermproblems; wrapped solver must be explicit RK with an embedded error estimate (Dopri8,Tsit5,Heun, ...);r h < ~700.Literature (what I read, and what I did not)
Tests (
tests/test_lawson.py, 10, all pass locally; full CI below)r h = 200(plain Dopri8 blows up at the same step);simulationdefault unchanged bitwise; Lawson agrees at solver tolerance; n <= 2 rows agree to 1e-6;jax.grad) versus central finite difference, rel 1e-5;nu = 4000simulation matches plain, with at least 2x fewer steps;[Ck, Fk]state, rate zero on fields;Limitations / review notes
rate_fnis evaluated at the step start; its time variation inside the step is explicit (documented above).simulationoption on main covers hypercollision/hyper-diffusion only (main has no field-scaled closure); custom closures useLawsonSolverdirectly.Merge recommendation
Safe to merge if the owner wants the option: opt-in, bitwise off, no new dependency, small. Value is concentrated in stiff-closure runs (large
nu, strongD, or the #66 field-scaled closure). If SPECTRAX's intended regime is the defaultnu, there is no benefit and the PR can wait; nothing else depends on it. A stacked follow-up (exact Hermite streaming, #83) is a separate PR on top of this one; its benchmark showed that exact streaming does not help the stiff-closure regime, so #83 is optional and this PR does not depend on it.