solprop.backends.numpy_ref.single#
The single-precision path of the reference backend: SEP 33’s oracle.
NumpySingleBackend is
NumpyRefBackend with the propagated state,
the stage values, every transform and the responses held in IEEE binary32, under the
contract of docs/dev/seps/archive/sep-0033-single-precision-mlx.md section
4.2. It is the target the mlx backend is compared against, so it keeps the
reference’s one-function-per-pass shape and states every order it sums in.
What is binary32 and what is not:
The state is held as
a / s,sthe launch’s exact power-of-two scale (solprop.translate.precision.state_scale()).observeand the statistics readstimes the state, widened to binary64, which is exact.The tables a source evaluation multiplies by are narrowed once at construction (
_upload). Each has its block exponent (solprop.translate.precision.block_exponent()); where narrowing the table directly keeps every entry the block-exponent form keeps (the table’s largest magnitude at least one, or no entry below binary32’s smallest normal), the exponent is applied at upload, exactly, and otherwise the table is refused unless its pass carries the exponent itself, as the Raman kernel’s does.The propagator
exp(dPhi)is formed from the binary64 exponent in binary64 and rounded once (section 4.1, item 3); every other z-dependent array a pass multiplies by – the prefactor, a z-table’s value, the spatial collar’s rate – is evaluated on the host in binary64 and rounded once.The responses run in binary32 on the scaled field. Each takes its homogeneity factor (section 4.3, rule 4) in one binary64 coefficient combined on the host (
solprop.translate.precision.combine()):s**2for the cubic terms; the plasma is evaluated at the physical fields E, an exact multiplication, and its current divided bys. The field-grid plasma uses the stable population forms of section 4.4 and blocked running integrals (solprop.translate.precision.prefix_sum()).Host evaluations of the oracle. The ionisation rate’s table lookup, the envelope-grid plasma’s cycle moments and populations, and the statistics are evaluated in binary64 from the binary32 field and rounded (or, for the statistics, returned) once: the oracle defines the reference these comparisons are made against.
The controller reads a norm reduced as a scaled sum of squares (
solprop.translate.precision.scaled_square_sum()), against an absolute tolerance divided bys.
Functions
|
Return the analytic signal of a real binary32 array, in binary32. |
|
Evaluate the Kerr polarisation of |
|
Return the field-grid plasma's ungated current density in binary32. |
|
Evaluate the delayed Raman polarisation in binary32. |
|
Return a running integral in binary32, in the oracle's blocked order. |
|
Evaluate the responses of |
|
Return the ionised fraction and the neutral survival in their stable forms. |
Classes
|
Propagate a single-precision problem: the reference backend in binary32. |
- class solprop.backends.numpy_ref.single.NumpySingleBackend(problem, *, grid=None, modes=None, profiles=None, tdse_binding=None)[source]#
Bases:
NumpyRefBackendPropagate a single-precision problem: the reference backend in binary32.
Constructed by the registry for
backend="numpy_ref"when the problem’s precision is single. See the module docstring for what is held in which precision.- Parameters:
- problemsolprop.translate.problem.KernelProblem
A validated problem with
precision.single.- gridsolprop.grid.TimeGrid, optional
The grid the state lives on, needed only by
stats().- modescollections.abc.Sequence, optional
The propagated modes, needed only by the
zdwstatistic.- profilescollections.abc.Mapping, optional
The z-profiles keyed by statistic name.
- tdse_bindingsolprop.translate.tdse.TDSEBinding or None, optional
Must be
None: TDSE responses are refused under single precision.
- Raises:
- BackendError
If the problem is not single precision, or a table cannot be narrowed without losing range that its pass does not carry.
- property scale: float[source]#
Return the state’s exact power-of-two scale
s.- Returns:
- float
The state is held as
a / s.
- set_initial(field, noise, *, z=0.0)[source]#
Load a state, holding it at the launch’s scale in binary32.
- Parameters:
- fieldnumpy.ndarray
The state in the canonical layout, physical units.
- noiseobject
Must be
None; noise models are refused under single precision.- zfloat, optional
The position the state belongs to, m.
- stats(spec)[source]#
Collect statistics from the physical state widened to binary64.
The oracle’s statistics are binary64 functions of the exactly widened binary32 state, so they carry the state’s rounding and none of their own.
- Parameters:
- specsolprop.stats.StatsSpec
The statistics to collect.
- Returns:
- solprop.backends.numpy_ref.single.analytic_single(values)[source]#
Return the analytic signal of a real binary32 array, in binary32.
The same construction as
solprop.fourier.analytic_signal()(doubling the positive frequencies, keeping zero and Nyquist), with the multiplier held in the values’ precision.- Parameters:
- valuesnumpy.ndarray
Real values along the last axis.
- Returns:
- numpy.ndarray
The complex64 analytic signal.
- solprop.backends.numpy_ref.single.kerr_single(field_t, kerr, factor, carrier)[source]#
Evaluate the Kerr polarisation of
passes.kerr_polarisation()in binary32.- Parameters:
- field_tnumpy.ndarray
The scaled field, binary32.
- kerrsolprop.translate.responses.KerrCoefficients
The compiled coefficients.
- factorfloat
coefficient * density * s**2, combined on the host and rounded once.- carriernumpy.ndarray or None
The narrowed harmonic carrier, when the envelope grid radiates the harmonic.
- Returns:
- numpy.ndarray
The polarisation divided by
s, binary32.
- solprop.backends.numpy_ref.single.plasma_current_single(field, channels, densities, preionisation, dt, rule)[source]#
Return the field-grid plasma’s ungated current density in binary32.
The current of
passes.nonlinear_sources()(one channel) and of its channel sum (several), with the stable populations ofstable_population(): the free current integratessum_c rho_c f_c (e^2/m) n_c Eand the loss current issum_c rho_c I_c W_c sigma_c E / |E|^2, its division masked where the rate or the field is zero. The rate’s table lookup is evaluated in binary64 from the binary32 magnitude and rounded once.- Parameters:
- fieldnumpy.ndarray
The physical field
s E, V/m, binary32.- channelstuple of solprop.translate.responses.PlasmaChannel
The compiled channels.
- densitiessequence of float
Each channel’s density at the stage, m^-3.
- preionisationsequence of float
Each channel’s pre-ionised fraction at the stage.
- dtfloat
The sample spacing, s.
- rulesolprop.nonlinear.ionisation.RunningIntegral
The running-integral rule.
- Returns:
- numpy.ndarray
The current density, A/m^2, binary32.
- solprop.backends.numpy_ref.single.raman_single(field_t, spectrum, factor, *, kind, thg)[source]#
Evaluate the delayed Raman polarisation in binary32.
The convolution of
passes.raman_polarisation()with the narrowed kernel; the coefficient carrieseps0, the density,s**2and the kernel’s exponent, and is applied once to the product with the field.- Parameters:
- field_tnumpy.ndarray
The scaled field, binary32.
- spectrumnumpy.ndarray
The narrowed kernel spectrum,
(n_to + 1,)scalar or(1 | 2, n_to + 1)tensor.- factorfloat
The combined coefficient, rounded once.
- kind{‘field’, ‘envelope’}
The spectral layout.
- thgbool
Whether the drive keeps the harmonic.
- Returns:
- numpy.ndarray
The polarisation divided by
s.
- Raises:
- BackendError
If the field has neither one nor two components.
- solprop.backends.numpy_ref.single.running_integral(values, dt, rule)[source]#
Return a running integral in binary32, in the oracle’s blocked order.
The rule of
solprop.nonlinear.ionisation.RunningIntegral.integrate(): the band rule’s filter (its taps rounded once, the pairs added in the same order), then the cumulative trapezoid, whose increments are summed bysolprop.translate.precision.prefix_sum(). Each prefix is a sum of depth at mostceil(log2 n), where a sequential binary32 cumulative sum ofnterms would carry an error growing withn.- Parameters:
- valuesnumpy.ndarray
The integrand along the last axis, binary32.
- dtfloat
The sample spacing, s.
- rulesolprop.nonlinear.ionisation.RunningIntegral
The problem’s rule.
- Returns:
- numpy.ndarray
The running integral, zero at the first sample, binary32.
- solprop.backends.numpy_ref.single.single_sources(field_t, responses, t_window, *, kind, scale_exponent, dt, scalars, carrier=None, raman_spectrum=None, raman_exponent=0)[source]#
Evaluate the responses of
passes.nonlinear_sources()in binary32.The field is the scaled one,
E / swiths = 2**k. The result is in the scaled state’s units: the polarisation and the current divided bys. Each response takes its homogeneity factor (SEP 33 section 4.3, rule 4) in one binary64 coefficient: the cubic termss**2with the density, the Raman term also the kernel’s block exponent; the plasma is evaluated at the physical fields E(exact) and its current divided bys(exact).- Parameters:
- field_tnumpy.ndarray
The scaled field at the chunk’s nodes, binary32.
- responsessolprop.translate.responses.CompiledResponses
The compiled responses.
- t_windownumpy.ndarray
The narrowed temporal collar profile.
- kind{‘field’, ‘envelope’}
The spectral layout.
- scale_exponentint
kwiths = 2**k.- dtfloat
The fine time grid’s spacing, s.
- scalarssolprop.translate.stage.StageScalars
The stage’s host scalars: densities and preionisation.
- carriernumpy.ndarray or None, optional
The narrowed harmonic carrier of an envelope grid.
- raman_spectrumnumpy.ndarray or None, optional
The narrowed Raman kernel spectrum.
- raman_exponentint, optional
Its block exponent.
- Returns:
- solprop.backends.numpy_ref.passes.NonlinearSources
The windowed polarisation and the ungated current, in the scaled units.
- Raises:
- BackendError
For a response the single-precision path does not run.
- solprop.backends.numpy_ref.single.stable_population(exposure, preionisation)[source]#
Return the ionised fraction and the neutral survival in their stable forms.
SEP 33 section 4.4:
f = p + (1 - p) (-expm1(-X))keeps relative accuracy for a small exposureX, andsigma = (1 - p) exp(-X)for a large one, wherefrounds to one. The loss current and the ionisation work are formed fromsigma, never from1 - f.- Parameters:
- exposurenumpy.ndarray
X, the running integral of the rate, non-negative, binary32.- preionisationfloat
pin[0, 1].
- Returns:
- fractionnumpy.ndarray
f, binary32.- survivalnumpy.ndarray
sigma, binary32.
Examples
>>> import numpy as np >>> from solprop.backends.numpy_ref.single import stable_population >>> f, sigma = stable_population(np.array([1e-8, 20.0], np.float32), 0.0) >>> bool(f[0] > 0), bool(sigma[1] > 0) (True, True)