solprop.nonlinear.envelope_plasma#

Cycle-averaged plasma sources for scalar and Cartesian vector envelopes.

The physical envelope is in V/m. This independent oracle integrates the real Cartesian field around an optical cycle with adaptive quadrature. It does not use the ellipse rules or tables compiled for a backend. The two returned current sources have different frequency factors; neither is a time-domain polarisation. See docs/guide/media/ionisation.md for the derivation and the frozen-cycle regime.

Functions

linear_cycle_average(rate, amplitude)

Return a rate averaged around one linearly polarised optical cycle.

linear_cycle_averages(rate, amplitudes)

Return a rate averaged around one linearly polarised cycle, at many amplitudes.

Classes

EnvelopePlasmaResponse(gas, rate, *[, ...])

Average an instantaneous isotropic rate over a physical envelope's cycle.

EnvelopePlasmaSources(ionisation_rate, ...)

Own the population and the two distinct envelope plasma source arrays.

class solprop.nonlinear.envelope_plasma.EnvelopePlasmaResponse(gas, rate, *, preionisation=0.0, species=None)[source]#

Bases: object

Average an instantaneous isotropic rate over a physical envelope’s cycle.

Attributes:
gasGas or str or Species

Chemical species supplying the first ionisation potential. Beside a rate that carries its own energy per event (an OptmatRate), the species is stored with that energy as its potential (bind_rate_energy(), SEP 3, D8).

rateEvaluableRate

Magnitude rate in s^-1 for V/m, declaring convention = 'instantaneous-isotropic', as optmat’s rates do (OptmatRate); a cycle-averaged rate is refused. Molecular orientation averaging is compatible. The rate must vanish at zero field and give an integrable loss current.

preionisationfloat or ZProfile

Initial ionised fraction in [0, 1], default zero: a number, or a path along z in m giving the fraction ionised before the pulse arrives at each position. The reference methods see one plane, so a path is resolved by the translation layer and the oracle for a plane is dataclasses.replace() with its value.

speciesstr or None

Optional nonempty component label, distinct from the chemical identity.

Notes

This is the frozen-cycle approximation: the envelope and population vary slowly compared with one optical cycle. It neither models carrier-scale depletion nor changes the physical parameters of the supplied rate model. The loss current retains both directional moments of a vector ellipse.

Examples

>>> from solprop.nonlinear.optmat_rates import OptmatRate
>>> rate = OptmatRate("Ar", 800e-9)
>>> response = EnvelopePlasmaResponse("Ar", rate, preionisation=0.25)
>>> source = response.sources(np.zeros((2, 3), complex), 1e25, dt=1e-16)
>>> source.fraction.tolist()
[0.25, 0.25, 0.25]
gas: Gas | str | Species#
ionised_fraction(field_t, *, dt)[source]#

Return a fresh population history from cycle-averaged exposure.

Parameters:
field_tnumpy.ndarray

Physical complex V/m envelope, shape (n_pol, n_to).

dtfloat

Positive finite time spacing in s.

Returns:
numpy.ndarray

Fraction in [preionisation, 1], shape (n_to,). The first sample is exactly the initial fraction, including for a one-sample input.

Raises:
GridError

If the field, spacing or evaluated rates are invalid.

ConvergenceError

If adaptive angular integration fails.

MaterialError

If the preionisation is a path along z rather than one plane’s value.

property potential: float[source]#

Return the species’ first ionisation potential.

Returns:
float

Binding energy in J.

Raises:
MaterialError

If the material supplies no ionisation data.

preionisation: float | ZProfile = 0.0#
rate: EvaluableRate#
sources(field_t, density, *, dt)[source]#

Return fresh cycle-averaged population, Drude drive and loss current.

Parameters:
field_tnumpy.ndarray

Physical complex envelope in V/m, shape (n_pol, n_to); one or two Cartesian components and at least one sample. Modal √W amplitudes must be converted to physical fields before this call.

densityfloat

Initial particle density in m^-3, finite and non-negative.

dtfloat

Time spacing in s, finite and positive.

Returns:
EnvelopePlasmaSources

New arrays, with the first fraction exactly preionisation. The population is integrated by the trapezoidal prefix convention.

Raises:
GridError

If inputs or evaluated rates are invalid, or sources are not finite.

ConvergenceError

If the independent adaptive cycle integral exhausts its budget.

MaterialError

If the preionisation is a path along z rather than one plane’s value.

species: str | None = None#
property traits: ResponseTraits[source]#

Declare temporal memory, envelope support and isotropic vector behaviour.

Returns:
ResponseTraits

Density and pre-ionisation profiles, optionally labelled per component. The compiled response also carries a distinct spectral assembly.

class solprop.nonlinear.envelope_plasma.EnvelopePlasmaSources(ionisation_rate, fraction, drude_drive, loss_current)[source]#

Bases: object

Own the population and the two distinct envelope plasma source arrays.

Attributes:
ionisation_ratenumpy.ndarray

Cycle-averaged rate in s^-1, shape (n_to,), finite and non-negative.

fractionnumpy.ndarray

Ionised fraction in [0, 1], shape (n_to,).

drude_drivenumpy.ndarray

(e²/m_e) density fraction field_t, in A m^-2 s^-1, complex, shape (n_pol, n_to) with one or two Cartesian components.

loss_currentnumpy.ndarray

Ionisation-work current in A m^-2, complex, shape (n_pol, n_to).

Notes

Construction copies the arrays. Calls never share source or population storage.

drude_drive: Complex[ndarray, 'n_drive_pol n_drive_t']#
fraction: Float[ndarray, 'n_fraction_t']#
ionisation_rate: Float[ndarray, 'n_rate_t']#
loss_current: Complex[ndarray, 'n_loss_pol n_loss_t']#
solprop.nonlinear.envelope_plasma.linear_cycle_average(rate, amplitude)[source]#

Return a rate averaged around one linearly polarised optical cycle.

The envelope plasma’s own average, (1/2 pi) int W(|a cos theta|) d theta for an envelope amplitude a, to its adaptive quadrature’s 2e-10, from one evaluation of the rate (linear_cycle_averages(), which takes many).

Parameters:
rateEvaluableRate

Instantaneous magnitude rate in s^-1 of a field in V/m, vectorised.

amplitudefloat

Envelope amplitude in V/m, non-negative and finite.

Returns:
float

The cycle-averaged rate in s^-1.

Raises:
GridError

If the amplitude is not finite and non-negative.

ConvergenceError

If the fixed rule could not certify the amplitude and the adaptive integral exhausts its budget.

Examples

>>> from solprop.nonlinear.envelope_plasma import linear_cycle_average
>>> from solprop.nonlinear.optmat_rates import OptmatRate
>>> linear_cycle_average(OptmatRate("Ar", 800e-9), 0.0)
0.0
solprop.nonlinear.envelope_plasma.linear_cycle_averages(rate, amplitudes)[source]#

Return a rate averaged around one linearly polarised cycle, at many amplitudes.

The envelope plasma’s own average, (1/2 pi) int W(|a cos theta|) d theta for each envelope amplitude a, to the relative tolerance of its adaptive quadrature, 2e-10. It evaluates the rate once for all the amplitudes, on a fixed Gauss–Legendre rule of order 32 over each piece of the quarter cycle between the field bounds the rate declares, with an embedded rule of order 24: where the two agree to the tolerance, the higher one’s error is below it; elsewhere (a corner the rate does not declare, such as a ceiling on its value) that amplitude takes the adaptive quadrature of the envelope’s sources instead.

Parameters:
rateEvaluableRate

Instantaneous magnitude rate in s^-1 of a field in V/m, vectorised.

amplitudesnumpy.ndarray

Envelope amplitudes in V/m, non-negative and finite, shape (n_amplitude,).

Returns:
numpy.ndarray

The cycle-averaged rates in s^-1, shape (n_amplitude,).

Raises:
GridError

If an amplitude is not finite and non-negative, or the rate returns values that are not finite, non-negative and real.

ConvergenceError

If an amplitude the fixed rule could not certify exhausts the adaptive integral’s budget.

Examples

>>> import numpy as np
>>> from solprop.nonlinear.envelope_plasma import linear_cycle_averages
>>> from solprop.nonlinear.optmat_rates import OptmatRate
>>> linear_cycle_averages(OptmatRate("Ar", 800e-9), np.array([0.0, 1e9])).shape
(2,)