Single precision#
solprop computes in IEEE binary64 (double precision) by default. A run can instead hold
its propagated field and its nonlinear evaluation in binary32 (single precision) with
precision="single" (SEP 33).
Single precision halves the memory of every field-sized buffer and is what graphics
processors without fast binary64 arithmetic compute in; whether a given problem keeps
its accuracy in binary32 is a property of the problem, so this page records which do.
Note
Single precision runs on the reference backend, numpy_ref, named explicitly: it runs
every route below as the reference implementation, which defines the arithmetic and
measures it but is not fast. native computes in binary64 only
(#342).
Asking for it#
from solprop.driver import prop_capillary
output = prop_capillary(
125e-6,
0.1,
"He",
0.8,
wavelength=800e-9,
fwhm=10e-15,
energy=100e-6,
wavelength_limits=(200e-9, 3e-6),
trange=200e-15,
precision="single",
backend="numpy_ref",
)
precision is a keyword of prop_gnlse, prop_capillary and prop_waveguide, and a
field of SimulationSettings for the free-space
interfaces. Under single precision:
The tolerance floor. An explicit adaptive
rtolbelow1e-6(SINGLE_RTOL_FLOOR) is refused: a local error target below binary32’s rounding per step buys steps without accuracy. A fixed schedule reads no tolerance.The default tolerance. Each interface takes the larger of its binary64 default and the floor, and no more than
1e-4(SINGLE_RTOL_CAP), the loosest value the survival record below measured:1e-6onprop_gnlse(whose binary64 default is1e-7) andprop_capillary,1e-5onprop_waveguide,prop_radialandprop_planar, and1e-4in free space (its record). A spatial interface applies it where itsSimulationSettingsgive no controller; an explicitrtolor controller is the caller’s.The step’s exponent. Binary32 represents
exp(x)only up to \(x \approx 88.7\) (binary64 to 709.8). The Runge–Kutta interaction picture multiplies by the linear propagator and its inverse, so underRungeKutta()a replayed step (or an adaptive run’s floordz_min) over which a strong collar or loss reaches that exponent is refused at translation, with the shortest step that fits, and one within a tenth of it is warned of; a 1 mm capillary’s default collar on 0.25 mm steps is one such case. The low-storage march and the exponential Adams method apply forward flows only: a damped bin’s flow underflows harmlessly towards zero, so they are limited by growth alone, which no passive medium has. The Kerr beams’ 0.5 µm steps, whose spectral collar reaches 150 to 180, run in binary32 withLowStorageRungeKutta()for this reason.The integrator. Each interface takes its binary64 default (the defaults):
Multistep()in its exponential formulation onprop_capillary,prop_radialandprop_planar(the Adams record),RungeKutta()(DOPRI5) elsewhere; the low-storage march is admitted too. A run changes arithmetic, not method, when it changes precision.Noise. A default
noiseresolves to none, and the run records why; an explicit noise model is refused (below).The backend.
backend="auto"is refused: it never resolves to a binary64 backend, nor to the reference implementation, which is named explicitly,backend="numpy_ref".Outputs are unchanged: saved fields, statistics and processing are binary64, and files are the same size. The precision is part of the run’s configuration, so a run is never resumed in the other precision.
What it covers#
|
|
|---|---|
capillaries, solid-core and GNLSE fibres, mode-averaged and multimode, field and envelope grids |
yes |
Kerr, the envelope grid’s third-harmonic term, scalar and tensor Raman, gas Raman mixtures, the silica bundle |
yes |
field-grid plasma |
yes |
envelope-grid plasma |
yes |
radial and Cartesian free space, including a line, with their transverse collars |
yes |
gradients, tapers, loss, both temporal absorber schemes, the polarisation taper |
yes |
Runge–Kutta, the low-storage march |
yes |
fixed-schedule batches through |
yes |
the Adams integrator |
the exponential formulation |
noise models |
refused (a known limitation, below) |
the general modal route, the hybrid planar kind, coupled flows, TDSE responses, the dispersive electronic response, the far-field statistics |
refused |
How the arithmetic is kept accurate#
Binary32 carries about seven significant digits and represents magnitudes between about \(10^{-38}\) and \(3\times10^{38}\). solprop keeps both from limiting a run:
Range. Every table a run multiplies by is narrowed with its own power-of-two exponent, and the field is held at an exact power-of-two scale chosen from the launch. A nitrogen Raman kernel whose spectrum is near \(10^{-50}\) — zero in binary32 as it stands — keeps every bin; a Cartesian energy sum that would reach \(10^{44}\) is scaled before squaring.
The linear propagator \(e^{\Delta\Phi}\) is formed to binary64 accuracy and rounded once per step. Its rounding still adds coherently from step to step, about \(c\,M\,u\) after \(M\) steps with \(u = 2^{-24}\); the record below states \(c\).
Populations. The ionised fraction and the neutral survival are formed in forms that keep relative accuracy at tiny and saturated exposures, and running integrals over time are summed in a balanced order rather than one long sequential sum.
The controller, landing and every scalar stay in binary64.
The survival record#
Each case below was run with RungeKutta() in both precisions: in single precision at
rtol = 1e-6 and 1e-5, compared at the end of its window with a binary64 run on the
same grid at rtol = 1e-10, against accuracy envelopes fixed before any comparison: the
field to \(10^{-3}\), the spectral energy in each of 32 bands above −40 dB to 1 %, the
total energy to \(10^{-4}\), the peak power or intensity, the final ionised fraction and
the beam width to \(10^{-3}\), all relative. The table gives the largest of those relative
errors at rtol = 1e-6, the field’s error, and binary64’s own field error at the same
tolerance for comparison.
case |
single: field error |
largest other metric |
binary64 at |
verdict |
|---|---|---|---|---|
self-phase modulation, 10π, no dispersion (GNLSE) |
7.9e-6 |
9.6e-5 (bands) |
1.9e-6 |
survives |
fundamental soliton, ten periods (GNLSE) |
2.7e-5 |
6.5e-6 (peak) |
1.1e-6 |
survives |
dispersive-wave emission, He capillary gradient, two modes, 1.5 m |
2.6e-6 |
4.9e-5 (bands) |
1.3e-6 |
survives |
comb-to-continuum, H₂ capillary at 40 bar, 0.1 m, noise-free |
2.6e-3 |
3.4e-4 (peak) |
3.0e-7 |
survives over 0.05 m |
plasma blue shift, Ar capillary, field grid, 0.4 m |
1.8e-4 |
2.1e-4 (bands) |
1.6e-4 |
survives |
plasma blue shift, Ar capillary, envelope grid, 0.4 m |
1.3e-5 |
2.1e-5 (ionised) |
1.3e-5 |
survives |
molecular Raman, N₂ capillary at 2 bar, 0.3 m |
1.1e-6 |
2.7e-5 (bands) |
1.6e-7 |
survives |
radial Kerr beam, 0.3 m |
8.5e-6 |
1.3e-4 (bands) |
8.6e-6 |
survives |
radial filament in argon with plasma, 3 cm |
2.3e-6 |
1.2e-5 (peak) |
2.2e-6 |
survives |
Cartesian Gaussian diffraction, 64 × 64 |
2.4e-7 |
2.4e-7 (bands) |
0 |
survives |
Cartesian Kerr beam, 64 × 64 |
2.7e-6 |
2.0e-5 (bands) |
4.2e-6 |
survives |
At rtol = 1e-5 every case but the comb-to-continuum stays inside its envelopes too.
The table is the reference implementation’s. Its rows were measured
on 24 and 25 October 2026, before the single-precision fixes of 27 October 2026 made the
reference’s transforms sum in binary32 (the comb-to-continuum case, re-measured on them,
is below) and before the default grids and boundaries changed
(SEP 21); they have not been
repeated since.
The comb-to-continuum limit. Noise-free stimulated Raman scattering grows from whatever seed the Stokes band holds; rounding seeds it at the level of the unit roundoff times the field. In binary64, adding a seed of \(2^{-24}\) of the launch’s peak spectral amplitude moves the result at 0.1 m by 5 %: the sensitivity is the physics, and binary32’s own rounding is such a seed. Over 0.05 m the run is inside every envelope. The reference’s transforms now sum in binary32, as the backends’ do (NumPy’s float32 transforms are binary64 rounded once, which this record first used); on them the field error is 2.5×10⁻⁴ at 0.05 m and 1.6×10⁻³ at 0.1 m, so the limit stands (SEP 36).
The tolerance floor stays at
1e-6: tightening from1e-5to1e-6still buys accuracy (by 92 % in the self-phase-modulation case’s field).The propagator’s step limit. With no nonlinear source the rounding of \(e^{\Delta\Phi}\) accumulates as \(c\,M\,u\) after \(M\) steps, with \(c \approx 0.5\) measured on a capillary operator over \(10^2\)–\(10^4\) steps (0.1–0.3 on a GNLSE one). The field envelope of \(10^{-3}\) is reached after about \(3\times10^4\) steps; a run that needs more takes binary64.
Free space at its binary64 tolerance#
Free space’s binary64 default, rtol = 1e-4, was qualified in binary32 on 5 November
2026 (#85); until then a single-precision
free-space run took 1e-5. Each case ran with RungeKutta(), noise-free, on a
power-of-two grid, in binary32 on the mlx backend (since retired) and binary64 on
native, against a binary64 run
at rtol = 1e-6 (the field’s relative difference):
case |
binary64 at |
binary32 at |
binary64 at |
binary32 at |
|---|---|---|---|---|
radial filament in argon with plasma, 3 cm |
9.8e-5 |
2.0e-5 |
1.2e-5 |
1.0e-5 |
radial Kerr beam with its transverse collar, 8 cm |
2.5e-5 |
2.1e-5 |
1.7e-6 |
2.0e-6 |
Cartesian argon filament, 128 × 128, 1.5 cm |
6.9e-5 |
2.4e-5 |
6.2e-6 |
5.2e-6 |
Binary32 at 1e-4 is as close to the reference as binary64 at 1e-4, or closer: the
tolerance, not the precision, sets the error. The Cartesian filament takes 48 steps at
1e-4 against 61 at 1e-5.
The Adams integrator in binary32#
Multistep() was admitted on 5 November 2026 by the rule
#342 proposed: binary32 Adams judged
against binary64 Adams at the same tolerance, rather than against Runge–Kutta, whose
difference from Adams is the methods’ truncation. Each case ran its whole length,
noise-free, on a power-of-two grid, at each interface’s default tolerance, on the mlx
backend (binary32, since retired) and native (binary64). The table gives the relative difference of the
final fields, and binary64 Runge–Kutta’s from binary64 Adams as the scale of the
methods’ own truncation:
case |
binary32 Adams against binary64 Adams |
binary64 RK against binary64 Adams |
binary32 RK against binary64 Adams |
|---|---|---|---|
He capillary gradient, mode-averaged, 1.5 m (RDW) |
2.3e-6 |
3.6e-6 |
4.3e-5 |
the same, four modes |
4.3e-6 |
1.7e-6 |
1.3e-4 |
Ar capillary, field-grid plasma, 0.2 m |
1.3e-5 |
2.3e-5 |
4.9e-5 |
Ar capillary, envelope-grid plasma, 0.2 m |
8.2e-5 |
1.1e-4 |
1.2e-4 |
H₂ capillary, Raman, mode-averaged, 0.4 m |
8.0e-5 |
2.9e-5 |
1.0e-4 |
GNLSE, Raman and shock, 0.15 m |
2.2e-4 |
3.1e-5 |
9.4e-5 |
radial filament in argon with plasma, 3 cm |
6.8e-6 |
1.4e-5 |
1.1e-5 |
radial Kerr beam with its transverse collar, 8 cm |
5.0e-6 |
6.7e-6 |
7.7e-6 |
Every case is far inside the field envelope of \(10^{-3}\), and all but the GNLSE within a
small multiple of the methods’ own difference; the GNLSE runs at 1e-6 in binary32
against binary64’s 1e-7 (the floor), which accounts for its row. On the capillaries
binary32 Adams is closer to the binary64 reference than binary32 Runge–Kutta is.
Known limitations#
Noise. A one-photon-per-mode seed is of order \(10^{-5}\) of a microjoule pulse’s peak spectral amplitude and smaller at higher energies, while binary32’s accumulated rounding can reach \(10^{-5}\) after \(10^4\) steps. Noise-seeded runs are refused under single precision until that boundary is qualified.
Amplifying dynamics. Rounding at the level of \(10^{-7}\) per step is amplified like any perturbation by soliton fission, modulation instability or noise-free stimulated Raman scattering; such runs reach their accuracy over a shorter length, as the record states.
Performance. On the reference implementation a single-precision run costs about as much as a double-precision one; no backend runs it faster.
The worked example runs a capillary and a radial filament, each with the field-grid plasma, in both precisions and compares them. The precision setting, its binary32 contract and the survival study were proposed and carried out by SEP 33.