solprop.backends.numpy_ref.backend#
The reference backend: the step loop, the seam and the refusals.
One NumpyRefBackend steps one mode-averaged problem with the Kerr term, in
plain NumPy, calling the named passes of solprop.backends.numpy_ref.passes in the
order of docs/dev/architecture.md section 8. The step control follows
docs/dev/stepper.md section 3 exactly: the controller’s proposal is its state, the
executed step’s own norm decides acceptance, and the equivalent norm of the proposal is
what the history and a rejection see.
The contract is consumed only through its evaluation functions –
solprop.translate.linop.delta_phi(),
solprop.translate.linop.unitary_phase(),
solprop.translate.responses.prefactor_at(), and the scalar tables
responses.density and transform.taper_scale – never through the coefficient
arrays, so the representation of the z tables can change without touching a backend.
Module Attributes
Relative quadrature error above which the alarm is logged, once per plane. |
Classes
|
|
|
Propagate one Kerr and plasma problem with interaction-picture DOPRI5. |
|
The problem's tables a source evaluation multiplies by. |
- class solprop.backends.numpy_ref.backend.BlockResidual(flow)[source]#
Bases:
objectR_s(z) statefor a held flow’s positions (SEP 16 phases 5 and 6).A history sample’s residual is formed against the section of every trial it serves, about six; its action depends only on the section and the sample’s flow weights, so each pair’s action is formed once and kept, the least recently used dropped first: each trial’s endpoint, at a new position, is used once.
- Parameters:
- flow_CoupledFlow
The held flow.
- class solprop.backends.numpy_ref.backend.NumpyRefBackend(problem, *, grid=None, modes=None, profiles=None, tdse_binding=None)[source]#
Bases:
StepDriver[Complex[ndarray, 'n_batch n_modes n_pol n_omega']]Propagate one Kerr and plasma problem with interaction-picture DOPRI5.
The oracle of
docs/dev/backends.mdsection 2. It implementssolprop.backends.protocol.Backendand steps a single problem (max_batch = 1) on either grid: mode-averaged or multimode on the fixed transverse quadrature, scalar or vector-isotropic, with the Kerr term, the delayed Raman term and the plasma. Mode-averaged propagation is the one-node case of the same pipeline and not a second code path.Refusals. A problem is refused by name, with
solprop.exceptions.BackendError, when itsschema_versionis not the one this backend knows, when its flags declare a spectral response, when a Raman kernel meets two polarisation components, when the transform and the state would both carry the transverse components, or when its batch axis is larger than one. A term silently dropped would run, converge and be wrong.Convention. Every array held or returned is in the FFT convention of
docs/dev/conventions.mdsection 2; the backend never conjugates. The output layer converts on the way to disk and the processing accessors on the way to a user.The grid.
stats()delegates tosolprop.stats.collect(), which needs asolprop.grid.TimeGrid; the kernel contract carries the array groupsolprop.translate.masks.Gridsand no grid object, so the grid is supplied here instead. This is a known gap in the contract.- Parameters:
- problemsolprop.translate.problem.KernelProblem
The validated kernel problem.
validate()is called again here: validation is the backend’s defence, not the caller’s courtesy.- gridsolprop.grid.TimeGrid, optional
The grid the state lives on, needed only by
stats().- modescollections.abc.Sequence, optional
The propagated modes, in state order, needed only by the
zdwstatistic.- profilescollections.abc.Mapping, optional
The z-profiles keyed by statistic name, needed only by the profile statistics.
- tdse_bindingsolprop.translate.tdse.TDSEBinding or None, optional
Driver-owned persistent atomic plans, required exactly when the problem declares a TDSE response. The driver closes this binding after the backend.
- Raises:
- BackendError
Naming what the backend refuses.
Examples
>>> from solprop.backends.numpy_ref import NumpyRefBackend >>> from solprop.grid import EnvelopeGrid >>> from solprop.nonlinear.gnlse import problem_from >>> from solprop.pulses import SechPulse >>> from solprop.stepper import PIController >>> from solprop.translate.problem import assemble >>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (500e-9, 2e-6), 1e-12) >>> gnlse = problem_from([0.0, 0.0, -1.183e-26], omega_ref=grid.omega0, ... gamma=0.11, shock=False) >>> start = SechPulse(wavelength=835e-9, width=100e-15, peak_power=9.8).build(grid) >>> problem = assemble(grid, gnlse.mode, [gnlse.kerr], start, ... controller=PIController(rtol=1e-8, atol=1e-16), ... save_planes=[0.01], dz_max=0.01, dz_init=1e-3, ... density=1.0, shock=False, prefactor_index=1.0) >>> backend = NumpyRefBackend(problem, grid=grid) >>> backend.set_initial(problem.initial.field0, None) >>> summary = backend.propagate_to(0.01) >>> summary.z, summary.n_rejected, summary.met_tolerance (0.01, 0, True) >>> backend.observe().field.shape (1, 1, 1, 1024) >>> backend.close()
- helpers = Helpers(name='plain')#
- max_batch = 1#
- memory_ledger()[source]#
Return the size of every buffer the backend works in, in bytes.
The reference backend allocates its stage and transform buffers per pass instead of keeping a preallocated pool, so this reports what one step has resident at its peak – which is what the optimised backends hold for the whole run, and what the budget of
docs/dev/architecture.mdsection 8 is measured against. Every buffer is named even when it is empty.The space-domain entries are sized by
transform.node_chunkand not by the node count, which is the whole point of the chunk loop (architecture.mdsection 13): holding(n_to, n_pol n_nodes)for every node at once would be 210 MB against 45 MB on the comb-to-continuum target.- Returns:
- dict
Buffer name to bytes.
- metadata()[source]#
Return execution facts and cumulative logical and atomic call ledgers.
- Returns:
- dict
Provider-free, serializable facts. A PEC predictor is explicitly labelled and is never reported as an accepted-field diagnostic.
- name = 'numpy_ref'#
- propagator_default = 'tabulate'#
- restore_call_ledgers(logical, atomic=None)[source]#
Restore cumulative counters while leaving the Adams history empty.
- Parameters:
- logicalmapping
Persisted logical call counters and accepted-order record.
- atomicmapping or None, optional
Persisted atomic attempts; unused reservations are released.
- Raises:
- BackendError
If a ledger is incompatible with this run.
- set_initial(field, noise, *, z=0.0)[source]#
Load a state; an Adams march restarts its history from it.
- Parameters:
- fieldnumpy.ndarray
The state in the canonical layout.
- noisesolprop.noise.NoiseRealisation or None
The realisation to carry, or
Nonefor the problem’s own.- zfloat, optional
The position the state belongs to, m; positive for a resume, which starts the history afresh unless
restore_march()then continues it.
- stats(spec)[source]#
Collect the requested statistics at the current position.
The statistics of the saved field go to
solprop.stats.collect(), one call per batch member, stacked along the leading batch axis the protocol promises; there is exactly one definition of each in the package and that is it. The statisticssolprop.stats.StatDefinitionmarksbackendare of quantities a saved plane does not carry – the electron density, the peak ionisation rate, the on-axis intensity, the quadrature error – and are formed here from the backend’s own buffers.- Parameters:
- specsolprop.stats.StatsSpec
Which statistics and which windows.
- Returns:
- dict
Small host arrays keyed by statistic name, each with a leading batch axis.
- Raises:
- BackendError
If the backend is closed, no initial state was loaded, no grid was given at construction, or a backend statistic needs something this run does not have.
- solprop.backends.numpy_ref.backend.QUADRATURE_ALARM = 1e-06#
Relative quadrature error above which the alarm is logged, once per plane.
The fixed rule integrates the Kerr quartic of a mode set to the reference’s own rounding – 2e-14 at
n_r = 32for four HE_1m modes (docs/guide/waveguides/mode-sets.md) – so anything a millionth of the polarisation is not the rule converging slowly but the integrand being unresolved, which no step size can fix. It also sits at the loose end of the tolerances a run asks the controller for, so an alarm means the quadrature has become the largest error in the step. The number is a judgement, not a measurement.
- class solprop.backends.numpy_ref.backend.SourceTables(synthesis, projection, t_window, t_window_derivative, omega_window, temporal_rate)[source]#
Bases:
objectThe problem’s tables a source evaluation multiplies by.
Read through this record rather than off the problem so that the single-precision path can hold them narrowed (SEP 33 section 4.2) while the passes stay the same.
- Attributes:
- synthesisnumpy.ndarray
transform.synthesis.- projectionnumpy.ndarray
transform.projection.- t_windownumpy.ndarray
grids.t_window_fine.- t_window_derivativenumpy.ndarray
grids.t_window_fine_derivative.- omega_windownumpy.ndarray
grids.omega_window.- temporal_ratenumpy.ndarray or None
responses.temporal_absorber_fine.
- classmethod of(problem)[source]#
Return the problem’s own tables.
- Parameters:
- problemsolprop.translate.problem.KernelProblem
The problem.
- Returns:
- SourceTables
References to its arrays, uncopied.
- omega_window: Float[ndarray, 'n_omega']#
- projection: Float[ndarray, 'n_modes n_columns']#
- synthesis: Float[ndarray, 'n_rows n_modes_s']#
- t_window: Float[ndarray, 'n_to']#
- t_window_derivative: Float[ndarray, 'n_to']#