solprop.optics#

Linear optical elements applied to a pulse outside a propagation.

Every element is a transfer function: a callable H(omega) giving the complex amplitude response in the optics convention of docs/dev/conventions.md section 2, so that a spectrum is multiplied by

\[H(\omega) = |H|\,e^{+i\varphi(\omega)},\]

the group delay is \(+d\varphi/d\omega\), and a positive second derivative chirps a pulse positively, as in any textbook. A spectrum in the FFT convention needs exp(-i phi) instead; that crossing is made once, in stored_factor(), through solprop.fourier.to_internal(). A transfer function is diagonal in frequency, so it commutes with the half-window origin shift of a stored spectrum and the conjugation is all the crossing needs.

The elements are TaylorPhase (a polynomial spectral phase: GDD, TOD, …), Material (a thickness of glass, or a path through a gas), ChirpedMirror (reflections from a dispersive mirror known by its measured group-delay dispersion), GratingPair, PrismPair and Chain. docs/guide/workflows/compression.md describes each and how the compressors in solprop.processing.compression use them.

Module Attributes

Medium

What a Material is made of: a glass model or name, a gas, or a mixture.

Functions

brewster_angle(medium, wavelength)

Return the external Brewster incidence angle in air.

brewster_apex(medium, wavelength)

Return the apex angle for Brewster entry and minimum deviation.

chirped_mirrors()

Return the names of the shipped chirped-mirror data sets.

littrow_angle(line_density, wavelength[, order])

Return the signed Littrow incidence angle of a reflection grating.

stored_factor(grid, transfer)

Return the factor that applies a transfer function to a stored spectrum.

taylor_phase(omega, coefficients, omega_ref)

Return a Taylor spectral phase, in the optics convention.

Classes

Chain(elements)

Several elements in series.

ChirpedMirror(omega, phase, ...[, ...])

Reflections from a dispersive mirror known by its measured dispersion.

GratingPair(line_density, separation, ...[, ...])

Apply the dispersion of parallel reflection gratings in air.

Material(medium, thickness[, wavelength, ...])

A thickness of glass, or a path through a gas.

PrismGeometry(separation, insertion, ...)

Specify fixed first-prism geometry and two second-prism stage coordinates.

PrismPair(medium, geometry, wavelength[, ...])

Apply the exact central-ray dispersion of two identical prisms in air.

PrismPaths(first_glass, air_gap, ...)

Report central-ray paths for one traversal through two ideal wedges.

TaylorPhase(coefficients, wavelength)

A polynomial spectral phase about a reference wavelength.

TransferFunction(*args, **kwargs)

A linear optical element, as its complex amplitude response.

class solprop.optics.Chain(elements)[source]#

Bases: Displayed

Several elements in series.

Attributes:
elementssequence of TransferFunction

The elements; their order does not matter, since each is diagonal in frequency.

Examples

>>> import numpy as np
>>> from solprop.optics import Chain, TaylorPhase
>>> pair = Chain((TaylorPhase((0, 0, 40e-30), 800e-9),
...               TaylorPhase((0, 0, -40e-30), 800e-9)))
>>> bool(np.allclose(pair(np.linspace(2e15, 3e15, 7)), 1.0))
True
elements: Sequence[TransferFunction]#
class solprop.optics.ChirpedMirror(omega, phase, reflectivity_omega, amplitude, band, reflections=1, name='')[source]#

Bases: Displayed

Reflections from a dispersive mirror known by its measured dispersion.

One reflection multiplies the spectrum by \(\sqrt{R(\omega)}\,e^{+i\varphi(\omega)}\,W(\omega)\), where \(\varphi\) is the double integral of the group-delay dispersion over angular frequency with its constant and linear parts removed (an arbitrary phase and an overall delay), and \(W\) is a Planck taper to zero outside the band the data are trusted on. Build one with from_data() or lookup(); choose the number of bounces with bounces().

Attributes:
omeganumpy.ndarray

Angular frequencies of the phase samples in rad/s, ascending.

phasenumpy.ndarray

Phase per reflection in rad on omega.

reflectivity_omeganumpy.ndarray

Angular frequencies of the reflectivity samples, ascending; empty for a phase-only mirror.

amplitudenumpy.ndarray

Amplitude reflectivity sqrt(R) on reflectivity_omega.

bandtuple of float

The taper’s four wavelengths in m: zero, one, one, zero.

reflectionsint

Number of reflections. Negative is the phase-only inverse of that many: the amplitude is left alone inside the band and, like the forward mirror, zero outside it.

namestr

A label for printing.

Examples

>>> from solprop.optics import ChirpedMirror
>>> ChirpedMirror.lookup("PC70").bounces(4).reflections
4
amplitude: Float[ndarray, 'n_reflectivity']#
band: tuple[float, float, float, float]#
bounces(reflections)[source]#

Return the same mirror with another number of reflections.

Parameters:
reflectionsint

Number of reflections; negative for the phase-only inverse.

Returns:
ChirpedMirror

A copy sharing the data.

classmethod from_data(wavelength, reflectivity, *, gdd=None, group_delay=None, reference_wavelength, band, taper_width=2e-08, fit_order=5, fit_window=None, name='')[source]#

Build a mirror from a data sheet’s columns.

Parameters:
wavelengthnumpy.ndarray

Wavelengths of the samples in m, strictly monotonic.

reflectivitynumpy.ndarray or None

Power reflectivity per reflection in [0, 1] on wavelength, or None for a phase-only mirror.

gddnumpy.ndarray or None, optional

Group-delay dispersion per reflection in s^2. Exactly one of this and group_delay.

group_delaynumpy.ndarray or None, optional

Group delay per reflection in s.

reference_wavelengthfloat

Wavelength about which the constant and linear phase are removed, m.

bandtuple of float

Shortest and longest wavelength in m the mirror is used over.

taper_widthfloat, optional

Width in m of the taper to zero outside band.

fit_orderint, optional

Order of the polynomial fitted to the integrated phase, of which only the constant and linear terms are subtracted.

fit_windowtuple of float or None, optional

Angular-frequency window of that fit in rad/s; None is all the data.

namestr, optional

A label.

Returns:
ChirpedMirror

One reflection; see bounces().

Raises:
MaterialError

If both or neither dispersion column is given, a reflectivity lies outside [0, 1], or the wavelength axis is not monotonic.

Examples

>>> import numpy as np
>>> from solprop.optics import ChirpedMirror
>>> wavelength = np.linspace(600e-9, 1000e-9, 401)
>>> mirror = ChirpedMirror.from_data(
...     wavelength, None, gdd=np.full(401, -50e-30),
...     reference_wavelength=800e-9, band=(650e-9, 950e-9))
>>> f"{mirror.gdd(np.array([2.355e15]))[0] * 1e30:.1f}"
'-50.0'
gdd(omega)[source]#

Return the group-delay dispersion of one reflection.

Parameters:
omeganumpy.ndarray

Angular frequencies in rad/s inside the data.

Returns:
numpy.ndarray

The second derivative of the stored phase in s^2; NaN outside the data.

group_delay(omega)[source]#

Return the group delay of one reflection, less the removed constant.

Parameters:
omeganumpy.ndarray

Angular frequencies in rad/s inside the data.

Returns:
numpy.ndarray

The first derivative of the stored phase in s; NaN outside the data.

classmethod lookup(name)[source]#

Return one reflection from a shipped data set.

Parameters:
namestr

One of chirped_mirrors().

Returns:
ChirpedMirror

The mirror, reduced from its data file with the recorded reference wavelength, fit order and window, and band.

Raises:
MaterialError

If the name is unknown.

Examples

>>> from solprop.optics import ChirpedMirror
>>> ChirpedMirror.lookup("HD120").name
'HD120'
name: str = ''#
omega: Float[ndarray, 'n_phase']#
phase: Float[ndarray, 'n_phase']#
reflections: int = 1#
reflectivity_omega: Float[ndarray, 'n_reflectivity']#
class solprop.optics.GratingPair(line_density, separation, incidence_angle, wavelength, order=-1, double_pass=True, band=None)[source]#

Bases: Displayed

Apply the dispersion of parallel reflection gratings in air.

Include the groove phase and remove phase and group delay at wavelength. The model describes sampled diffraction orders, with no efficiency, aperture, polarisation or spatial propagation. See the compression manual for Treacy’s construction and the meaning of a compensating return pass.

Attributes:
line_densityfloat

Grooves per metre, finite and positive.

separationfloat

Normal distance between the grating surfaces in m, finite and nonnegative.

incidence_anglefloat

Signed incidence in rad, strictly between -pi/2 and pi/2.

wavelengthfloat

Explicit vacuum reference wavelength in m, finite and positive.

orderint

Nonzero signed diffraction order, -1 by default.

double_passbool

Two traversals (four diffractions) if true; one traversal otherwise.

bandtuple of float or None

Fixed ascending vacuum wavelength band in m containing wavelength. The transfer is zero outside it. Endpoints and evaluated bins are checked; no continuous validity certificate is implied.

Raises:
MaterialError

If the parameters or fixed band are invalid.

OpticsGeometryError

If an evaluated order is not real or is grazing.

band: tuple[float, float] | None = None#
double_pass: bool = True#
incidence_angle: float#
line_density: float#
order: int = -1#
phase(omega)[source]#

Return phase after removing reference phase and group delay.

Parameters:
omegaarray_like

Positive in-band angular frequencies in rad/s, shape (n_omega,).

Returns:
numpy.ndarray

Optics-convention residual phase in rad, shape (n_omega,).

Raises:
MaterialError

If frequencies are invalid or the phase exceeds floating-point range.

OpticsGeometryError

If any requested diffraction order is unavailable or grazing.

separation: float#
wavelength: float#
class solprop.optics.Material(medium, thickness, wavelength=None, loss=False, pressure=None, temperature=293.15)[source]#

Bases: Displayed

A thickness of glass, or a path through a gas.

\(H = \exp\{+i[\beta(\omega) - \beta_1(\omega_0)(\omega-\omega_0)]L\}\) with \(\beta = \omega\,{\rm Re}\,n/c\). The group delay at the reference wavelength is removed so that the pulse stays in its window; the constant \(\beta_0\) is kept, so the carrier-envelope phase does move with thickness.

Attributes:
mediumGlassIndex, Gas, str or Mixture

A glass model, a glass name (solprop.physdata.glasses.glass(), optmat’s recommended model), a built-in gas (which needs pressure, and becomes its one-population Mixture under optmat’s models), or a mixture (which carries its own).

thicknessfloat

Path length in m. Negative removes material.

wavelengthfloat or None

Wavelength at which the group delay is removed, m; None keeps it, and the pulse leaves its window after a few millimetres of glass.

lossbool

Whether to apply the absorption exp(-omega Im(n) L / c). Off by default, which makes the element phase-only: right for a transparent window, wrong near an absorption edge.

pressurefloat or None

Gas pressure in bar; required for a built-in gas and refused otherwise.

temperaturefloat

Gas temperature in K; ignored for a glass and a mixture.

Examples

>>> import numpy as np
>>> from solprop.optics import Material
>>> window = Material("SiO2", 1e-3, 800e-9)
>>> response = window(2 * np.pi * 299792458.0 / np.array([700e-9, 900e-9]))
>>> bool(np.allclose(np.abs(response), 1.0))
True
loss: bool = False#
medium: GlassIndex | Gas | str | Mixture#
pressure: float | None = None#
temperature: float = 293.15#
thickness: float#
wavelength: float | None = None#
solprop.optics.Medium = solprop.physdata.glasses.GlassIndex | solprop.physdata.gases.Gas | str | solprop.physdata.mixtures.Mixture#

What a Material is made of: a glass model or name, a gas, or a mixture.

class solprop.optics.PrismGeometry(separation, insertion, first_face_distance, apex_angle, incidence_angle)[source]#

Bases: Displayed

Specify fixed first-prism geometry and two second-prism stage coordinates.

The first apex is (0, 0), with its base horizontal below it. The inverted second apex is R*u0 + (0, -H), where u0 is the reference inter-prism ray. Increasing insertion moves only the second prism down; increasing separation moves it along u0. Neither coordinate is the physical tip distance.

Attributes:
separationfloat

Stage coordinate R in m from formal zero insertion, finite and nonnegative.

insertionfloat

Second-prism displacement H perpendicular to its base in m, nonnegative.

first_face_distancefloat

Distance a along the first entry face from its apex in m, finite and positive.

apex_anglefloat

Common apex angle in rad, strictly between zero and pi.

incidence_anglefloat

Fixed external incidence in rad, strictly between zero and pi/2.

Raises:
MaterialError

If a length or angle is outside its domain. Ray feasibility is checked by PrismPair; zero insertion with positive a does not describe a ray.

apex_angle: float#
first_face_distance: float#
incidence_angle: float#
insertion: float#
separation: float#
class solprop.optics.PrismPair(medium, geometry, wavelength, double_pass=True, band=None)[source]#

Bases: Displayed

Apply the exact central-ray dispersion of two identical prisms in air.

Remove phase and analytic group delay at the explicit reference wavelength. Glass dispersion is already in the wavefront phase: do not add a separate slab. Use only the real index; loss, finite bases, apertures and beam clearance are outside this model. A single traversal retains spatial chirp. Doubling assumes a compensating return or four-prism arrangement, not an arbitrary return mirror.

Attributes:
mediumGlassIndex or str

Glass model or name in the existing glass registry; real index must exceed one.

geometryPrismGeometry

Fixed first prism, incidence and apex angle, and second-prism R and H in m.

wavelengthfloat

Explicit vacuum reference wavelength in m, finite and positive.

double_passbool

Double the pair phase if true, the default.

bandtuple of float or None

Fixed ascending vacuum wavelength band in m containing the reference. The response is zero outside it. Check endpoints and every evaluated bin; this does not prove validity between samples for an arbitrary index model.

Raises:
MaterialError

If a parameter, band or material model is invalid.

OpticsGeometryError

If a sampled reference, endpoint or requested ray is infeasible.

property apex_distance: float[source]#

Return the physical tip-to-tip distance in metres.

Returns:
float

norm(R*u0 + (0, -H)), which changes when either stage moves.

band: tuple[float, float] | None = None#
double_pass: bool = True#
geometry: PrismGeometry#
medium: GlassIndex | str#
phase(omega)[source]#

Return wavefront phase with reference phase and group delay removed.

Parameters:
omegaarray_like

Positive in-band angular frequencies in rad/s, shape (n_omega,).

Returns:
numpy.ndarray

Optics-convention residual phase in rad, shape (n_omega,).

Raises:
MaterialError

If frequencies or the material model are invalid, or the phase is not finite.

OpticsGeometryError

If any requested central ray is infeasible.

ray_paths(omega)[source]#

Trace positive central-ray paths through the two ideal wedges.

Parameters:
omegaarray_like

Positive in-band angular frequencies in rad/s, shape (n_omega,).

Returns:
PrismPaths

New path and face-distance arrays in m, shape (n_omega,).

Raises:
MaterialError

If frequencies or the real refractive index are invalid.

OpticsGeometryError

If any ray is backwards, grazing, misses a face or undergoes TIR.

wavelength: float#
class solprop.optics.PrismPaths(first_glass, air_gap, second_glass, first_exit_face_distance, second_entry_face_distance, second_exit_face_distance)[source]#

Bases: Displayed

Report central-ray paths for one traversal through two ideal wedges.

Attributes:
first_glassnumpy.ndarray

First glass path in m, shape (n_omega,).

air_gapnumpy.ndarray

Actual inter-prism ray length in m, shape (n_omega,).

second_glassnumpy.ndarray

Second glass path in m, shape (n_omega,).

first_exit_face_distancenumpy.ndarray

First exit distance along its face from the apex in m, shape (n_omega,).

second_entry_face_distancenumpy.ndarray

Second entry distance along its face from the apex in m, shape (n_omega,).

second_exit_face_distancenumpy.ndarray

Second exit distance along its face from the apex in m, shape (n_omega,).

air_gap: Float[ndarray, 'n_omega']#
first_exit_face_distance: Float[ndarray, 'n_omega']#
first_glass: Float[ndarray, 'n_omega']#
second_entry_face_distance: Float[ndarray, 'n_omega']#
second_exit_face_distance: Float[ndarray, 'n_omega']#
second_glass: Float[ndarray, 'n_omega']#
class solprop.optics.TaylorPhase(coefficients, wavelength)[source]#

Bases: Displayed

A polynomial spectral phase about a reference wavelength.

Attributes:
coefficientssequence of float

c_0, c_1, c_2, ... in s**n: carrier-envelope phase in rad, group delay in s, group-delay dispersion in s^2, third-order dispersion in s^3. Zero-based, the same indexing as the phases= keyword of the run interfaces. A positive c_2 chirps positively. c_1 multiplies the detuning, so it delays the envelope and leaves the phase at the reference frequency where it was; a delay of the whole field, absolute frequency times a time, is a pulse’s t0 and the delay of taylor_phase().

wavelengthfloat

Wavelength the expansion is about, m, > 0.

Examples

>>> import numpy as np
>>> from solprop.optics import TaylorPhase
>>> gdd = TaylorPhase((0.0, 0.0, 50e-30), 800e-9)
>>> bool(np.allclose(np.abs(gdd(np.linspace(2e15, 3e15, 5))), 1.0))
True
coefficients: Sequence[float]#
wavelength: float#
class solprop.optics.TransferFunction(*args, **kwargs)[source]#

Bases: Protocol

A linear optical element, as its complex amplitude response.

solprop.optics.brewster_angle(medium, wavelength)[source]#

Return the external Brewster incidence angle in air.

Parameters:
mediumGlassIndex or str

Glass model or existing glass registry name; its real index is used.

wavelengthfloat

Vacuum wavelength in m, finite and positive.

Returns:
float

Incidence angle in rad, atan(real(n)).

Raises:
MaterialError

If the wavelength or glass is invalid, or its real index is not above one.

solprop.optics.brewster_apex(medium, wavelength)[source]#

Return the apex angle for Brewster entry and minimum deviation.

Parameters:
mediumGlassIndex or str

Glass model or existing glass registry name; its real index is used.

wavelengthfloat

Vacuum wavelength in m, finite and positive.

Returns:
float

Apex angle in rad, pi - 2*brewster_angle(medium, wavelength).

Raises:
MaterialError

If the reference wavelength or glass index is invalid.

solprop.optics.chirped_mirrors()[source]#

Return the names of the shipped chirped-mirror data sets.

Returns:
tuple of str

Names ChirpedMirror.lookup() accepts. Where the data sets came from is not recorded (docs/guide/workflows/compression.md).

Examples

>>> from solprop.optics import chirped_mirrors
>>> "PC70" in chirped_mirrors()
True
solprop.optics.littrow_angle(line_density, wavelength, order=-1)[source]#

Return the signed Littrow incidence angle of a reflection grating.

Parameters:
line_densityfloat

Grooves per metre, finite and positive; 1200 lines/mm is 1.2e6.

wavelengthfloat

Vacuum wavelength in m, finite and positive.

orderint, optional

Nonzero signed order in sin(theta_m) = sin(theta_i) + m*wavelength/d.

Returns:
float

Incidence angle in rad, strictly between -pi/2 and pi/2.

Raises:
MaterialError

If density, wavelength or order is invalid.

OpticsGeometryError

If the Littrow order is unavailable or grazing.

solprop.optics.stored_factor(grid, transfer)[source]#

Return the factor that applies a transfer function to a stored spectrum.

The response is evaluated on the grid’s active band only and is one elsewhere: the bins outside it hold no field, and asking a material model for an index there would only raise range warnings about frequencies nothing depends on. For an element that blocks light, such as a mirror outside its band, this means the little that a spectral collar leaves outside the active band is passed rather than blocked.

Parameters:
gridsolprop.grid.TimeGrid

The grid the stored spectrum lives on.

transferTransferFunction

The element, in the optics convention.

Returns:
numpy.ndarray

The factor in the internal (FFT) convention, shape (n_omega,): conj(H) on the active band, by solprop.fourier.to_internal().

Examples

>>> import numpy as np
>>> from solprop.optics import TaylorPhase, stored_factor
>>> from solprop.processing._examples import example_grid
>>> grid = example_grid()
>>> factor = stored_factor(grid, TaylorPhase((0.0, 0.0, 100e-30), 800e-9))
>>> bool(np.allclose(np.abs(factor), 1.0))
True
solprop.optics.taylor_phase(omega, coefficients, omega_ref, delay=0.0)[source]#

Return a Taylor spectral phase, in the optics convention.

\[\varphi(\omega) = \omega t_0 + \sum_n c_n\,(\omega-\omega_{\rm ref})^n / n!\]

The one place the package writes this sum: the pulse builders and TaylorPhase both call it, so a chirp put on a pulse at construction is removed exactly by the opposite TaylorPhase.

Parameters:
omeganumpy.ndarray

Absolute angular frequencies in rad/s, shape (n_omega,).

coefficientsnumpy.ndarray

c_0, c_1, ... in s**n for order n: carrier-envelope phase, group delay, group-delay dispersion, third-order dispersion and so on.

omega_reffloat

Frequency the expansion is about, rad/s.

delayfloat, optional

A pure delay \(t_0\) in s multiplying the absolute frequency, so that the whole field moves and not only its envelope; positive is later.

Returns:
numpy.ndarray

The phase in rad, shape (n_omega,).

Examples

>>> import numpy as np
>>> from solprop.optics import taylor_phase
>>> taylor_phase(np.array([1.0, 3.0]), np.array([0.0, 0.0, 2.0]), 1.0).tolist()
[0.0, 4.0]