solprop.processing.modal#
Physical E and H on a saved plane of a general modal run, and what they measure.
A general modal guide propagates channel amplitudes, and its file stores those: the
mode axis is a coordinate axis and not a physical field. This module is the way back.
Given the run’s own reference tables – the ones
solprop.translate.general.general_modal_route() built, rebuilt from the guide the
file names – it reconstructs E(x, y, t) and H(x, y, t) in V/m and A/m at the
guide’s quadrature nodes, and forms the quantities a detector would see: the
cycle-averaged reconstructed_flux(), the real instantaneous_flux() with its
sum-frequency term, and the per-coordinate coordinate_intensity(), which is
not additive.
What a file carries and what it does not. Output schema 7 records the guide’s
identity – the channel labels, the provider, the sampling, the table and metric
identities – and not the reference arrays themselves, which are tens of megabytes per
run and are rebuilt from the guide in tens of milliseconds (28 ms on the slice’s
one-channel 288-node fixture; about 0.71 s if the guide has still to be solved, which
is where that cost is). Physical profile storage for output is separate from the
execution tables and may be a hash-identified sidecar.
Every function here therefore takes the tables beside the handler and checks them
against the stored identity, path by path, refusing the first entry that disagrees,
so a reconstruction is never made from the wrong guide. guide= is required
beside them, and its sampling and its regions are checked too, which the tables’
identity cannot see: a guide re-sampled at other interior knots, or declaring another
chi3, builds tables whose identity agrees entry for entry. Every
caller has the guide, because that is what the tables were rebuilt from, so there is no
reading of this module in which the narrower check is the one wanted; the keyword has
no default and no alias.
A guide whose geometry moves along z is reconstructed at each plane’s own
position: the guide is solved again there on the rule that has moved with its
interfaces, so the fields come back on that position’s nodes and the flux is weighted
by that position’s areas.
channel_amplitudes() recovers amplitudes on the entrance reference only.
The accessor whitelist. These names are admitted on a general modal basis and
refused on every other, because an orthogonal modal run and a spatial run carry
neither the certified metric nor the E/H reference they promise
(solprop.output.capability). The refusal is the same text the run loop uses.
The manual page is docs/guide/results/output.md.
Functions
|
Recover channel amplitudes from a nodal E/H pair, in the square root of watts. |
|
Return the ordered channel labels a file records for its mode axis. |
|
Return the flux density each channel would carry alone, in W/m^2. |
|
Return the electric field at the guide's nodes on one saved plane, in V/m. |
|
Return the instantaneous Poynting flux of one saved plane, in watts. |
|
Return the magnetic field at the guide's nodes on one saved plane, in A/m. |
|
Return the physical energy through a plane, or through every plane, in joules. |
|
Return where one saved plane is reconstructed: its nodes and area weights. |
|
Return the cycle-averaged Poynting flux of one saved plane, in watts. |
- solprop.processing.modal.channel_amplitudes(electric, magnetic, tables)[source]#
Recover channel amplitudes from a nodal E/H pair, in the square root of watts.
The inverse of the synthesis
electric_field()andmagnetic_field()perform, through the coefficient dual ofModalTransformTables:a_m = sum_q w_q [W^-1]_mn (E x conj(h_n) + conj(e_n) x H)_z / 4, the same Hermitian pairing the flux metric is built from. It is amplitude recovery and not source projection, which carries the separate-i omegafactor.Reprojecting a physical field that was not synthesised from this basis creates a new initial-value problem; it is not a resume path.
- Parameters:
- electricnumpy.ndarray
Nodal electric spectrum, shape
(n_nodes, 3, n_omega), V/m, internal convention.- magneticnumpy.ndarray
Nodal magnetic spectrum, same shape, A/m.
- tablessolprop.translate.modal_tables.ModalTransformTables
The reference the fields were synthesised from, carrying its
coordinate_dual.
- Returns:
- numpy.ndarray
The amplitudes, shape
(n_modes, n_omega), square root of watts.
- Raises:
- solprop.exceptions.OutputError
If the record carries no coefficient dual, or the fields do not match its node and frequency extents.
- solprop.processing.modal.channel_labels(output)[source]#
Return the ordered channel labels a file records for its mode axis.
Output schema 7 persists one
solprop.modes.protocol.ChannelLabelper row of the mode axis, so a plot legend, a selection by name and a resume check all read the same identity. A file written before schema 7 named its channels by class and position and carries none.- Parameters:
- outputsolprop.output.schema.Output
An opened output handler.
- Returns:
- tuple
One label per mode-axis row, in state order.
- Raises:
- solprop.exceptions.OutputError
If the handler holds no record, or the record carries no labels.
Examples
>>> from solprop.processing._examples import example_general_output >>> from solprop.processing.modal import channel_labels >>> [label.display_label for label in channel_labels(example_general_output())] ['HE1,1:even']
- solprop.processing.modal.coordinate_intensity(output, tables, *, plane=None, z=None, guide)[source]#
Return the flux density each channel would carry alone, in W/m^2.
The coordinate decomposition of the intensity: channel
m’s own analytic flux densityRe(E^m x conj(H^m))/2 . z, withE^msynthesised from that channel alone. It is what a per-mode intensity means on a modal basis.It is not additive. The sum over channels of these densities is the physical flux density only where the channels do not interfere; in general the difference is the cross term, which is exactly what
reconstructed_flux()withdensitycarries and this does not. Even a positive spectral metric does not make an instantaneous cross-frequency flux a sum of coordinate powers. Nothing is clipped, here or there.- Parameters:
- outputsolprop.output.schema.Output
An opened output handler holding a general modal run.
- tablessolprop.translate.modal_tables.ModalTransformTables
The run’s own reference; its identity is checked against the file’s.
- planeint or None, optional
Index of the plane wanted, negative from the end.
- zfloat or None, optional
Position of the plane wanted, m. Exactly one of plane and z is given.
- guidesolprop.modes.guide.ModalGuide
The guide the reference was rebuilt from, checked as in
electric_field(). Required.
- Returns:
- numpy.ndarray
The per-channel flux density, shape
(n_modes, n_nodes, n_t), W/m^2.
- Raises:
- solprop.exceptions.OutputError
If the run is not a general modal one, the tables or the guide are not the ones that produced the file, or no single plane was selected.
- solprop.processing.modal.electric_field(output, tables, *, plane=None, z=None, analytic=False, convention='optics', guide)[source]#
Return the electric field at the guide’s nodes on one saved plane, in V/m.
E_i(x_q, t) = sum_m e_i^m(x_q, omega) a_m(omega)transformed back to time, withethe stored reference in V/(m sqrt(W)) andathe saved amplitudes in the square root of watts. The three components areE_x,E_y,E_z. On a guide whose geometry moves along z,eand the nodes are the guide’s at the plane’s own position, solved again there (the module’s notes).- Parameters:
- outputsolprop.output.schema.Output
An opened output handler holding a general modal run.
- tablessolprop.translate.modal_tables.ModalTransformTables
The run’s own reference, rebuilt from the guide the record names; its identity is checked against the file’s.
- planeint or None, optional
Index of the plane wanted, negative from the end.
- zfloat or None, optional
Position of the plane wanted, m. Exactly one of plane and z is given.
- analyticbool, optional
Return the complex analytic signal instead of the real physical field. The real field is
numpy.realof it, and the two flux accessors differ in exactly this choice.- convention{‘optics’, ‘fft’}, optional
Sign convention of the analytic signal, as every other accessor of
solprop.processingtakes it and with the same default: the optics convention ofdocs/dev/conventions.mdsection 2 unless'fft'asks for the internal one the reference is solved in. The real field is convention-free, so this is read only with analytic.- guidesolprop.modes.guide.ModalGuide
The guide the reference was rebuilt from. Its sampling and its regions are checked against the file’s own guide identity, which the tables’ identity cannot see. It is required and has no default.
- Returns:
- numpy.ndarray
The field, shape
(n_nodes, 3, n_t), V/m; real unless analytic.
- Raises:
- solprop.exceptions.OutputError
If the run is not a general modal one, the tables or the guide are not the ones that produced the file, or no single plane was selected.
- solprop.processing.modal.instantaneous_flux(output, tables, *, plane=None, z=None, density=False, guide)[source]#
Return the instantaneous Poynting flux of one saved plane, in watts.
(E x H) . zof the real fields, integrated over the cross-section. It carries the sum-frequency term the cycle-averagedreconstructed_flux()drops – the oscillation at twice the carrier – and averages to it over a cycle. Which one a measurement wants is a statement about the detector: an instrument slower than the carrier sees the analytic flux, and a field-resolved measurement sees this one.The sum-frequency oscillation is aliased when the grid does not resolve it. The trace is formed from products of two real fields sampled on the run’s own time axis, so the term at
2 omega_0is only representable while2 omega_0is below the grid’s Nyquist frequency. The sample values are exact either way – each is the product of two exact samples – and so is the integral identity below; what moves is the apparent frequency of the plotted oscillation, which folds toabs(2 omega_0 - 2 omega_Nyq). A field grid declared for a carrier near the top of its band will therefore show a slow ripple where the physical one is fast, and a plot that means to show the carrier beat needs a window sampled for it.int inst dtequalsint analytic dtwhen no sum-frequency content folds onto DC: the cross terms are an integer number of cycles in the window and integrate away only while none of them aliases to zero frequency. That holds whenever the spectrum’s support, doubled, stays clear of the sampling frequency’s multiples, which a run whose carrier is inside its declared band satisfies.- Parameters:
- outputsolprop.output.schema.Output
An opened output handler holding a general modal run.
- tablessolprop.translate.modal_tables.ModalTransformTables
The run’s own reference; its identity is checked against the file’s.
- planeint or None, optional
Index of the plane wanted, negative from the end.
- zfloat or None, optional
Position of the plane wanted, m. Exactly one of plane and z is given.
- densitybool, optional
Return the flux density at each node,
(n_nodes, n_t)in W/m^2, instead of its weighted sum over the cross-section.- guidesolprop.modes.guide.ModalGuide
The guide the reference was rebuilt from, checked as in
electric_field(). Required.
- Returns:
- numpy.ndarray
The flux, shape
(n_t,)in W, or(n_nodes, n_t)in W/m^2 with density.
- Raises:
- solprop.exceptions.OutputError
If the run is not a general modal one, the tables or the guide are not the ones that produced the file, or no single plane was selected.
- solprop.processing.modal.magnetic_field(output, tables, *, plane=None, z=None, analytic=False, convention='optics', guide)[source]#
Return the magnetic field at the guide’s nodes on one saved plane, in A/m.
The partner of
electric_field(), from the storedmagneticreference in A/(m sqrt(W)). The pair is what makes a flux: the provider normalises every channel to unit longitudinal Poynting flux, soint Re(E x conj(H))/2 . z dAis one watt for a unit amplitude and the reconstruction carries SI units throughout.- Parameters:
- outputsolprop.output.schema.Output
An opened output handler holding a general modal run.
- tablessolprop.translate.modal_tables.ModalTransformTables
The run’s own reference; its identity is checked against the file’s.
- planeint or None, optional
Index of the plane wanted, negative from the end.
- zfloat or None, optional
Position of the plane wanted, m. Exactly one of plane and z is given.
- analyticbool, optional
Return the complex analytic signal instead of the real physical field.
- convention{‘optics’, ‘fft’}, optional
Sign convention of the analytic signal, as
electric_field()takes it and with the same default.- guidesolprop.modes.guide.ModalGuide
The guide the reference was rebuilt from, checked as in
electric_field(). Required.
- Returns:
- numpy.ndarray
The field, shape
(n_nodes, 3, n_t), A/m; real unless analytic.
- Raises:
- solprop.exceptions.OutputError
If the run is not a general modal one, the tables or the guide are not the ones that produced the file, or no single plane was selected.
- solprop.processing.modal.physical_energy(output, *, plane=None, z=None)[source]#
Return the physical energy through a plane, or through every plane, in joules.
solprop.stats.physical_energy(), which is the same-frequency product of the state with the basis’s flux metric integrated over frequency, so a number read off a file and the number the run recorded agree to the bit. It is a scalar per plane because a coordinate energy is not additive on a basis that is not orthonormal. Output schema 7 records the metric’s identity and not its arrays, so this accessor evaluates the unweighted form and refuses by name a record whosemodal.metric.kindis not"identity"– the number it could form from the stored state alone is the answer for a different basis. Read the run’s own recordedphysical_energystatistic, orreconstructed_flux()here, which reconstructs the physical flux from the guide’s stored reference and needs no metric at all.- Parameters:
- outputsolprop.output.schema.Output
An opened output handler holding a general modal run.
- planeint or None, optional
Index of the plane wanted, negative from the end; with neither plane nor z, every plane is returned with a leading
n_zaxis.- zfloat or None, optional
Position of the plane wanted, m.
- Returns:
- numpy.ndarray
The energy, J, a scalar per plane.
- Raises:
- solprop.exceptions.OutputError
If the run is not a general modal one. If the recorded basis metric is not the identity, so that the weighted energy cannot be formed from the stored state.
Examples
>>> import numpy as np >>> from solprop.processing._examples import example_general_output >>> from solprop.processing.modal import physical_energy >>> values = physical_energy(example_general_output()) >>> bool(np.allclose(values, values[0], rtol=1e-12)) True
- solprop.processing.modal.plane_nodes(output, tables, *, plane=None, z=None, guide)[source]#
Return where one saved plane is reconstructed: its nodes and area weights.
The field accessors of this module return values at the guide’s quadrature nodes and integrate them with its area weights; this returns those nodes and weights, in the same order as the node axis of
electric_field(),reconstructed_flux()withdensity=Trueandcoordinate_intensity(). For a guide whose geometry does not move they are the tables’ own, the same at every plane. For a moving guide they are the plane’s own: the rule that has moved with the interfaces to that plane’s position, which is the provider’s rule asked for there exactly as the entrance rule was (solprop.translate.modal_path.path_rule()) – the same rule the field accessors solve on, so no caller needs the translation layer to plot a plane.- Parameters:
- outputsolprop.output.schema.Output
An opened output handler holding a general modal run.
- tablessolprop.translate.modal_tables.ModalTransformTables
The run’s own reference; its identity is checked against the file’s.
- planeint or None, optional
Index of the plane wanted, negative from the end.
- zfloat or None, optional
Position of the plane wanted, m. Exactly one of plane and z is given.
- guidesolprop.modes.guide.ModalGuide
The guide the reference was rebuilt from, checked as in
electric_field(). Required.
- Returns:
- tuple of numpy.ndarray
The node positions
(x, y)in the cross-section, shape(n_nodes, 2)in m, and their area weights, shape(n_nodes,)in m^2, so thatweights @ reconstructed_flux(..., density=True)isreconstructed_flux(...).
- Raises:
- solprop.exceptions.OutputError
If the run is not a general modal one, the tables or the guide are not the ones that produced the file, no single plane was selected, or a moving guide cannot be solved again at the plane’s position.
Examples
>>> import numpy as np >>> from solprop.processing._examples import example_general_run >>> from solprop.processing.modal import plane_nodes, reconstructed_flux >>> run, tables, guide = example_general_run() >>> xy, weights = plane_nodes(run, tables, plane=-1, guide=guide) >>> xy.shape == (weights.size, 2) True >>> density = reconstructed_flux(run, tables, plane=-1, density=True, guide=guide) >>> flux = reconstructed_flux(run, tables, plane=-1, guide=guide) >>> bool(np.allclose(weights @ density, flux, rtol=1e-12, atol=0.0)) True
- solprop.processing.modal.reconstructed_flux(output, tables, *, plane=None, z=None, density=False, guide)[source]#
Return the cycle-averaged Poynting flux of one saved plane, in watts.
Re(E_a x conj(H_a))/2 . zintegrated over the cross-section with the guide’s own area weights, from the reconstructed analytic fields. This is the physical power through the plane at each instant, a trace in time, and it is not the trace the run statisticsolprop.stats.analytic_flux()is the maximum of (hence the different name): that statistic is a scalar, the peak of the same-frequency diagonal,max_t sum_m |a_m(t)|^2, while this carries the guide’s cross-frequency flux kernelK_ij = sum_q w_q [e_x(w_i) conj(h_y(w_j)) - e_y(w_i) conj(h_x(w_j))]/2as well. The two peaks differ by at mostsum_ij |B_i||B_j||K_ij - 1|, measured at 1.3e-5 of the peak inside a bound of 3.4e-5 on the general-basis test fixture; their time integrals agree, because the cross-frequency terms are an integer number of cycles in the window. This one is the quantity a detector sees.Negative values are kept. A broadband field’s Hermitian flux can go negative where two channels interfere; clipping it would make the trace look like a power and stop it integrating to the right energy.
- Parameters:
- outputsolprop.output.schema.Output
An opened output handler holding a general modal run.
- tablessolprop.translate.modal_tables.ModalTransformTables
The run’s own reference; its identity is checked against the file’s.
- planeint or None, optional
Index of the plane wanted, negative from the end.
- zfloat or None, optional
Position of the plane wanted, m. Exactly one of plane and z is given.
- densitybool, optional
Return the flux density at each node,
(n_nodes, n_t)in W/m^2, instead of its weighted sum over the cross-section.- guidesolprop.modes.guide.ModalGuide
The guide the reference was rebuilt from, checked as in
electric_field(). Required.
- Returns:
- numpy.ndarray
The flux, shape
(n_t,)in W, or(n_nodes, n_t)in W/m^2 with density.
- Raises:
- solprop.exceptions.OutputError
If the run is not a general modal one, the tables or the guide are not the ones that produced the file, or no single plane was selected.