solprop.backends.spatial#

Collect spatial host statistics through bounded transverse reconstruction chunks.

Module Attributes

FAR_FIELD_BAND_BUDGET

Bytes a compiled far-field pass's band partials may hold (SEP 23 section 6).

LINE_BLOCK

Columns per unit of a line's far-field pass: a plane's unit is a whole row.

AXIS_FOLDED

The axis statistics numba_cpu's far-field pass forms from its W = 1 slot.

AXIS_SPECTRUM_ONLY

The axis statistics Kokkos's far-field pass forms from its W = 1 slot.

Functions

collar_block(problem)

Return how many frequency bins the collar diagnostic reconstructs at a time.

collar_field_fraction(problem, field)

Measure the fraction of the beam's field norm in the declared spatial collar.

collect_spatial(spec, grid, transform, ...)

Collect spatial statistics without retaining a full physical-space field.

far_field_bands(n_x, n_y, n_slots, n_omega)

Return the column edges of a compiled far-field pass's bands.

far_field_layout(names, *, n_apertures, ...)

Lay out the slots a compiled far-field pass accumulates for a request.

far_field_partials(problem, *[, axis_folded])

Return the slots and bands a compiled far-field pass holds for a problem.

fluence_budget(magnitude, n_terms)

Return the rounding budget of a signed local fluence (SEP 34 section 5.1).

radial_absorber_matrix(transform, pad_scale)

Compose the fixed radial rate into one spectral-space matrix.

signed_fluence_widths(geometry, fluence, ...)

Return the widths of a signed local fluence, refusing a negative profile.

slab_columns(transform, rows)

Take a planar state from its (p, y) rows back to (p, k_y) columns.

slab_projection(transform, physical)

Project spectra at the planar nodes onto the (p, k_y) columns.

slab_rows(transform, columns)

Take a planar state from its (p, k_y) columns to its (p, y) rows.

slab_synthesis(transform, columns)

Synthesise a planar state's field at the (x, y) nodes.

Classes

FarFieldLayout(beam, absorbed, regions, ...)

Where each quantity of a compiled far-field pass lives in its slots.

FarFieldTables(problem)

Hold a problem's far-field tables, formed at construction, for its statistics.

solprop.backends.spatial.AXIS_FOLDED = frozenset({'on_axis_intensity', 'on_axis_spectrum'})#

The axis statistics numba_cpu’s far-field pass forms from its W = 1 slot.

solprop.backends.spatial.AXIS_SPECTRUM_ONLY = frozenset({'on_axis_spectrum'})#

The axis statistics Kokkos’s far-field pass forms from its W = 1 slot.

Kokkos forms on_axis_intensity in its own spatial statistics pass, so its slot count leaves that name out.

solprop.backends.spatial.FAR_FIELD_BAND_BUDGET = 134217728#

Bytes a compiled far-field pass’s band partials may hold (SEP 23 section 6).

The band count is min(n_units, budget // (8 n_slots n_omega)), at least one: fixed by the shapes and this constant, never by the thread count, so the order of every sum is the same whatever the pool.

class solprop.backends.spatial.FarFieldLayout(beam, absorbed, regions, apertures, stride, collected, amplitude, axis, n_slots)[source]#

Bases: object

Where each quantity of a compiled far-field pass lives in its slots.

The slot order of SEP 23 section 6, present slots only: the beam spectrum, the four absorbed-power channels, the regions, then per aperture its collected spectrum and its on-axis amplitude, then the on-axis amplitude itself (the W = 1 slot). An amplitude is the real and imaginary parts per polarisation of the electric sum sum_c alpha_c W E_c, then those of its magnetic closure sum_c alpha_c W conj(eta_c) E_c (SEP 34), 4 n_pol slots. An absent quantity is -1.

Attributes:
beam, absorbed, regionsint

The first slot of each, or -1.

aperturesint

The first aperture’s first slot, or -1.

strideint

Slots per aperture.

collected, amplitudeint

Offsets within an aperture’s slots, or -1.

axisint

The first of the 4 n_pol slots of the on-axis amplitude and its closure, or -1.

n_slotsint

Slots in all, positive.

absorbed: int#
amplitude: int#
apertures: int#
array()[source]#

Return the layout as the integer array a compiled pass reads.

Returns:
numpy.ndarray

The attributes in their declared order, int64, shape (9,).

axis: int#
beam: int#
collected: int#
n_slots: int#
regions: int#
stride: int#
class solprop.backends.spatial.FarFieldTables(problem)[source]#

Bases: object

Hold a problem’s far-field tables, formed at construction, for its statistics.

A backend builds one when it is constructed, which forms solprop.translate.spatial.aperture_tables() for the problem’s own spec – refusing a geometry the far-field statistics do not admit before any step – and hands for_spec() the spec of each statistics call. The periodic channel and the reference backend’s filtered specs carry the problem’s own apertures and regions, and get the held tables; a different spec handed to the run loop gets tables formed for it.

Parameters:
problemsolprop.translate.problem.KernelProblem

The problem the backend executes.

Raises:
OutputError

If the problem’s spec names a far-field statistic its geometry does not admit (solprop.translate.spatial.aperture_tables()).

for_spec(spec)[source]#

Return the tables a statistics call’s spec reads.

Parameters:
specsolprop.stats.StatsSpec

The spec of this call.

Returns:
solprop.spatial.ApertureTables or None

The held tables when the spec carries the problem’s own apertures and regions and they were formed, tables formed for this spec otherwise, and None when it names no far-field statistic.

solprop.backends.spatial.LINE_BLOCK = 64#

Columns per unit of a line’s far-field pass: a plane’s unit is a whole row.

solprop.backends.spatial.collar_block(problem)[source]#

Return how many frequency bins the collar diagnostic reconstructs at a time.

A block of the physical field on every node holds at most as many complex samples, with its working copies (the strided slice, the transform’s output and the weighted power: three block volumes), as one node chunk of the response pass holds of one temporal column, node_chunk * n_pol * n_to. The chunk is what the run’s node_budget admits, so the diagnostic’s transient is bounded by the same budget.

Parameters:
problemsolprop.translate.problem.KernelProblem

A Cartesian or planar problem.

Returns:
int

Bins per block, at least one and at most n_omega.

solprop.backends.spatial.collar_field_fraction(problem, field)[source]#

Measure the fraction of the beam’s field norm in the declared spatial collar.

A named electric-field-norm boundary diagnostic, the share of integral |E_a|^2 dA dt on the collar’s nodes: it says how much field reaches the transverse boundary. It is not a fraction of the physical axial flux, which the nonlocal admittance need not localise on those nodes (SEP 34 section 5.1).

Parameters:
problemsolprop.translate.problem.KernelProblem

Plain geometry, temporal scaling and scalar synthesis data.

fieldnumpy.ndarray

One internal spatial spectrum, with the problem’s state dimensions.

Returns:
float

Field-norm fraction on nodes where the spatial window is below one. Zero for an empty beam, absent geometry or a disabled spatial window.

Notes

On the Cartesian and planar kinds the physical field is reconstructed by block of frequency (collar_block()), never as the whole volume: each node’s fluence is a sum over frequency, so blocks accumulate it exactly, up to the order of the sum (SEP 22 section 6.3), and the transient is one block, bounded by the node chunk the run’s node_budget admits. The radial kind synthesises by node chunk, as before.

solprop.backends.spatial.collect_spatial(spec, grid, transform, field, *, z, flux, profiles=None, physical=None, tables=None, operator=None, axis=None, closure=None)[source]#

Collect spatial statistics without retaining a full physical-space field.

Every field statistic is the axial Poynting flux of the medium at the plane (SEP 34): energy and spectra weigh each column and bin by the real admittance c Re(k_z)/omega of the plane’s root, and local statistics pair the field with its magnetic closure, synthesised from the complex admittance.

Parameters:
specsolprop.stats.StatsSpec

Requested spatial saved-field statistics or scalar profiles.

gridsolprop.grid.TimeGrid

Temporal reconstruction and spectral energy measure.

transformsolprop.translate.modal.Transform

Scalar radial synthesis and plain geometry data from the seam.

fieldnumpy.ndarray

One internal spatial spectrum, shape (n_modes, n_pol, n_omega).

zfloat

Current propagation position in m.

fluxsolprop.translate.spatial.FluxPlan or None

The run’s plane measure; required by every field statistic.

profilescollections.abc.Mapping or None, optional

Named scalar paths, where requested.

physicalnumpy.ndarray or None, optional

Borrowed Cartesian physical-space spectrum, reconstructed into a compiled backend’s persistent scratch. Shape agrees with field.

tablessolprop.spatial.ApertureTables or None, optional

The far-field tables (FarFieldTables), needed by the far-field statistics of SEP 23.

operatorsolprop.translate.spatial.SeparableOperator or None, optional

The run’s separable linear operator, whose rates absorbed_power needs.

axistuple of numpy.ndarray or None, optional

The on-axis amplitude sum_c alpha_c E_c in V/m and its magnetic closure sum_c alpha_c conj(eta_c) E_c, each of shape (n_pol, n_omega), when a compiled pass has formed them (SEP 23 section 6); the axis statistics then read them instead of forming them here.

closurenumpy.ndarray or None, optional

The spectrum’s magnetic closure conj(eta) E at this plane, when a compiled pass has formed it; the local statistics then read it.

Returns:
dict

Scalar or small array values, without the backend’s batch axis.

Raises:
BackendError

If geometry, the plane measure or a requested statistic dependency is missing, or a width is asked of a fluence negative beyond its rounding.

Notes

The far-field statistics are one pass of solprop.spatial.aperture_statistics() over the columns, in chunks of the transform’s node_chunk, reading the plane’s root through solprop.translate.spatial.axial_factors(), the root the stages use.

solprop.backends.spatial.far_field_bands(n_x, n_y, n_slots, n_omega)[source]#

Return the column edges of a compiled far-field pass’s bands.

The units are whole rows on a plane and blocks of LINE_BLOCK columns on a line (n_y == 1); the bands are contiguous runs of units, as many as the units or as FAR_FIELD_BAND_BUDGET admits, whichever is fewer, and at least one. Nothing here depends on the thread count.

Parameters:
n_x, n_yint

The transverse grid’s samples; column ix + n_x*iy.

n_slotsint

The pass’s slots.

n_omegaint

Frequency bins.

Returns:
numpy.ndarray

Ascending column edges, int64, shape (n_bands + 1,), from 0 to n_x*n_y.

Examples

>>> from solprop.backends.spatial import far_field_bands
>>> far_field_bands(4, 3, 2, 8).tolist()
[0, 4, 8, 12]
>>> far_field_bands(130, 1, 2, 8).tolist()
[0, 64, 128, 130]
solprop.backends.spatial.far_field_layout(names, *, n_apertures, n_regions, n_pol, axis_folded=frozenset({'on_axis_intensity', 'on_axis_spectrum'}))[source]#

Lay out the slots a compiled far-field pass accumulates for a request.

Parameters:
namescollections.abc.Collection of str

The statistics asked for; any that the pass does not form are ignored.

n_apertures, n_regionsint

The request’s table rows.

n_polint

The state’s polarisation components.

axis_foldedcollections.abc.Collection of str, optional

The axis statistics that read the W = 1 slot: AXIS_FOLDED on numba_cpu (the default), AXIS_SPECTRUM_ONLY on the native backend.

Returns:
FarFieldLayout or None

The layout, or None when the pass has nothing to form.

Examples

>>> from solprop.backends.spatial import far_field_layout
>>> layout = far_field_layout(
...     ("beam_spectrum", "aperture_spectrum", "on_axis_spectrum"),
...     n_apertures=2, n_regions=0, n_pol=1,
... )
>>> layout.beam, layout.apertures, layout.stride, layout.axis, layout.n_slots
(0, 1, 1, 3, 7)
solprop.backends.spatial.far_field_partials(problem, *, axis_folded=frozenset({'on_axis_intensity', 'on_axis_spectrum'}))[source]#

Return the slots and bands a compiled far-field pass holds for a problem.

Sized from the problem’s own request at construction: its names, tables and polarisations. A Cartesian or line problem whose request forms nothing in the pass (and any other kind) holds none.

Parameters:
problemsolprop.translate.problem.KernelProblem

The translated problem.

axis_foldedcollections.abc.Collection of str, optional

The axis statistics the backend’s pass forms, as for far_field_layout().

Returns:
tuple of int

(n_slots, n_bands), both zero when nothing is held. The partials hold n_bands * n_slots * n_omega float64 values and their band sum n_slots * n_omega.

solprop.backends.spatial.fluence_budget(magnitude, n_terms)[source]#

Return the rounding budget of a signed local fluence (SEP 34 section 5.1).

A node’s fluence (eps0 c/2) dt sum Re(E G*) sums n_pol n_t products of two syntheses over the columns; n_terms counts both sums. A synthesis (a transverse FFT or a dense sum, then the temporal FFT) errs normwise: each node’s value carries rounding of the whole field’s size, which in a beam’s wings far exceeds the value itself. Eight rounding units per term, relative to the largest magnitude (eps0 c/2) dt sum |E| |G| over the nodes, bound every node’s error.

Parameters:
magnitudenumpy.ndarray

The fluence magnitude at each node in J/m^2.

n_termsint

n_pol * n_t + n_modes.

Returns:
numpy.ndarray

The budget in J/m^2 at each node.

solprop.backends.spatial.radial_absorber_matrix(transform, pad_scale)[source]#

Compose the fixed radial rate into one spectral-space matrix.

Parameters:
transformsolprop.translate.modal.Transform

Scalar radial forward/inverse matrices and plain spatial rate data.

pad_scalefloat

Temporal oversampling factor already folded into synthesis.

Returns:
numpy.ndarray

F diag(-alpha/2) B in m^-1, shape (n_r, n_r), or an empty matrix when spatial absorption is absent. No temporal scaling remains.

Notes

The radial rate is independent of time and z. It therefore commutes with temporal Fourier transforms, allowing this construction-time composition. It remains a term in N, separate from the material polarization prefactor. Cartesian rates use transverse FFTs instead of this dense matrix.

solprop.backends.spatial.signed_fluence_widths(geometry, fluence, budget, axis_fluence)[source]#

Return the widths of a signed local fluence, refusing a negative profile.

A fluence negative by more than its rounding budget (fluence_budget()) has no width (SEP 34 section 5.1); within the budget it is rounding and is read as zero.

Parameters:
geometrysolprop.translate.spatial.SpatialGeometry

Radial, Cartesian, line or planar geometry.

fluencenumpy.ndarray

Signed fluence in J/m^2 at the nodes.

budgetnumpy.ndarray

Its rounding budget at each node.

axis_fluencefloat

The on-axis fluence in J/m^2, which the radial widths read.

Returns:
tuple of float

Second-moment, 1/e^2 and FWHM widths in m, as the geometry’s width helper defines them.

Raises:
BackendError

If the fluence is negative beyond its budget anywhere.

solprop.backends.spatial.slab_columns(transform, rows)[source]#

Take a planar state from its (p, y) rows back to (p, k_y) columns.

Parameters:
transformsolprop.translate.modal.Transform

A transform with "slab" geometry.

rowsnumpy.ndarray

Spectra with the n_p * n_y rows first, the channel fastest.

Returns:
numpy.ndarray

The unscaled forward raw DFT in y, the same shape.

solprop.backends.spatial.slab_projection(transform, physical)[source]#

Project spectra at the planar nodes onto the (p, k_y) columns.

Parameters:
transformsolprop.translate.modal.Transform

A transform with "slab" geometry.

physicalnumpy.ndarray

Spectra at the nodes ix + n_x*iy, first axis n_x*n_y.

Returns:
numpy.ndarray

The slab projection in x, then the forward DFT in y, first axis n_p*n_y.

solprop.backends.spatial.slab_rows(transform, columns)[source]#

Take a planar state from its (p, k_y) columns to its (p, y) rows.

The inverse raw DFT in y alone, scaled by 1/n_y. A row is a modal amplitude in sqrt(W/m) at one y sample, whose time signal is real on a field grid, so every per-row temporal operation – a temporal absorber, the y collar – is exact here.

Parameters:
transformsolprop.translate.modal.Transform

A transform with "slab" geometry.

columnsnumpy.ndarray

Spectra with the n_p * n_y columns first, the channel fastest.

Returns:
numpy.ndarray

The same shape, rows p + n_p*iy.

solprop.backends.spatial.slab_synthesis(transform, columns)[source]#

Synthesise a planar state’s field at the (x, y) nodes.

The inverse DFT in y, then the slab synthesis in x – the two commute, and this order transforms the smaller axis first. The synthesis carries the temporal pad scale, so the result is the field the response pass needs on the fine grid.

Parameters:
transformsolprop.translate.modal.Transform

A transform with "slab" geometry.

columnsnumpy.ndarray

Spectra with the n_p * n_y columns first.

Returns:
numpy.ndarray

Spectra at the nodes ix + n_x*iy, shape (n_x*n_y, ...).