thunder4d.pulse

Pulse initialisation. A pulse is built as

\[A(x, y, \Omega) = E(\Omega)\; U(x, y; \Omega),\]

where \(E(\Omega)\) is a 1D complex spectral amplitude and \(U\) a spatial field evaluated separately at every frequency (so it can be chromatic) and normalised to unit power at each frequency. The spatially integrated spectrum is therefore exactly \(|E(\Omega)|^2\).

Spectral amplitude

All functions return a complex 1D array on grid.Omega (FFT order).

thunder4d.pulse.gaussian_spectrum(grid, fwhm_fs=None, fwhm_nm=None, center_nm=None)[source]

Transform-limited Gaussian. Give either the intensity FWHM duration [fs] or the spectral FWHM [nm]. center_nm defaults to \(\lambda_0\).

thunder4d.pulse.measured_spectrum(grid, wavelength_nm, intensity, phase_rad=None, background=0.0)[source]

Spectrum measured against wavelength. Applies the Jacobian \(S_\omega = S_\lambda\,\lambda^2/2\pi c\), subtracts background, clips negative values and interpolates onto the grid. An optional spectral phase (e.g. from a d-scan or FROG retrieval) can be given on the same wavelength axis; it is unwrapped before interpolation.

thunder4d.pulse.spectrum_from_temporal_field(grid, t_fs, field)[source]

Complex temporal envelope (e.g. a retrieved pulse \(|E|e^{i\varphi}\)), relative to grid.lambda0, interpolated on the time grid and transformed.

thunder4d.pulse.add_spectral_phase(grid, E, gdd_fs2=0.0, tod_fs3=0.0, fod_fs4=0.0, delay_fs=0.0, phase=None)[source]

Returns \(E\,e^{i\varphi}\) with \(\varphi = \frac{\text{GDD}}{2}\Omega^2 + \frac{\text{TOD}}{6}\Omega^3 + \frac{\text{FOD}}{24}\Omega^4 + \text{delay}\cdot\Omega\) (\(\Omega\) in rad/fs). phase adds an arbitrary term: a callable of \(\Omega\) [rad/s] or an array on grid.Omega.

Spatial profiles

class thunder4d.pulse.Profile(func, radius, name)[source]

Callable f(X, Y) returning a complex amplitude. radius is used as the default Zernike pupil.

thunder4d.pulse.gaussian(w)[source]

\(\exp(-r^2/w^2)\) (1/e² intensity radius \(w\)).

thunder4d.pulse.super_gaussian(w, order=10)[source]

\(\exp[-(r/w)^\text{order}]\); order 2 is a Gaussian.

thunder4d.pulse.top_hat(radius, order=24)[source]

Super-Gaussian with soft edges. Higher orders give harder edges and need a finer near-field sampling (e.g. order 100 with 384 points).

thunder4d.pulse.knife_edge(profile, edge, axis='x', side='+', width=None)[source]

Clip any profile with a hard edge at edge [m] along axis.

Parameters:
  • side (str) – "+" blocks \(x > \text{edge}\), "-" blocks \(x < \text{edge}\), "both" keeps \(|x| < |\text{edge}|\) (slit)

  • width (float) – 10–90 % width of a tanh edge [m]; None gives a step

thunder4d.pulse.measured_profile(image, pixel_size, center='centroid', background=0.0)[source]

Camera image (rows = y, columns = x) → amplitude \(\sqrt{I}\), bilinear interpolation, zero outside the image. center is "centroid" or (cx, cy) [m].

Aberrations

thunder4d.pulse.zernike_wavefront(X, Y, coeffs_waves, pupil_radius, lambda0)[source]

Wavefront error \(W\) [m] from RMS-normalised Zernike terms with coefficients in waves at \(\lambda_0\). In Beam it is applied as the phase \((\omega/c)\,W\), an achromatic path error correct for every colour.

Available terms: piston, tilt_x, tilt_y, defocus, astig_0, astig_45, coma_x, coma_y, trefoil_0, trefoil_30, spherical.

Beam

class thunder4d.pulse.Beam(profile, zernike=None, pupil_radius=None, spatial_chirp_mm_per_nm=(0, 0), angular_dispersion_urad_per_nm=(0, 0), pft_fs_per_mm=(0, 0), pfc_fs_per_mm2=0.0, radial_gdd_fs2_per_mm2=0.0, tilt_urad=(0, 0), offset_m=(0, 0), custom_phase=None)[source]

Spatial part of the pulse: profile + aberrations + space-time couplings. With \(\Delta\lambda = \lambda - \lambda_0\) and \(\Omega\) in rad/fs:

profile

spatial amplitude (Profile)

zernike

dict, e.g. {"astig_0": 0.1, "coma_x": 0.05} (RMS waves at \(\lambda_0\))

pupil_radius

Zernike normalisation radius [m] (default profile.radius)

spatial_chirp_mm_per_nm

(sx, sy): each colour shifted by \(s\,\Delta\lambda\)

angular_dispersion_urad_per_nm

(ax, ay): propagation angle \(a\,\Delta\lambda\)

pft_fs_per_mm

(px, py): pulse-front tilt, delay \(p\,x\)

pfc_fs_per_mm2

pulse-front curvature, delay \(a\,r^2\)

radial_gdd_fs2_per_mm2

GDD varying as \(r^2\) (radial chirp)

tilt_urad

pointing, same for all colours

offset_m

transverse position

custom_phase

callable (X, Y, Omega) -> phase [rad]

field(X, Y, omega, omega0)[source]

Unnormalised complex field at one angular frequency.

Pulse

class thunder4d.pulse.Pulse(grid, Aw)[source]

Field \(A(x, y, \Omega)\) of shape grid.shape.

Builders

classmethod at_focus(grid, E, beam, energy)[source]

Beam defined directly at the cell centre.

classmethod from_near_field(grid, E, beam, energy, nf_size, nf_points=256, focal_length=None, target_waist=None, verbose=True)[source]

Beam defined in the collimated near field, in the front focal plane of an achromatic lens; the cell centre is the focal plane. Exact per-colour Fraunhofer transform (spot size \(\propto\lambda\)): a top-hat gives an Airy pattern.

Parameters:
  • nf_size (float) – full width of the near-field window [m]

  • nf_points (int) – near-field sampling

  • focal_length (float) – lens focal length [m]. If None, it is chosen by golden-section search to maximise the overlap at \(\lambda_0\) with a Gaussian of waist target_waist and stored in pulse.focal_length.

A UserWarning is emitted if less than 99 % of the focused power fits in the box, even with verbose=False.

classmethod imaged_near_field(grid, E, beam, energy, cell, image_z=None, curvature_radius=None, verbose=True)[source]

Near field relay-imaged (same size for every colour) onto the plane at distance image_z from the centre, on the input side (default: the mirror, \(d/2\)), with a spherical wavefront of radius curvature_radius (default \(R(z) = z + z_R^2/z\) of the linear mode, equal to the mirror ROC at the mirror plane). The field is then propagated back (linear, exact) to the cell centre.

Tip

For a top-hat, a radius of 1.12 × w_mirror maximises the overlap with the Gaussian mode (\(\eta = 0.815\)).

Note

This builder works on a standard (fixed) grid. On a lens-frame grid use imaged_near_field_lens(), which takes the same profile.

All builders normalise each colour to unit power before multiplying by \(E(\Omega)\), then scale the total to energy [J].

Methods and properties

set_energy(energy)[source]

Rescale to energy [J]; returns self.

property energy

Energy [J].

At()[source]

Field in \((x, y, t)\).

power()[source]

Spatially integrated power \(P(t)\) [W] (FFT order).

peak_power()[source]

\(\max P(t)\) [W].

weighted_power()[source]

\(\int P^2 dt / \int P\,dt\) (= \(P_\text{peak}/\sqrt 2\) for a Gaussian).

add_spectral_phase(**kw)[source]

Same arguments as add_spectral_phase(), applied to every pixel.

copy()[source]

Independent copy.