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,

\[U_{\rm out} = U_{\rm in} - L_{\rm specified} - U_{\rm removed} + \epsilon_{\rm approximation},\]

so the approximation error is the signed part of the energy change that neither a declared loss nor an intentional removal explains.

Classes

Alignment([displacement, tilt, model_error])

A lateral displacement and a paraxial tilt of a Cartesian field.

Aperture(radius, model_error[, edge, kind, ...])

An aperture built on the SEP 23 edge profile, with its weighting declared.

Element(*args, **kwargs)

A linear element between two planes.

ElementReport(element, position, energy_in, ...)

The accounting of one element's application (SEP 31 §4.7).

ElementResult(state, report)

The state after an element and the report of its application.

FreeSpace(distance, medium[, output, ...])

Homogeneous propagation over a distance, \(e^{+ik_zL}\) per frequency.

Mirror(reflectivity_p, reflectivity_s, ...)

A flat mirror: spectral p/s reflection and the incoming/outgoing frame map.

PlanarInterface(first, second)

A plane boundary between two lossless media, at normal incidence.

PolarisationTransform(jones)

A spatially uniform Jones matrix in the plane's local (x, y) axes.

ScreenCertificate(model_error, cone_cosine, ...)

The single-field thin-screen admission record of SEP 31 §4.6.

SpatialState(grid, space, spectrum, medium)

A spatial field at one plane, with its grids, medium and local frame.

SpectralCalibration(removes_phase, ...[, note])

Which affine spectral phase a frequency-only element removes or keeps.

SpectralTransfer(transfer[, efficiency, ...])

A frequency-only transfer function acting coherently on every sample.

ThinLens(focal_length, model_error)

A thin paraxial lens, the phase screen \(e^{-ik(\omega)r^2/(2f(\omega))}\).

TransmissionMask(transmission, model_error)

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: object

A 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 tilt T = exp(+i k (x sin(theta_x) + y sin(theta_y))), k the 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.

apply(state)[source]#

Apply the tilt, then the displacement.

Parameters:
stateSpatialState

The input plane.

Returns:
ElementResult

The output plane and its report.

Raises:
CouplingError

If a nonzero alignment is asked of a radial grid, or a tilt has no budget or exceeds it.

displacement: tuple[float, float] = (0.0, 0.0)#
model_error: float | None = None#
tilt: tuple[float, float] = (0.0, 0.0)#
class solprop.coupling.elements.Aperture(radius, model_error, edge=0.0, kind='hard', centre=(0.0, 0.0), weighting='amplitude')[source]#

Bases: object

An aperture built on the SEP 23 edge profile, with its weighting declared.

solprop.spatial.aperture_profile() gives the edge profile W. Its meaning is fixed by weighting, exactly as for the in-run aperture statistics of solprop.stats.ApertureSet: 'amplitude' (the default) takes W as the field transmission, so the power goes as W**2; 'quadrature' takes W as a power weight, applied to the field as sqrt(W). SEP 31 §4.6’s intensity-defined aperture is the 'quadrature' case. A hard aperture (W zero 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 tanh and rcos, order for supergauss, unused for hard. 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' applies W to the field, 'quadrature' applies sqrt(W). Default 'amplitude'.

Examples

>>> from solprop.coupling import Aperture
>>> Aperture(1e-3, model_error=1e-2, weighting="quadrature").weighting
'quadrature'
apply(state)[source]#

Apply the aperture.

Parameters:
stateSpatialState

The input plane.

Returns:
ElementResult

The output plane and its certified report.

Raises:
CouplingError

If the weighting is unknown or an off-axis aperture is asked of a radial grid.

centre: tuple[float, float] = (0.0, 0.0)#
edge: float = 0.0#
kind: Literal['hard', 'tanh', 'rcos', 'supergauss'] = 'hard'#
model_error: float#
radius: float#
weighting: Literal['amplitude', 'quadrature'] = 'amplitude'#
class solprop.coupling.elements.Element(*args, **kwargs)[source]#

Bases: Protocol

A linear element between two planes.

apply(state)[source]#

Apply the element to a field plane.

Parameters:
stateSpatialState

The field at the element’s input plane.

Returns:
ElementResult

The output plane and the report.

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: object

The 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_error exactly.

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.

approximation_error: float#
calibration: tuple[SpectralCalibration, ...] = ()#
certificate: ScreenCertificate | None = None#
diagnostics: Mapping[str, float]#
element: str#
energy_in: float#
energy_out: float#
notes: tuple[str, ...] = ()#
numerical_error: float#
position: int#
reconstruction: bool = False#
removed: float#
specified_loss: float#
spectrum_in: Float[ndarray, 'n_omega_in']#
spectrum_out: Float[ndarray, 'n_omega_out']#
class solprop.coupling.elements.ElementResult(state, report)[source]#

Bases: object

The 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: object

Homogeneous 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_removed and phase_removed and solprop.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_tolerance is refused, unless beyond_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) exceeds edge_tolerance is 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 removed with window_removed in 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_removed in s and phase_removed in 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.

band_limit: float | None = None#
beyond_window: Literal['refuse', 'remove'] = 'refuse'#
distance: float#
edge_tolerance: float = 0.0001#
evanescent_tolerance: float | None = None#
frame_delay: float | None = None#
frame_phase: float = 0.0#
medium: SpatialMedium#
output: RadialGrid | FreeGrid | None = None#
output_method: Literal['angular', 'fresnel'] = 'angular'#
sampling_tolerance: float = 1e-06#
class solprop.coupling.elements.Mirror(reflectivity_p, reflectivity_s, incident, outgoing, s_axis)[source]#

Bases: object

A 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.

incident: Sequence[float] | ndarray#
outgoing: Sequence[float] | ndarray#
reflectivity_p: complex | Callable[[Float[ndarray, 'n_band']], ArrayLike]#
reflectivity_s: complex | Callable[[Float[ndarray, 'n_band']], ArrayLike]#
s_axis: Sequence[float] | ndarray#
class solprop.coupling.elements.PlanarInterface(first, second)[source]#

Bases: object

A 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: object

A 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)
apply(state)[source]#

Apply the Jones matrix.

Parameters:
stateSpatialState

The input plane.

Returns:
ElementResult

The output plane and its report.

Raises:
CouplingError

If the matrices have the wrong shape or amplify.

jones: ArrayLike | Callable[[Float[ndarray, 'n_band']], ArrayLike]#
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: object

The 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.

cone_cosine: float#
defect_in: float#
defect_out: float#
exact_zero: bool#
model_error: float#
numerical_error: float#
ratio: float#
reference_energy: float#
scope: str = 'single field'#
class solprop.coupling.elements.SpatialState(grid, space, spectrum, medium, frame=<factory>)[source]#

Bases: object

A spatial field at one plane, with its grids, medium and local frame.

The plain input of every element; solprop.coupling.transport() builds it from a FieldPlane (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, as solprop.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']#
grid: TimeGrid#
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: object

Which 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
note: str = ''#
reference_wavelength: float | None#
removes_delay: bool | None#
removes_phase: bool | None#
class solprop.coupling.elements.SpectralTransfer(transfer, efficiency=None, calibration=None, predict_loss=False, reconstruction=False)[source]#

Bases: object

A frequency-only transfer function acting coherently on every sample.

Adapts any solprop.optics.TransferFunction – Material, ChirpedMirror, GratingPair, PrismPair, TaylorPhase – an solprop.optics.Chain as 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 through solprop.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#
efficiency: float | Callable[[Float[ndarray, 'n_band']], ArrayLike] | None = None#
predict_loss: bool = False#
reconstruction: bool = False#
transfer: TransferFunction#
class solprop.coupling.elements.ThinLens(focal_length, model_error)[source]#

Bases: object

A 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
apply(state)[source]#

Apply the lens screen.

Parameters:
stateSpatialState

The input plane.

Returns:
ElementResult

The output plane and its certified report.

Raises:
CouplingError

If a focal length is zero or not finite.

focal_length: float | Callable[[Float[ndarray, 'n_band']], ArrayLike]#
model_error: float#
class solprop.coupling.elements.TransmissionMask(transmission, model_error, phase_only=False)[source]#

Bases: object

A 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| <= 1 everywhere.

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.

model_error: float#
phase_only: bool = False#
transmission: Callable[[Float[ndarray, 'n_nodes'], Float[ndarray, 'n_nodes'], Float[ndarray, 'n_band']], ArrayLike] | ArrayLike#