solprop.coupling.elements#
Linear optical elements acting on a spatial field between planes (SEP 31 §4.6).
Each element is a frozen record with an apply method that takes a
SpatialState – a radial or Cartesian spectrum with its temporal grid, its
homogeneous medium and its oriented local frame – and returns the new state with an
ElementReport. The stored spectrum keeps the layout and units of
solprop.pulses.SpatialPulse.build(): the internal (FFT) temporal convention,
a raw order-zero Hankel spectrum in V m on a solprop.grid.RadialGrid or a
raw two-dimensional DFT in V/m on a solprop.grid.FreeGrid, shape
(n_modes, n_pol, n_omega). Every physical expression in this module – the
propagation phase \(e^{+ik_zL}\), a lens \(e^{-ikr^2/(2f)}\), a mask, a
Jones matrix or a reflection coefficient – is written in the optics convention of
docs/dev/conventions.md section 2 and crosses to the stored spectrum as its
complex conjugate, as solprop.optics.stored_factor() does for a transfer
function. Transverse transforms are not conjugated: they act on positions, which
are the same in both conventions.
A FieldPlane is carried through a sequence of these
elements by solprop.coupling.transport(), which converts it to this state and
back and updates its reference, geometry, medium and metric; the state and the
Element protocol are the interface a new element is written against. Every
refusal raises solprop.exceptions.CouplingError.
Energies are physical: the axial Poynting flux of the medium at the plane,
solprop.spatial.SpatialFlux and solprop.spatial.spatial_energy()
(SEP 34). Every report closes its own ledger in joules,
so the approximation error is the signed part of the energy change that neither a declared loss nor an intentional removal explains.
Classes
|
A lateral displacement and a paraxial tilt of a Cartesian field. |
|
An aperture built on the SEP 23 edge profile, with its weighting declared. |
|
A linear element between two planes. |
|
The accounting of one element's application (SEP 31 §4.7). |
|
The state after an element and the report of its application. |
|
Homogeneous propagation over a distance, \(e^{+ik_zL}\) per frequency. |
|
A flat mirror: spectral p/s reflection and the incoming/outgoing frame map. |
|
A plane boundary between two lossless media, at normal incidence. |
|
A spatially uniform Jones matrix in the plane's local |
|
The single-field thin-screen admission record of SEP 31 §4.6. |
|
A spatial field at one plane, with its grids, medium and local frame. |
|
Which affine spectral phase a frequency-only element removes or keeps. |
|
A frequency-only transfer function acting coherently on every sample. |
|
A thin paraxial lens, the phase screen \(e^{-ik(\omega)r^2/(2f(\omega))}\). |
|
A complex field transmission, as a function or as samples at the nodes. |
- class solprop.coupling.elements.Alignment(displacement=(0.0, 0.0), tilt=(0.0, 0.0), model_error=None)[source]#
Bases:
objectA lateral displacement and a paraxial tilt of a Cartesian field.
The field is tilted about the plane’s origin and then displaced rigidly:
E'(x, y) = T(x - d_x, y - d_y) E(x - d_x, y - d_y)with the optics-convention tiltT = exp(+i k (x sin(theta_x) + y sin(theta_y))),kthe medium’s real wave number. A positive displacement moves the beam towards +x (+y); a positive tilt makes it propagate towards +x (+y). The displacement is exact in the periodic DFT representation; the tilt is a phase screen certified against model_error. A radial grid refuses both.- Attributes:
- displacementtuple of float
(d_x, d_y)in m, finite. Default no displacement.- tilttuple of float
(theta_x, theta_y)in rad, finite, each below pi/2 in magnitude. Default no tilt.- model_errorfloat or None
Thin-screen budget in (0, 1), required for a nonzero tilt.
- class solprop.coupling.elements.Aperture(radius, model_error, edge=0.0, kind='hard', centre=(0.0, 0.0), weighting='amplitude')[source]#
Bases:
objectAn aperture built on the SEP 23 edge profile, with its weighting declared.
solprop.spatial.aperture_profile()gives the edge profileW. Its meaning is fixed by weighting, exactly as for the in-run aperture statistics ofsolprop.stats.ApertureSet:'amplitude'(the default) takesWas the field transmission, so the power goes asW**2;'quadrature'takesWas a power weight, applied to the field assqrt(W). SEP 31 §4.6’s intensity-defined aperture is the'quadrature'case. A hard aperture (Wzero or one) is the same either way.- Attributes:
- radiusfloat
Half-width of the profile in m, finite and positive.
- model_errorfloat
Required thin-screen budget in (0, 1).
- edgefloat
Edge width in m for
tanhandrcos, order forsupergauss, unused forhard. Default 0.- kind{‘hard’, ‘tanh’, ‘rcos’, ‘supergauss’}
Edge profile. Default
'hard'.- centretuple of float
Centre
(x, y)in m in the local frame; a radial grid needs the axis.- weighting{‘amplitude’, ‘quadrature’}
'amplitude'appliesWto the field,'quadrature'appliessqrt(W). Default'amplitude'.
Examples
>>> from solprop.coupling import Aperture >>> Aperture(1e-3, model_error=1e-2, weighting="quadrature").weighting 'quadrature'
- class solprop.coupling.elements.Element(*args, **kwargs)[source]#
Bases:
ProtocolA linear element between two planes.
- class solprop.coupling.elements.ElementReport(element, position, energy_in, energy_out, specified_loss, removed, approximation_error, numerical_error, spectrum_in, spectrum_out, certificate=None, calibration=(), reconstruction=False, diagnostics=<factory>, notes=())[source]#
Bases:
objectThe accounting of one element’s application (SEP 31 §4.7).
Energies are the physical axial flux of the plane’s medium (SEP 34) on the whole represented plane. They satisfy
energy_out = energy_in - specified_loss - removed + approximation_errorexactly.- Attributes:
- elementstr
A short description of the element.
- positionint
Index of the element in a transport sequence; 0 when applied alone.
- energy_in, energy_outfloat
Energy crossing the input and output planes, J.
- specified_lossfloat
Loss the element declares: material absorption, reflection, a mask’s local loss \(L_0\) or a transfer function’s attenuation, J.
- removedfloat
Energy intentionally removed: an explicit angular band limit, or the bins a transfer function sets to exactly zero, J.
- approximation_errorfloat
Signed remainder of the ledger, J: the thin-screen axial-flux defect, obliquity at an interface, output-window truncation and resampling, or rounding for an exact element. Never absorption.
- numerical_errorfloat
Estimated numerical energy error of the representation, J.
- spectrum_in, spectrum_outnumpy.ndarray
Energy per temporal bin at the input and output planes, J, shape
(n_omega,); each sums to its energy.- certificateScreenCertificate or None
The thin-screen certificate of a lens, mask, aperture or tilt.
- calibrationtuple of SpectralCalibration
One record per frequency-only factor; empty for a spatial element.
- reconstructionbool
True for an operation that is not a passive physical element: a negative length, an inverse phase or a backward propagation.
- diagnosticscollections.abc.Mapping
Element-specific numbers (sampling and wrap shares, bounds), read-only.
- notestuple of str
Element-specific statements, such as the factors of a chain.
- calibration: tuple[SpectralCalibration, ...] = ()#
- certificate: ScreenCertificate | None = None#
- spectrum_in: Float[ndarray, 'n_omega_in']#
- spectrum_out: Float[ndarray, 'n_omega_out']#
- class solprop.coupling.elements.ElementResult(state, report)[source]#
Bases:
objectThe state after an element and the report of its application.
- Attributes:
- stateSpatialState
The field at the element’s output plane.
- reportElementReport
Its accounting.
- report: ElementReport#
- state: SpatialState#
- class solprop.coupling.elements.FreeSpace(distance, medium, output=None, output_method='angular', band_limit=None, frame_delay=None, frame_phase=0.0, evanescent_tolerance=None, sampling_tolerance=1e-06, edge_tolerance=0.0001, beyond_window='refuse')[source]#
Bases:
objectHomogeneous propagation over a distance, \(e^{+ik_zL}\) per frequency.
\(k_z=\sqrt{(\omega n/c)^2-\kappa^2}\) at each absolute frequency and transverse wave number, on the order-zero Hankel columns of a radial grid or the DFT columns of a Cartesian one. An affine frame term is removed from the whole field, \(e^{-i(\phi_f+\omega\tau_f)}\), so that the pulse stays in its window; the report records
delay_removedandphase_removedandsolprop.coupling.transport()adds them to the plane’s reference.Without output the field stays on its grid, propagated exactly in its periodic (Cartesian) or Dirichlet (radial) representation. A column at angle \(\theta\) moves its rays by \(L\tan\theta\); content whose rays leave the window would wrap (or reflect), which is the same condition as sampling the propagator’s phase \(k_zL\) below its Nyquist rate in \(\kappa\). Content beyond
sampling_toleranceis refused, unlessbeyond_window='remove'declares its removal, which is then reported as removed energy. A propagated field whose share in the window’s outer band (the declared collar, or the outer tenth of each half-width) exceedsedge_toleranceis refused too: it is already meeting the periodic or reflecting edge, which the ray test does not see. With output, a plane of another radius or sampling is evaluated by chunked direct summation; the method is always the caller’s explicit choice:output_method='angular'sums the propagated source spectrum at the output nodes (\(\sum_j v_jH_jJ_0(k_j\rho)/2\pi\) or the trigonometric interpolant), exact and nonparaxial, inside the source window only; the field must stay away from the source window’s edge.output_method='fresnel'evaluates the Fresnel integral of the source samples (zero outside the source window) at the output nodes with the paraxial kernel, radial \(\frac{k}{iL}e^{ikL}e^{ik\rho^2/2L}\int E\,e^{ikr^2/2L}J_0(k\rho r/L)r\,dr\), Cartesian separably. It reaches any observation window; its paraxial phase bound \(k(\rho_{\max}+r_{\rm occ})^4/(8L^3)\) is reported, and an undersampled kernel is refused.
Significant evanescent content is refused rather than capped, unless an explicit band_limit removes it, with the removed energy reported.
- Attributes:
- distancefloat
Propagation distance in m, finite; negative back-propagates and is flagged as a reconstruction.
- mediumsolprop.spatial.SpatialMedium
The homogeneous medium of the gap; must be the plane’s medium (a change of medium is a
PlanarInterface).- outputsolprop.grid.RadialGrid, solprop.grid.FreeGrid or None
Output plane of the same kind as the source; None keeps the source grid.
- output_method{‘angular’, ‘fresnel’}
How an output plane is evaluated. Default
'angular'.- band_limitfloat or None
Largest retained propagation angle in rad, in (0, pi/2]; columns beyond it, and every nonpropagating column, are removed and reported. None removes nothing.
- frame_delayfloat or None
Delay \(\tau_f\) in s removed from the whole field; None removes the group delay of the medium at the grid’s reference frequency,
beta1(omega0) L.solprop.coupling.transport()fills it from the plane’s frame when it is given one.- frame_phasefloat
Constant phase \(\phi_f\) in rad removed with the delay. Default 0.
- evanescent_tolerancefloat or None
Largest admitted reference-measure share of nonpropagating content; None is the rounding budget of the transforms that formed the field.
- sampling_tolerancefloat
Largest admitted reference-measure share of content whose rays leave the window (same-grid and angular routes), of field at the source edge (angular output) and of aliased content (Fresnel output). Default 1e-6.
- edge_tolerancefloat
Largest admitted reference-measure share of the propagated field in the window’s outer band on the same-grid route. Default 1e-4: on a radial window without a collar a Gaussian beam meets it when the window’s radius is about 2.4 times its 1/e^2 radius, and the well-resolved transports of the coupling chapter stay at or below a few 1e-6.
- beyond_window{‘refuse’, ‘remove’}
What to do with content whose rays leave the window over the distance: refuse it (the default), or remove it explicitly as an angular band, reported as
removedwithwindow_removedin the diagnostics.
Examples
>>> from solprop.coupling import FreeSpace >>> from solprop.spatial import SpatialMedium >>> FreeSpace(0.5, SpatialMedium(), beyond_window="remove").beyond_window 'remove'
- apply(state)[source]#
Propagate the plane.
- Parameters:
- stateSpatialState
The input plane.
- Returns:
- ElementResult
The output plane and the report, whose diagnostics include
delay_removedin s andphase_removedin rad.
- Raises:
- CouplingError
If the element is invalid, the medium is not the plane’s, the field holds significant evanescent content, its rays wrap beyond the window, the propagated field fills the window’s outer band on the same grid, the angular output leaves the source window, or the Fresnel kernel is undersampled.
- medium: SpatialMedium#
- output: RadialGrid | FreeGrid | None = None#
- class solprop.coupling.elements.Mirror(reflectivity_p, reflectivity_s, incident, outgoing, s_axis)[source]#
Bases:
objectA flat mirror: spectral p/s reflection and the incoming/outgoing frame map.
Each beam has the right-handed local frame \((\hat p,\hat s,\hat k)\) with \(\hat p=\hat s\times\hat k\), for incoming and outgoing directions alike. A field with components \((E_p,E_s)\) leaves as \((r_pE_p,r_sE_s)\) on \((\hat p_{\rm out},\hat s)\); there is no conjugation. The outgoing local axes have the same p/s components as the incoming ones, so the frame stays right-handed, and the improper reflection appears as a mirror image of the transverse pattern along p (SEP 31 §4.6). In this convention a perfect conductor at any incidence has \(r_s=-1, r_p=+1\), and a dielectric at normal incidence \(r_p=-r_s\); coefficients calibrated in another p/s convention must be converted first.
- Attributes:
- reflectivity_p, reflectivity_scomplex or callable
Optics-convention amplitude reflection coefficients, constants or functions of positive angular frequency in rad/s;
|r| <= 1.- incidentsequence of float or numpy.ndarray
Incoming propagation direction in laboratory coordinates; must match the plane’s forward axis.
- outgoingsequence of float or numpy.ndarray
Outgoing propagation direction; not parallel to incident.
- s_axissequence of float or numpy.ndarray
Direction perpendicular to both, hence normal to the plane of incidence when there is one; at normal incidence it resolves the degeneracy. Its sign does not change the map.
- apply(state)[source]#
Reflect the plane.
- Parameters:
- stateSpatialState
The input plane, propagating along incident.
- Returns:
- ElementResult
The reflected plane in its outgoing frame, and the report.
- Raises:
- CouplingError
If the geometry is invalid, the plane does not propagate along incident, a coefficient exceeds one in modulus, or the mirror image cannot be represented exactly on a Cartesian grid.
- class solprop.coupling.elements.PlanarInterface(first, second)[source]#
Bases:
objectA plane boundary between two lossless media, at normal incidence.
Tangential E/H continuity gives \(t_E=2n_1/(n_1+n_2)\) and \(r_E=(n_1-n_2)/(n_1+n_2)\) per frequency, with \(T=(n_2/n_1)|t_E|^2\) and \(R+T=1\). The factor is applied to every angular column, and the departure of an oblique column’s flux from the normal-incidence coefficient is reported as approximation error. The output plane is in second, so a second application of the same interface is refused: a Fresnel factor is applied once.
- Attributes:
- firstsolprop.spatial.SpatialMedium
The incident medium; must be the plane’s medium.
- secondsolprop.spatial.SpatialMedium
The transmitted medium.
- apply(state)[source]#
Transmit the plane through the interface.
- Parameters:
- stateSpatialState
The input plane, in first.
- Returns:
- ElementResult
The transmitted plane, in second, and the report.
- Raises:
- CouplingError
If the plane is not in first or either medium is lossy.
- first: SpatialMedium#
- second: SpatialMedium#
- class solprop.coupling.elements.PolarisationTransform(jones)[source]#
Bases:
objectA spatially uniform Jones matrix in the plane’s local
(x, y)axes.- Attributes:
- jonesarray_like or callable
Optics-convention 2x2 matrix acting on
(E_x, E_y), or a function of positive angular frequency in rad/s returning shape(n_band, 2, 2). Passive: singular values of at most one.
Examples
>>> import numpy as np >>> from solprop.coupling.elements import PolarisationTransform >>> PolarisationTransform(np.diag([1.0, -1.0])).jones.shape (2, 2)
- class solprop.coupling.elements.ScreenCertificate(model_error, cone_cosine, defect_in, defect_out, reference_energy, numerical_error, ratio, exact_zero, scope='single field')[source]#
Bases:
objectThe single-field thin-screen admission record of SEP 31 §4.6.
A thin screen is exact in the local reference measure \(U_0=\int Y_0|\tilde E|^2\,d\kappa\,d\omega/2\) with \(Y_0=\operatorname{Re}n\,\varepsilon_0c\); the physical axial energy \(U_Y\) weighs each plane wave by \(\cos\theta\) in a transparent medium. With \(1-\cos\theta_*=\epsilon_m/8\), the defect \(d(E)=(1-\cos\theta_*)U_{0,\rm cone}+U_{0,\rm tail}\) bounds \(U_0-U_Y\), and the screen is admitted when \([d(E_{\rm in})+d(E_{\rm out})]/U_Y(E_{\rm in})\) plus the numerical error is at most \(\epsilon_m\).
- Attributes:
- model_errorfloat
The required budget \(\epsilon_m\), in (0, 1).
- cone_cosinefloat
\(\cos\theta_* = 1 - \epsilon_m/8\).
- defect_in, defect_outfloat
\(d(E)\) of the input and output fields, J (reference measure).
- reference_energyfloat
\(U_Y(E_{\rm in})\), J.
- numerical_errorfloat
Relative numerical and domain error added to the ratio: the transform round trip’s energy discrepancy bound \(2\delta+\delta^2\) plus the field’s share at the window’s edge on input and output.
- ratiofloat
The admitted quantity, at most model_error; zero for a zero input.
- exact_zerobool
True when the input is exactly zero, the exact separate case.
- scopestr
Always
"single field": the certificate applies only to this field, not to a reusable map over a subspace.
- class solprop.coupling.elements.SpatialState(grid, space, spectrum, medium, frame=<factory>)[source]#
Bases:
objectA spatial field at one plane, with its grids, medium and local frame.
The plain input of every element;
solprop.coupling.transport()builds it from aFieldPlane(the internal conjugate of the plane’s samples, with the plane’s axes as the frame’s rows). The single component of a scalar state (n_pol = 1) is polarised along the frame’s x axis; two components are the optics-convention(x, y)Jones components stored conjugated, assolprop.pulses.SpatialPulse.build()stores them.- Attributes:
- gridsolprop.grid.TimeGrid
Temporal grid of the spectrum.
- spacesolprop.grid.RadialGrid or solprop.grid.FreeGrid
Transverse representation. A
solprop.grid.LineGrid(per unit width) and a planar grid (slab amplitudes) are refused.- spectrumnumpy.ndarray
Internal-convention Hankel/temporal spectrum in V m or Cartesian DFT/temporal spectrum in V/m, complex128, shape
(n_modes, n_pol, n_omega); exactly zero outside the active band and at nonpositive frequency. Stored as a read-only copy.- mediumsolprop.spatial.SpatialMedium
Homogeneous medium at the plane: every parameter path is constant.
- framenumpy.ndarray
Right-handed orthonormal local frame in laboratory coordinates, shape
(3, 3): the rows are the transverse x and y axes and the forward propagation direction. Default: the identity. Stored as a read-only copy.
- Raises:
- CouplingError
If the representation, the spectrum’s shape, finiteness or band, or the frame is invalid, or the medium varies along z.
- frame: Float[ndarray, '3 3']#
- medium: SpatialMedium#
- property n_pol: int[source]#
Return the number of stored polarisation components.
- Returns:
- int
One for a scalar state, two for
(x, y).
- space: RadialGrid | FreeGrid#
- spectrum: Complex[ndarray, 'n_modes n_pol n_omega']#
- with_spectrum(spectrum, *, space=None, medium=None, frame=None)[source]#
Return a state with a new spectrum and, optionally, new plane data.
- Parameters:
- spectrumnumpy.ndarray
New internal spectrum, shape
(n_columns, n_components, n_omega).- spacesolprop.grid.RadialGrid, solprop.grid.FreeGrid or None, optional
New transverse representation; None keeps this one.
- mediumsolprop.spatial.SpatialMedium or None, optional
New medium; None keeps this one.
- framenumpy.ndarray or None, optional
New local frame, shape
(3, 3); None keeps this one.
- Returns:
- SpatialState
The validated new state.
- class solprop.coupling.elements.SpectralCalibration(removes_phase, removes_delay, reference_wavelength, note='')[source]#
Bases:
objectWhich affine spectral phase a frequency-only element removes or keeps.
A plane’s reference record (SEP 31 §4.5) accumulates the carrier phase and the delay of its path; an element that removes them from its own response leaves them unknown to that record unless the removal is recorded.
- Attributes:
- removes_phasebool or None
True if the element drops its constant phase at the reference frequency, False if it keeps it, None if unknown.
- removes_delaybool or None
True if the element drops its group delay at the reference frequency, False if it keeps it, None if unknown.
- reference_wavelengthfloat or None
Vacuum wavelength in m at which the removal is referenced, or None.
- notestr
How the record was obtained.
Examples
>>> from solprop.coupling.elements import SpectralCalibration >>> SpectralCalibration(True, True, 800e-9, "measured compressor").removes_delay True
- class solprop.coupling.elements.SpectralTransfer(transfer, efficiency=None, calibration=None, predict_loss=False, reconstruction=False)[source]#
Bases:
objectA frequency-only transfer function acting coherently on every sample.
Adapts any
solprop.optics.TransferFunction–Material,ChirpedMirror,GratingPair,PrismPair,TaylorPhase– ansolprop.optics.Chainas one block whose factors commute among themselves only, or a compressor’s response described by its callable and metadata. The response crosses to the stored spectrum throughsolprop.optics.stored_factor(). Losses are kept per frequency.- Attributes:
- transfersolprop.optics.TransferFunction
The optics-convention response
H(omega).- efficiencyfloat, callable or None
Power efficiency per frequency in [0, 1], applied as
sqrt(efficiency)on top of a phase-only model. None applies none.- calibrationSpectralCalibration, tuple of SpectralCalibration or None
The affine phase the element removes. None derives it from a known type and is refused for any other callable.
- predict_lossbool
Ask for a lossy prediction: refused for a phase-only model without an explicit efficiency. Default False.
- reconstructionbool
Declare a reconstruction (inverse) operation; negative material lengths and inverse mirror phases are detected and flagged regardless. Default False.
- apply(state)[source]#
Apply the transfer function.
- Parameters:
- stateSpatialState
The input plane.
- Returns:
- ElementResult
The output plane and its report, with the calibration records.
- Raises:
- CouplingError
If a lossy prediction lacks its efficiency, an efficiency is given to a lossy model, an efficiency is outside [0, 1], or the calibration is missing.
- calibration: SpectralCalibration | tuple[SpectralCalibration, ...] | None = None#
- transfer: TransferFunction#
- class solprop.coupling.elements.ThinLens(focal_length, model_error)[source]#
Bases:
objectA thin paraxial lens, the phase screen \(e^{-ik(\omega)r^2/(2f(\omega))}\).
\(k=\operatorname{Re}n\,\omega/c\) is the wave number of the plane’s medium and \(r\) the distance from the plane’s axis. The screen is certified per field against model_error (
ScreenCertificate).- Attributes:
- focal_lengthfloat or callable
Focal length in m, finite and nonzero (negative diverges), or a function of positive angular frequency in rad/s returning it per band bin.
- model_errorfloat
Required thin-screen budget in (0, 1).
Examples
>>> from solprop.coupling.elements import ThinLens >>> ThinLens(0.5, model_error=1e-3).focal_length 0.5
- class solprop.coupling.elements.TransmissionMask(transmission, model_error, phase_only=False)[source]#
Bases:
objectA complex field transmission, as a function or as samples at the nodes.
- Attributes:
- transmissioncallable or array_like
T(x, y, omega)in the optics convention (positions in m, shape(n_nodes,); band angular frequencies in rad/s, shape(n_band,); a result broadcasting to(n_nodes, n_band)), or samples at the state’s nodes, shape(n_nodes,)or(n_nodes, n_band). A function on a radial grid must not depend on the azimuth.|T| <= 1everywhere.- model_errorfloat
Required thin-screen budget in (0, 1).
- phase_onlybool
Declare
|T| = 1: the local loss is then exactly zero. Default False.
- apply(state)[source]#
Apply the mask.
- Parameters:
- stateSpatialState
The input plane.
- Returns:
- ElementResult
The output plane and its certified report.
- Raises:
- CouplingError
If sampled values have the wrong shape, a declared phase-only mask changes the modulus, or a function depends on the azimuth on a radial grid.