solprop.processing.time#

Pulse metrics: energy, peak power, durations, arrival time and autocorrelations.

The metrics follow two rules. Where solprop.stats already owns a definition – the energy, the peak power, the two temporal widths – this module calls it, so a metric read off a saved run and the same metric recorded during the run are the same number to the bit. Where it does not – a spectral width, an arrival time, an autocorrelation – the definition lives here, on the general half-maximum and moment helpers below.

Polarisation components are summed wherever the quantity is quadratic in the field, as they are in solprop.stats: they are two components of one field and their powers add at each instant. Modes are not summed unless asked: modes=None gives one number per mode, modes='sum' the number of the total.

What the stored basis admits is checked here too. energy() and peak_power() are the two metrics of this module whose meaning depends on the mode axis being an orthogonal basis whose coordinate powers add, so on a general modal file they are refused by name, with the same text the run loop and solprop.processing.modal use (solprop.output.capability). The widths, the spectral metrics and the autocorrelations are shape functionals of the same trace and are admitted on every basis.

Module Attributes

ArrivalMethod

Whether an arrival time is the first moment of the power or the time of its peak.

ARRIVAL_METHODS

The two definitions of an arrival time.

Functions

arrival_time(output, *[, plane, z, modes, ...])

Return when a pulse arrives, in seconds on the grid's own time axis.

coherence_time(output, *[, plane, z, modes, ...])

Return the coherence time of a plane, in seconds.

energy(output, *[, plane, z, modes, bandpass])

Return the pulse energy of a plane, or of every plane, in joules.

field_autocorrelation(output, *[, plane, z, ...])

Return the field autocorrelation of a plane, in joules.

fwhm(x, y, *[, outer])

Return the full width of a trace at half its maximum.

fwhm_f(output, *[, plane, z, modes, outer])

Return the spectral width at half maximum of a plane, in hertz.

fwhm_t(output, *[, plane, z, modes, ...])

Return the temporal width at half maximum of a plane, or of every plane.

half_max_range(x, y, *[, outer])

Return the two points at which a trace crosses half its maximum.

intensity_autocorrelation(output, *[, ...])

Return the intensity autocorrelation of a plane, in watts squared times seconds.

moment(x, y[, order])

Return a normalised moment of a trace, sum(x**order y) / sum(y).

peak_power(output, *[, plane, z, modes, ...])

Return the peak power of a plane, or of every plane, in watts.

time_bandwidth(output, *[, plane, z, modes, ...])

Return the time-bandwidth product of a plane, or of every plane.

solprop.processing.time.ARRIVAL_METHODS: tuple[Literal['moment', 'peak'], ...] = ('moment', 'peak')#

The two definitions of an arrival time.

solprop.processing.time.ArrivalMethod#

Whether an arrival time is the first moment of the power or the time of its peak.

alias of Literal[‘moment’, ‘peak’]

solprop.processing.time.arrival_time(output, *, plane=None, z=None, modes=None, bandpass=None, method='moment')[source]#

Return when a pulse arrives, in seconds on the grid’s own time axis.

'moment' is the first moment of the instantaneous power, which weighs the whole trace; 'peak' is the time of its maximum, which does not. A bandpass makes this the arrival time of one spectral region, which is how a walk-off is measured.

Parameters:
outputsolprop.output.schema.Output

An opened output handler.

planeint or None

Index of the plane wanted, negative from the end.

zfloat or None

Position of the plane wanted, m.

modesint, sequence of int, ‘sum’ or None

Which modes to report.

bandpasstuple of float, numpy.ndarray or None

Wavelength limits, m, of an explicit window applied before the measurement, or a ready-made window on the stored axis.

method{‘moment’, ‘peak’}

Which definition to use.

Returns:
numpy.ndarray

The arrival time, s, positive for a pulse later than the window centre.

Raises:
solprop.exceptions.GridError

If method is not one of ARRIVAL_METHODS.

Examples

>>> import numpy as np
>>> from solprop.processing._examples import example_output
>>> from solprop.processing.time import arrival_time
>>> bool(np.all(np.abs(arrival_time(example_output())) < 1e-16))
True
solprop.processing.time.coherence_time(output, *, plane=None, z=None, modes=None, bandpass=None)[source]#

Return the coherence time of a plane, in seconds.

The width at half maximum of the squared modulus of the field autocorrelation, which for a Gaussian spectrum of angular width d_omega is 2 sqrt(ln 2) / d_omega.

Parameters:
outputsolprop.output.schema.Output

An opened output handler.

planeint or None

Index of the plane wanted, negative from the end.

zfloat or None

Position of the plane wanted, m.

modesint, sequence of int, ‘sum’ or None

Which modes to report.

bandpasstuple of float, numpy.ndarray or None

Wavelength limits, m, of an explicit window applied before the transform, or a ready-made window on the stored axis.

Returns:
numpy.ndarray

The coherence time, s.

Examples

>>> from solprop.processing._examples import example_output
>>> from solprop.processing.time import coherence_time
>>> float(coherence_time(example_output(), plane=0)) > 0.0
True
solprop.processing.time.energy(output, *, plane=None, z=None, modes=None, bandpass=None)[source]#

Return the pulse energy of a plane, or of every plane, in joules.

solprop.stats.energy(), which is the exact discrete functional of conventions.md section 4, summed over polarisation.

A general modal file is refused by name, as it is at the run loop, in both CPU backends and in solprop.processing.modal: a coordinate energy is not additive on a three-component basis, and solprop.processing.modal.physical_energy() is that basis’s own energy (solprop.output.capability). Every older file, and every schema-7 run on an ordinary basis, is unaffected.

Parameters:
outputsolprop.output.schema.Output

An opened output handler.

planeint or None

Index of the plane wanted, negative from the end; with neither plane nor z, every plane is returned with a leading n_z axis.

zfloat or None

Position of the plane wanted, m.

modesint, sequence of int, ‘sum’ or None

Which modes to report; 'sum' adds their energies.

bandpasstuple of float, numpy.ndarray or None

Wavelength limits, m, of an explicit window applied before the measurement, or a ready-made window on the stored axis.

Returns:
numpy.ndarray

The energy, J, with the plane and mode axes the selection leaves.

Raises:
solprop.exceptions.OutputError

If the stored run is a general modal one, which does not define this name.

Examples

>>> import numpy as np
>>> from solprop.processing._examples import example_output
>>> from solprop.processing.time import energy
>>> values = energy(example_output())
>>> bool(np.allclose(values, values[0], rtol=1e-12))
True
solprop.processing.time.field_autocorrelation(output, *, plane=None, z=None, modes=None, bandpass=None)[source]#

Return the field autocorrelation of a plane, in joules.

A(tau) = integral E_a*(t) E_a(t + tau) dt by the Wiener-Khinchin theorem, so that its value at zero delay is the pulse energy and its width is the coherence time. It carries the sample spacing rather than being a bare sample sum, which is what gives it units and makes the zero-delay identity exact.

Parameters:
outputsolprop.output.schema.Output

An opened output handler.

planeint or None

Index of the plane wanted, negative from the end.

zfloat or None

Position of the plane wanted, m.

modesint, sequence of int, ‘sum’ or None

Which modes to report; 'sum' adds their autocorrelations.

bandpasstuple of float, numpy.ndarray or None

Wavelength limits, m, of an explicit window applied before the transform, or a ready-made window on the stored axis.

Returns:
delaynumpy.ndarray

Delay axis, shape (n_t,), s, centred on zero.

correlationnumpy.ndarray

The autocorrelation, J.

Examples

>>> import numpy as np
>>> from solprop.processing._examples import example_output
>>> from solprop.processing.time import energy, field_autocorrelation
>>> delay, correlation = field_autocorrelation(example_output(), plane=0)
>>> zero = correlation[delay.size // 2]
>>> bool(np.isclose(zero.real, energy(example_output(), plane=0), rtol=1e-12))
True
solprop.processing.time.fwhm(x, y, *, outer=False)[source]#

Return the full width of a trace at half its maximum.

The distance between the two crossings of half_max_range(): those nearest the peak, or with outer the first and last anywhere.

Parameters:
xnumpy.ndarray

Abscissa, shape (n,), increasing.

ynumpy.ndarray

The trace, shape (n,).

outerbool

Whether to span every satellite rather than the central feature alone.

Returns:
float

The width in the units of x, or nan where it is undefined.

Examples

>>> import numpy as np
>>> from solprop.processing.time import fwhm
>>> x = np.linspace(-4.0, 4.0, 801)
>>> bool(np.isclose(fwhm(x, np.exp(-(x**2))), 1.6651, atol=1e-4))
True
solprop.processing.time.fwhm_f(output, *, plane=None, z=None, modes=None, outer=False)[source]#

Return the spectral width at half maximum of a plane, in hertz.

The width of the spectral energy density on the frequency axis, which is the quantity a time-bandwidth product needs.

Parameters:
outputsolprop.output.schema.Output

An opened output handler.

planeint or None

Index of the plane wanted, negative from the end.

zfloat or None

Position of the plane wanted, m.

modesint, sequence of int, ‘sum’ or None

Which modes to report; 'sum' adds their densities first.

outerbool

Whether to span every satellite rather than the central feature alone.

Returns:
numpy.ndarray

The width, Hz.

Examples

>>> import numpy as np
>>> from solprop.processing._examples import example_output
>>> from solprop.processing.time import fwhm_f
>>> bool(np.all(fwhm_f(example_output()) > 0.0))
True
solprop.processing.time.fwhm_t(output, *, plane=None, z=None, modes=None, bandpass=None, outer=False)[source]#

Return the temporal width at half maximum of a plane, or of every plane.

solprop.stats.fwhm_t(), the width of the central feature of the total power, or solprop.stats.fwhm_t_outer() with outer=True, the total extent above half maximum. A trace that never falls to half its maximum has no width and gives nan.

The trace measured here is |b(t)|^2, the squared modulus of the analytic true-power envelope, because a saved plane carries no mode index. The run’s own stats/fwhm_t is the width of the analytic Poynting flux Re[a(t) conj(a_w(t))] (docs/guide/results/power-and-intensity.md). The two traces differ at second order in the variation of Re n_eff across the spectrum, of order 1e-7 of the peak for a gas-filled capillary (7.95e-8 on the reduced comb-to-continuum witness), so the widths differ far below the sampling.

Parameters:
outputsolprop.output.schema.Output

An opened output handler.

planeint or None

Index of the plane wanted, negative from the end.

zfloat or None

Position of the plane wanted, m.

modesint, sequence of int, ‘sum’ or None

Which modes to report; 'sum' measures the width of their total power.

bandpasstuple of float, numpy.ndarray or None

Wavelength limits, m, of an explicit window applied before the measurement, or a ready-made window on the stored axis.

outerbool

Whether to span every satellite rather than the central feature alone.

Returns:
numpy.ndarray

The width, s.

Examples

>>> import numpy as np
>>> from solprop.processing._examples import example_output
>>> from solprop.processing.time import fwhm_t
>>> widths = fwhm_t(example_output())
>>> bool(np.isclose(widths[-1] / widths[0], 2.0, rtol=1e-3))
True
solprop.processing.time.half_max_range(x, y, *, outer=False)[source]#

Return the two points at which a trace crosses half its maximum.

The level is half the global peak with no baseline subtraction, and the crossing is interpolated linearly between the two samples that bracket it, in the stable form x1 + (level - y1)(x2 - x1)/(y2 - y1). outer=False walks outwards from the peak and stops at the first sample below the level on either side, so structure further out does not widen the answer; outer=True takes the first and last sample above the level anywhere. These are the two conventions solprop.stats.fwhm_t() and solprop.stats.fwhm_t_outer() use for the temporal power, here for any trace, and the same code: both widths are measured by the one implementation this function exposes.

Parameters:
xnumpy.ndarray

Abscissa, shape (n,), increasing.

ynumpy.ndarray

The trace, shape (n,).

outerbool

Whether to take the outermost pair of crossings.

Returns:
tuple of float

The lower and upper crossings, both nan when the trace carries nothing, does not fall to half its maximum on both sides, or reaches the end of the axis still above it.

Examples

>>> import numpy as np
>>> from solprop.processing.time import half_max_range
>>> x = np.linspace(-4.0, 4.0, 801)
>>> low, high = half_max_range(x, np.exp(-(x**2)))
>>> bool(np.isclose(high - low, 2 * np.sqrt(np.log(2)), atol=1e-4))
True
solprop.processing.time.intensity_autocorrelation(output, *, plane=None, z=None, modes=None, bandpass=None)[source]#

Return the intensity autocorrelation of a plane, in watts squared times seconds.

integral P(t) P(t + tau) dt, the quantity an autocorrelator measures, formed by the same circular correlation as field_autocorrelation() on the instantaneous power.

Parameters:
outputsolprop.output.schema.Output

An opened output handler.

planeint or None

Index of the plane wanted, negative from the end.

zfloat or None

Position of the plane wanted, m.

modesint, sequence of int, ‘sum’ or None

Which modes to report.

bandpasstuple of float, numpy.ndarray or None

Wavelength limits, m, of an explicit window applied before the transform, or a ready-made window on the stored axis.

Returns:
delaynumpy.ndarray

Delay axis, shape (n_t,), s, centred on zero.

correlationnumpy.ndarray

The autocorrelation, W^2 s.

Examples

>>> import numpy as np
>>> from solprop.processing._examples import example_output
>>> from solprop.processing.time import intensity_autocorrelation
>>> delay, correlation = intensity_autocorrelation(example_output(), plane=0)
>>> bool(np.argmax(correlation) == delay.size // 2)
True
solprop.processing.time.moment(x, y, order=1)[source]#

Return a normalised moment of a trace, sum(x**order y) / sum(y).

The sample spacing cancels between numerator and denominator, so none is applied and the answer is exact on a uniform axis.

Parameters:
xnumpy.ndarray

Abscissa, shape (n,).

ynumpy.ndarray

Weight, shape (n,), non-negative for the result to be a centroid.

orderint

Which moment, one for the centroid.

Returns:
float

The moment, in the units of x raised to order.

Examples

>>> import numpy as np
>>> from solprop.processing.time import moment
>>> moment(np.array([0.0, 1.0, 2.0]), np.array([0.0, 1.0, 1.0]))
1.5
solprop.processing.time.peak_power(output, *, plane=None, z=None, modes=None, bandpass=None, oversampling=1)[source]#

Return the peak power of a plane, or of every plane, in watts.

solprop.stats.peak_power() per mode and solprop.stats.peak_power_total() for modes='sum', so that a modal sum is the peak of the total power and not the largest of the per-mode peaks: modes that peak at different times never carry their combined power at any one instant. Above unit oversampling the maximum is taken on the resampled trace instead, which finds a peak that falls between two samples.

The measured quantity is the squared modulus of the analytic true-power envelope, max_t |b(t)|^2, because a saved plane is what this is given and a file carries no mode. The value the run itself recorded is the analytic Poynting flux Re[a(t) conj(a_w(t))] of docs/guide/results/power-and-intensity.md, which needs the plane’s index; it is in stats/peak_power and is the number to quote. The two differ at second order in the variation of Re n_eff across the spectrum – of order 1e-7 of the peak for a gas-filled capillary, 7.95e-8 on the reduced comb-to-continuum witness – and their time integrals agree exactly by Parseval, so the energy does not move at all.

A general modal file is refused by name, as it is at the run loop, in both CPU backends and in solprop.processing.modal: modes='sum' here is solprop.stats.peak_power_total(), which promises a sum of coordinate powers that a three-component basis does not make, and solprop.processing.modal.reconstructed_flux() is that basis’s own flux (solprop.output.capability). Every older file, and every schema-7 run on an ordinary basis, is unaffected.

Parameters:
outputsolprop.output.schema.Output

An opened output handler.

planeint or None

Index of the plane wanted, negative from the end.

zfloat or None

Position of the plane wanted, m.

modesint, sequence of int, ‘sum’ or None

Which modes to report.

bandpasstuple of float, numpy.ndarray or None

Wavelength limits, m, of an explicit window applied before the measurement, or a ready-made window on the stored axis.

oversamplingint

Factor by which to resample the time axis before taking the maximum.

Returns:
numpy.ndarray

The peak power, W.

Raises:
solprop.exceptions.OutputError

If the stored run is a general modal one, which does not define this name.

Examples

>>> from solprop.processing._examples import example_output
>>> from solprop.processing.time import peak_power
>>> float(peak_power(example_output(), plane=0)) > 0.0
True
solprop.processing.time.time_bandwidth(output, *, plane=None, z=None, modes=None, bandpass=None)[source]#

Return the time-bandwidth product of a plane, or of every plane.

The product of the temporal and spectral widths at half maximum, which is 2 ln 2 / pi = 0.4413 for a transform-limited Gaussian and grows with any residual phase. One mode selection reaches both widths, so a modal sum does not silently measure the modes separately.

Parameters:
outputsolprop.output.schema.Output

An opened output handler.

planeint or None

Index of the plane wanted, negative from the end.

zfloat or None

Position of the plane wanted, m.

modesint, sequence of int, ‘sum’ or None

Which modes to report.

bandpasstuple of float, numpy.ndarray or None

Wavelength limits, m, of an explicit window applied before the temporal width, or a ready-made window on the stored axis.

Returns:
numpy.ndarray

The product, dimensionless.

Examples

>>> import numpy as np
>>> from solprop.processing._examples import example_output
>>> from solprop.processing.time import time_bandwidth
>>> product = time_bandwidth(example_output(), plane=0)
>>> bool(np.isclose(product, 2 * np.log(2) / np.pi, rtol=1e-2))
True