solprop.processing.axes#
Rebuild the axes and the layout of a saved run from its grid record.
A saved run carries a solprop.output.schema.GridRecord – scalars only, so that
the metadata stays small and its digest cheap – and not the
solprop.grid.TimeGrid it was computed on. Everything else in
solprop.processing needs the axes back, and solprop.stats needs a grid
object, so this module is the one place that rebuilds them.
Two things the rest of the package can then rely on. First, the frequency axis is stored
in the layout the kernels use: non-negative and increasing on a field grid, in FFT order
about omega0 on an envelope grid (conventions.md section 3). Processing shows an
ascending axis, and spectral_order() is the permutation that gets there.
Second, the accessors work on the grid’s active band by default, which is what keeps
the wavelength axis finite and the selection contiguous.
Module Attributes
Which spectral abscissa a density is expressed on. |
|
The spectral abscissae, in SI units: rad/s, Hz and m. |
|
Which part of the stored spectrum an accessor returns. |
|
|
|
A mode index, several, the incoherent sum over all of them, or all of them. |
Functions
|
Return the mask of the bins an accessor keeps, on the stored axis. |
|
Rebuild a grid from the scalars a saved run records. |
|
Return the grid a saved run was computed on. |
|
Return the shape of a saved run as |
|
Return a spectral abscissa and the Jacobian that maps a density onto it. |
|
Return the permutation that sorts the stored frequency axis ascending. |
|
Return the units a saved run's powers and energies are in. |
Classes
|
The units a run's transverse integrals come out in, for labels. |
- solprop.processing.axes.BANDS: tuple[Literal['active', 'all'], ...] = ('active', 'all')#
'active'is the propagated band,'all'every stored bin.
- solprop.processing.axes.Band#
Which part of the stored spectrum an accessor returns.
alias of
Literal[‘active’, ‘all’]
- solprop.processing.axes.ModeSelection = int | collections.abc.Sequence[int] | typing.Literal['sum'] | None#
A mode index, several, the incoherent sum over all of them, or all of them.
- solprop.processing.axes.SPECTRAL_AXES: tuple[Literal['omega', 'f', 'wavelength'], ...] = ('omega', 'f', 'wavelength')#
The spectral abscissae, in SI units: rad/s, Hz and m.
- solprop.processing.axes.SpectralAxis#
Which spectral abscissa a density is expressed on.
alias of
Literal[‘omega’, ‘f’, ‘wavelength’]
- class solprop.processing.axes.TransverseUnits(measure, power, energy, intensity='W/m^2', fluence='J/m^2')[source]#
Bases:
objectThe units a run’s transverse integrals come out in, for labels.
- Attributes:
- measure{‘area’, ‘per_unit_width’}
What the run’s transverse integrals measure (
solprop.modes.protocol.TransverseMeasure).- powerstr
"W", or"W/m"per metre of y.- energystr
"J", or"J/m"per metre of y.- intensitystr
"W/m^2"for both: an intensity is local.- fluencestr
"J/m^2"for both, for the same reason.
Examples
>>> from solprop.processing.axes import TransverseUnits >>> TransverseUnits.of("per_unit_width").energy 'J/m'
- classmethod of(measure)[source]#
Return the units of a measure.
- Parameters:
- measure{‘area’, ‘per_unit_width’}
What the transverse integrals measure.
- Returns:
- TransverseUnits
The labels. The measure is already validated where it is read (
solprop.output.schema.RunMetadata.transverse_measure).
- solprop.processing.axes.band_mask(grid, band='active')[source]#
Return the mask of the bins an accessor keeps, on the stored axis.
'active'is the propagated bandomega_min/2 < omega < 1.1 omega_max, which is the only region where the dispersion relation, the noise and the error norm are defined;'all'keeps every stored bin, including the zero and Nyquist bins of a field grid, where a wavelength is not defined.- Parameters:
- gridsolprop.grid.TimeGrid
The grid the stored spectrum lives on.
- band{‘active’, ‘all’}
Which part of the axis to keep.
- Returns:
- numpy.ndarray
Boolean mask, shape
(n_omega,), in storage order.
- Raises:
- solprop.exceptions.ProcessingError
If
bandis not one ofBANDS.
Examples
>>> from solprop.grid import FieldGrid >>> from solprop.processing.axes import band_mask >>> grid = FieldGrid.from_limits(1.0, 800e-9, (400e-9, 2e-6), 1e-12) >>> int(band_mask(grid, "all").sum()) == grid.n_omega True
- solprop.processing.axes.grid_from_record(record)[source]#
Rebuild a grid from the scalars a saved run records.
Every axis and both collars come back exactly: they are functions of the recorded sizes, spacings, band limits and collar edges alone, evaluated by the expressions that built them. The grid exists so that
solprop.statscan be called with the definitions it already owns.- Parameters:
- recordsolprop.output.schema.GridRecord
The grid record of the run.
- Returns:
- solprop.grid.TimeGrid
A
FieldGridorEnvelopeGrid, validated.
- Raises:
- solprop.exceptions.GridError
If the record’s scalars do not satisfy the grid invariants.
Examples
>>> from solprop.grid import EnvelopeGrid >>> from solprop.output.schema import GridRecord >>> from solprop.processing.axes import grid_from_record >>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (400e-9, 2e-6), 2e-12) >>> rebuilt = grid_from_record(GridRecord.from_grid(grid)) >>> rebuilt.kind, bool((rebuilt.t == grid.t).all()) ('envelope', True)
- solprop.processing.axes.grid_of(output)[source]#
Return the grid a saved run was computed on.
- Parameters:
- outputsolprop.output.schema.Output
A memory or HDF5 output handler that has been opened.
- Returns:
- solprop.grid.TimeGrid
The rebuilt grid, as
grid_from_record()returns it.
- Raises:
- solprop.exceptions.OutputError
If the handler carries no metadata, so there is no record to rebuild from.
Examples
>>> from solprop.processing.axes import grid_of >>> from solprop.processing._examples import example_output >>> grid_of(example_output()).kind 'envelope'
- solprop.processing.axes.layout(output)[source]#
Return the shape of a saved run as
(n_z, n_modes, n_pol, n_omega).The mode and polarisation counts are not in the metadata – a mode-averaged run records no modes at all – so they are read off the stored field, which on an HDF5 handler means reading it.
- Parameters:
- outputsolprop.output.schema.Output
A memory or HDF5 output handler that has been opened and holds at least one plane.
- Returns:
- tuple of int
(n_z, n_modes, n_pol, n_omega).
Examples
>>> from solprop.processing.axes import layout >>> from solprop.processing._examples import example_output >>> layout(example_output())[1:3] (1, 1)
- solprop.processing.axes.spectral_axis(omega, axis)[source]#
Return a spectral abscissa and the Jacobian that maps a density onto it.
The spectral energy density is per unit of whatever abscissa it is quoted on, so a change of variable carries
|d omega / dx|: one for angular frequency,2 pifor frequency andomega^2 / (2 pi c) = 2 pi c / lambda^2for wavelength. Units are SI: rad/s, Hz and m, so the densities are J/(rad/s), J/Hz and J/m.The wavelength abscissa decreases where
omegaincreases; sorting it is the caller’s business, because the same permutation has to be applied to the density.- Parameters:
- omeganumpy.ndarray
Angular frequency axis, shape
(n_omega,), rad/s.- axis{‘omega’, ‘f’, ‘wavelength’}
The abscissa wanted.
- Returns:
- xnumpy.ndarray
The abscissa, shape
(n_omega,), in rad/s, Hz or m.- jacobiannumpy.ndarray
The factor that multiplies a density per rad/s to give one per unit of
x, shape(n_omega,).
- Raises:
- solprop.exceptions.ProcessingError
If
axisis not one ofSPECTRAL_AXES, or if a wavelength is asked for on an axis that reaches zero frequency, where it is not defined.
Examples
>>> import numpy as np >>> from solprop.processing.axes import spectral_axis >>> x, jacobian = spectral_axis(np.array([2.0e15, 3.0e15]), "f") >>> float(x[0]) / 1e14, float(jacobian[0]) (3.183098861837907, 6.283185307179586)
- solprop.processing.axes.spectral_order(grid)[source]#
Return the permutation that sorts the stored frequency axis ascending.
The identity on a field grid, whose axis is already increasing, and the FFT shift on an envelope grid, whose axis runs from the carrier up and then wraps to the bins below it. Applying it is what
conventions.mdsection 3 means by “processing shifts for display”.- Parameters:
- gridsolprop.grid.TimeGrid
The grid the stored spectrum lives on.
- Returns:
- numpy.ndarray
Indices into the stored axis, shape
(n_omega,), such thatgrid.omega[order]increases.
Examples
>>> import numpy as np >>> from solprop.grid import EnvelopeGrid >>> from solprop.processing.axes import spectral_order >>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (400e-9, 2e-6), 2e-12) >>> order = spectral_order(grid) >>> bool(np.all(np.diff(grid.omega[order]) > 0)) True
- solprop.processing.axes.transverse_units(output)[source]#
Return the units a saved run’s powers and energies are in.
A run on modes uniform in y – the hollow planar guide of
solprop.modes.slab.SlabMode– records that its transverse integrals are per metre of y (solprop.output.schema.RunMetadata.transverse_measure): its powers, energies and the processing functions that integrate them are then in W/m and J/m, from the same formulas. A handler without metadata is taken to measure an area, as every run did before the key existed.- Parameters:
- outputsolprop.output.schema.Output
An opened output handler.
- Returns:
- TransverseUnits
The unit labels.
Examples
>>> from solprop.processing.axes import transverse_units >>> from solprop.processing._examples import example_output >>> transverse_units(example_output()).power 'W'