solprop.translate.ionisation#

Ionisation rates as converged, clipped, log-spaced spline tables.

Evaluating a rate model directly – optmat’s, through solprop.nonlinear.optmat_rates.OptmatRate – costs of order a microsecond per sample, special functions per point, per stage. A propagation evaluates the rate once per sample of the fine time grid on every column of every stage, so the rate has to be a table. This module builds it.

Three properties of the table matter:

  • Log-spaced knots. log W is nearly linear in log E at the low-field turn-on and flattens at high field, so uniform knots in log E put the samples where the curvature is and let one table span four decades. Knots uniform in E over the same span reach only about one per cent.

  • A converged knot count. The count doubles until the interpolant meets the requested relative tolerance against direct evaluation everywhere, rather than being fixed in advance.

  • Clipping rather than throwing. A rate that raised above its maximum field would stop a run in the middle of a propagation. Here the table is exactly zero below field_min – which the plasma loss term Ip W (1-f) / E relies on – and holds its last value above field_max, so a diverged step cannot extrapolate a cubic in log W into an overflow (docs/dev/stepper.md section 10, trap 9).

The manual page is docs/guide/media/ionisation.md; the kernel’s view of the table is docs/dev/kernel-contract.md section 5.

Module Attributes

SCHEMA_VERSION

Version of the table layout, part of the cache key.

DEFAULT_RTOL

Default bound on the relative error of the table against direct evaluation.

DEFAULT_INTERVALS

Knot intervals tried first; the count doubles until the tolerance is met.

MAX_KNOTS

Knot budget before the build gives up.

Functions

build_rate_table(rate, field_range, *[, ...])

Build a converged spline table of an ionisation rate.

clear_rate_table_cache()

Forget every table built in this process.

rate_table_key(rate, field_range, rtol)

Return the deterministic cache key of a table.

Classes

RateTable(log_rate, coefficients, ...[, ...])

A cubic-spline table of log W against log E, on uniform log-spaced knots.

solprop.translate.ionisation.DEFAULT_INTERVALS: Final = 256#

Knot intervals tried first; the count doubles until the tolerance is met.

solprop.translate.ionisation.DEFAULT_RTOL: Final = 1e-06#

Default bound on the relative error of the table against direct evaluation.

solprop.translate.ionisation.MAX_KNOTS: Final = 1048576#

Knot budget before the build gives up.

A million knots over four decades is a spacing of 1e-5 in log E; needing more means the rate is not smooth, which for these models means a kink, not a fine feature.

class solprop.translate.ionisation.RateTable(log_rate, coefficients, log_field_min, d_log_field, field_min, field_max, rate_max, error, key, convention='unspecified', species_identity=None, ionisation_potential=None)[source]#

Bases: object

A cubic-spline table of log W against log E, on uniform log-spaced knots.

Knots are uniform in log E, so locating one is arithmetic rather than a search: i = floor((log|E| - log_field_min) / d_log_field). On interval i the value is sum_j coefficients[j, i] t^(3-j) with t = log|E| - log_field_min - i d_log_field, which is how scipy.interpolate.CubicSpline stores it. The coefficients rather than a spline object are the table, because they are what crosses into the kernel contract.

Attributes:
log_field_minfloat

Natural logarithm of field_min, with the field in V/m.

d_log_fieldfloat

Knot spacing in log E, positive.

log_ratenumpy.ndarray

Natural logarithm of the rate at each knot, shape (n_table,), s^-1. Diagnostic: evaluation goes through the coefficients.

coefficientsnumpy.ndarray

Spline coefficients, shape (n_deg, n_intervals), highest power first.

field_minfloat

Field amplitude in V/m below which the table is exactly zero.

field_maxfloat

Field amplitude in V/m above which the table holds rate_max.

rate_maxfloat

The rate at field_max, s^-1, and the value returned above it.

errorfloat

The largest relative deviation from direct evaluation measured during the build.

keystr

A digest of the rate’s parameters and the build settings, stable across processes. Names a cache entry; two tables with the same key are the same table.

conventionstr

Optical-cycle convention retained from the source rate. Legacy manually constructed tables default to 'unspecified'.

species_identitystr or None

Chemical species name, when declared by the source rate.

ionisation_potentialfloat or None

First ionisation potential in J, when declared by the source rate.

Raises:
TranslationError

If the knot spacing is not positive, the coefficient array does not have four rows and one column per interval, the field range is not increasing, or anything stored is not finite.

Examples

>>> from solprop.nonlinear.optmat_rates import OptmatRate
>>> from solprop.translate.ionisation import build_rate_table
>>> table = build_rate_table(OptmatRate("Ar", 800e-9), (1e9, 5e10), rtol=1e-4)
>>> float(table(1e6))
0.0
>>> abs(float(table(3e10)) / float(OptmatRate("Ar", 800e-9)(3e10)) - 1.0) < 1e-4
True
coefficients: Float[ndarray, 'n_deg n_intervals']#
convention: Literal['instantaneous-isotropic', 'cycle-averaged', 'unspecified'] = 'unspecified'#
d_log_field: float#
error: float#
property field: Float[ndarray, 'n_table'][source]#

Return the knot positions as field amplitudes.

Returns:
numpy.ndarray

Geometrically spaced field amplitudes in V/m, shape (n_table,).

field_max: float#
field_min: float#
ionisation_potential: float | None = None#
key: str#
log_evaluate(log_field)[source]#

Return the interpolated log W at logarithmic field amplitudes.

This is the interpolant itself, without the clipping and without the exponential. The build measures its error here rather than on the rate, because a difference of logarithms is the relative error and does not underflow where the rate is 1e-300.

Parameters:
log_fieldnumpy.ndarray

Natural logarithms of field amplitudes in V/m, shape (n_probe,), inside [log(field_min), log(field_max)].

Returns:
numpy.ndarray

Interpolated log W with the rate in s^-1, shape (n_probe,).

property log_field: Float[ndarray, 'n_table'][source]#

Return the knot positions in log E.

Returns:
numpy.ndarray

Uniformly spaced logarithms of the field amplitude, shape (n_table,).

log_field_min: float#
log_rate: Float[ndarray, 'n_table']#
property n_knots: int[source]#

Return the number of knots.

Returns:
int

The knot count, one more than the number of intervals.

property plasma_energy: float | None[source]#

Return the energy per ionisation event the source rate declared, in J.

A table keeps the species and the energy of the rate it tabulates, so that a plasma response built on the table pays the same energy as one built on the rate (solprop.nonlinear.ionisation.bind_rate_energy(), SEP 3, D8).

Returns:
float or None

ionisation_potential when the source rate named its species and energy; None otherwise.

rate_max: float#
species_identity: str | None = None#
solprop.translate.ionisation.SCHEMA_VERSION: Final = 2#

Version of the table layout, part of the cache key.

Bump it when the knot placement, the spline convention or the clipping changes, so that a table built by an older version can never be mistaken for one built by this one.

solprop.translate.ionisation.build_rate_table(rate, field_range, *, rtol=1e-06, n_intervals=256, max_knots=1048576, use_cache=True)[source]#

Build a converged spline table of an ionisation rate.

The knot count doubles until the interpolant is within rtol of direct evaluation at every probe point, which is what makes the table’s accuracy a stated property rather than a consequence of a fixed sample count.

Parameters:
rateIonisationRate

The rate to tabulate, in s^-1 for a field amplitude in V/m.

field_rangetuple of float

Lower and upper field amplitude in V/m. The lower end is raised to the rate’s threshold and the upper end lowered below any clipping; see the table’s field_min and field_max for what was used.

rtolfloat, optional

Bound on the relative deviation from direct evaluation, measured as the largest absolute difference of logarithms.

n_intervalsint, optional

Knot intervals to try first.

max_knotsint, optional

Knot budget before the build gives up.

use_cachebool, optional

Reuse a table already built in this process for the same key, and record this one under it.

Returns:
RateTable

The converged table.

Raises:
TranslationError

If the arguments are inconsistent, nothing is left of the field range, or the tolerance is not reached within max_knots.

Examples

>>> from solprop.nonlinear.optmat_rates import OptmatRate
>>> from solprop.translate.ionisation import build_rate_table
>>> table = build_rate_table(OptmatRate("Ar", 800e-9), (1e9, 5e10), rtol=1e-6)
>>> table.error < 1e-6
True
solprop.translate.ionisation.clear_rate_table_cache()[source]#

Forget every table built in this process.

The cache exists so that two responses sharing a rate share its table; it is a memo, not a store, and nothing is written to disk. Tests that count builds clear it first.

Examples

>>> from solprop.translate.ionisation import clear_rate_table_cache
>>> clear_rate_table_cache()
solprop.translate.ionisation.rate_table_key(rate, field_range, rtol)[source]#

Return the deterministic cache key of a table.

Every setting that changes the table appears once, in name order, so the key cannot depend on the order in which the rate’s keyword arguments were written: the same settings in a different order give the same cache file.

Parameters:
rateIonisationRate

The rate to tabulate.

field_rangetuple of float

Lower and upper field amplitude in V/m.

rtolfloat

Requested relative tolerance.

Returns:
tuple

A hashable key, beginning with the schema version.

Examples

>>> from solprop.nonlinear.optmat_rates import OptmatRate
>>> from solprop.translate.ionisation import rate_table_key
>>> first = OptmatRate("Ar", 800e-9)
>>> second = OptmatRate("Ar", 800e-9)
>>> rate_table_key(first, (1e9, 1e11), 1e-6) == rate_table_key(
...     second, (1e9, 1e11), 1e-6
... )
True