Physical validation¶
Most of a solver’s test suite can pass while the physics is wrong. Tests that compare the backends against each other pass when all of them are wrong in the same way. Tests that measure convergence order pass when the answer converges beautifully to the wrong number — order is a statement about how the error shrinks, not about what it shrinks towards. And a test that checks the propagator by writing the same formula a second time and comparing catches a typo in one of the two copies, never the formula itself.
So there is a separate suite, tests/physics/test_closed_forms.py, whose
assertions come from outside the package: solutions of the same equation that
were known before this code existed. Each one isolates a different term, and
the last one isolates none of them.

Curves are the analytic solutions, markers are what the solver returns. The residuals in the titles are what the figure cannot show.
The equation, and the conventions it fixes¶
Two conventions follow from it that nothing else in the documentation stated, and that the tests now pin:
\(n_2 > 0\) is self-focusing. A positive nonlinear index raises the index where the beam is brightest, which is what makes the bright soliton below exist at that sign and not the other.
alphaattenuates the intensity, not the amplitude: \(I = I_0e^{-\alpha z}\). A factor of two here is invisible to every other kind of test.
What each check isolates¶
Check |
Closed form |
Isolates |
Agreement |
|---|---|---|---|
Gaussian diffraction |
\(w(z) = w_0\sqrt{1 + (z/z_R)^2}\), \(z_R = kw_0^2/2\) |
the propagator, its normalization, the \(k\) grid, the wavelength |
exact |
Gouy phase |
\(\varphi(0,z) = -\arctan(z/z_R)\) |
the sign and scale of the dispersion relation |
5 decimals |
Talbot revival |
\(z_T = kd^2/\pi\) |
the propagator at a finite transverse wavenumber |
\(1.6\times10^{-6}\) |
Beer’s law |
\(I(z) = I_0e^{-\alpha z}\) |
the loss term, and its convention |
6 decimals |
Saturated self-phase modulation |
\(\varphi = k n_2 I z / (1 + I/I_{sat})\) |
the interaction term and the saturation model |
\(10^{-7}\) |
The lossy identity |
\(\varphi = \dfrac{k n_2}{\alpha}\left(I_0 - I_{end}\right)\) |
loss and interaction together |
\(4\times10^{-7}\) |
Bright soliton |
\(x_0^2 = 1/(k g A_0^2)\), \(g = kn_2c\varepsilon_0/2\) |
nothing separately — only the balance |
\(6\times10^{-7}\) |
Why three checks on the propagator¶
A beam diffracts at roughly the right rate under a surprising range of mistakes, and a second moment is a blunt instrument. The Gouy phase is the sharp one: flipping the sign of the dispersion operator still produces a beam that spreads, and only the phase test notices. The Talbot distance covers what neither can — both Gaussian tests concentrate their power near \(K = 0\), where a wrong dispersion relation hides, while a grating puts all of it at one finite \(K\) and revives only at the distance that \(K^2/2k\) predicts.
The lossy identity¶
This one is worth stating in full, because it is the physics behind the solved real-space step rather than a property of the numerics. With \(y = |A|^2\) and \(s = 1/(1 + y/I_{sat})\),
so the phase accumulated over any distance depends only on how much intensity was lost, whatever the saturation did in between — and the intensity that remains is fixed implicitly by \(\ln I + I/I_{sat}\) falling by \(\alpha z\). Both halves are asserted. Elsewhere the suite measures the order of that step; here it is measured against the answer.
The soliton, and its control¶
\(A_0\,\mathrm{sech}(x/x_0)\) propagates unchanged only when diffraction and self-focusing cancel exactly. Every other check above passes if the two terms are individually right; this is the one that fails if a sign or a factor sits between them. It is asserted alongside a control — the same profile 1.5x too wide, which is not a soliton and visibly spreads — because “the shape barely changed” means nothing without something that changed.
What breaking the physics does¶
The checks were verified by breaking the solver on purpose. Each mutation is a plausible slip in a constant that no other test in the suite reads against anything external:
Injected fault |
Caught by |
|---|---|
dispersion off by a factor of two |
diffraction, Gouy, Talbot |
dispersion sign flipped |
Gouy only |
|
Beer, the lossy identity |
saturation off by a factor of two |
Beer, the lossy identity |
What this does not cover¶
Vortex dynamics. A vortex–antivortex pair should translate at \(v = \hbar/(md)\), which is the natural closed form for a periodic box since net circulation must vanish there. A first attempt reproduced it to 7% at one separation and not at two others; the initial state was not relaxed and the core positions came out quantized to the grid. Doing it properly needs imaginary-time relaxation and sub-pixel core fitting, and a test that passes at one separation is worse than none.
The absorbing potential and the coupled solvers. Their real-space step is still frozen rather than solved, so it is first order in a lossy medium. That is a known limitation rather than an untested one — see the Open section of
docs/optimization-log.md.Whether the grid resolves your problem. Every check here is self-consistent on its own grid. None of them says that the grid you chose is fine enough for the physics you are running.