solprop.backends.exponential#
The phi functions and exponential Adams weights, in NumPy (SEP 16 sections 4.2-4.3).
Exponential Adams integrates the polynomial through untransported source samples
exactly against the linear flow. For a constant operator D, a step h and the
Lagrange basis ell_j(theta) = sum_k c_jk theta**k on the normalised nodes,
- w_j(x) = int_0^1 exp((1 - theta) x) ell_j(theta) dtheta
= sum_k c_jk k! phi_{k+1}(x),
with x = h D per element and phi_r(x) = sum_m x**m / (m + r)!. At a fraction
xi of the step the same integral to xi is
sum_k c_jk k! xi**(k+1) phi_{k+1}(xi x). At x = 0 these are the ordinary
Adams weights (solprop.stepper.multistep.integrated_weights()).
The phi functions are evaluated by two algorithms, each where it is stable:
near zero (
|x| <= 8): scale toy = x / 2**swith|y| <= 1/2, sum the Taylor series of the highest function to a fixed number of terms, recur down withphi_k(y) = 1/k! + y phi_{k+1}(y), which contracts an error by|y|and never divides byy, and undo the scaling by the doubling identityphi_k(2y) = [exp(y) phi_k(y) + sum_{j=1}^k phi_j(y) / (k - j)!] / 2**k, obtained by splitting the defining integral at one half [1] [2];away from zero (
|x| > 8): recur up fromphi_0 = exp(x),phi_k(x) = (phi_{k-1}(x) - 1/(k-1)!) / x, whose division by|x| > 8contracts the error of every earlier function.
Both are checked against augmented matrix exponentials and independent quadrature in
tests/backends/test_exponential_weights.py, on both sides of the join. This module
is the reference the compiled backends’ moment kernels are checked against.
References#
S. M. Cox and P. C. Matthews, “Exponential time differencing for stiff systems”, J. Comput. Phys. 176, 430 (2002). doi:10.1006/jcph.2002.6995
M. Hochbruck and A. Ostermann, “Exponential integrators”, Acta Numerica 19, 209 (2010), section 2. doi:10.1017/S0962492910000048
Module Attributes
Highest phi function evaluated: the corrector's |
|
|
|
The coupled flow's section methods the exponential formulation steps (SEP 16 Q3). |
|
The linear-operator representations the exponential formulation steps (SEP 16). |
Functions
|
Return the reference element's operator alone, or |
|
Return where a run's carrier frame takes its shift, or |
|
Return the exponential Adams weights of distinct nodes at each argument. |
|
Return |
|
Refuse a carrier frame where it is not yet delivered (SEP 35 section 5). |
|
Refuse the exponential formulation where it is not yet delivered (SEP 16). |
Classes
|
The reference element's cumulative operator alone (SEP 35 sections 6.1, 6.4). |
|
Where a run's carrier frame takes its shift, fixed for the run (SEP 35 6.1). |
- solprop.backends.exponential.COUPLED_SECTIONS = frozenset({'constant_schur', 'frozen_residual'})#
The coupled flow’s section methods the exponential formulation steps (SEP 16 Q3).
- class solprop.backends.exponential.CarrierChord(constant=None, expansion=None, table=None)[source]#
Bases:
objectThe reference element’s cumulative operator alone (SEP 35 sections 6.1, 6.4).
The operator’s own representation restricted to column 0, polarisation 0 and the reference bin, every batch member kept: its chord over a step is the reference element’s exponent, to rounding the one the backend forms, at one scalar per member. The step cap reads it for every proposal, and a backend that forms its exponent elsewhere (the native engine, on a device too) takes its shift from it with nothing read back.
- Attributes:
- constantnumpy.ndarray or None
Dat the element, 1/m, shape(n_batch_c,), for a constant operator.- expansionsolprop.translate.expansion.ParameterExpansion or None
The expansion with its terms at the element, for an expansion.
- tablesolprop.translate.chebyshev.PiecewiseChebyshev or None
The z table at the element, for a table.
- expansion: ParameterExpansion | None = None#
- exponent(z1, z2)[source]#
Return
Phi(z2) - Phi(z1)at the element, per batch member.- Parameters:
- z1, z2float
Positions in m, inside the operator’s span.
- Returns:
- numpy.ndarray
Dimensionless, shape
(n_batch_c,).
- table: PiecewiseChebyshev | None = None#
- class solprop.backends.exponential.CarrierReference(policy, bin, omega, reason, chord=None)[source]#
Bases:
objectWhere a run’s carrier frame takes its shift, fixed for the run (SEP 35 6.1).
The shift of batch member
bissigma_b = i Im x[b, 0, 0, bin],xthe trial’s own exponentPhi(z + h) - Phi(z): column 0 is the frame’s mode (build_phifixes the frame on the first mode; a coupled route’s carrier is the same in every channel), polarisation 0. The change of variable is exact for any shift, so the choice of bin only changes how smooth the interpolated source is.- Attributes:
- policy{‘scalar’}
The policy asked for (
solprop.stepper.multistep.CarrierFrame).- binint or None
The active bin nearest the reference frequency, ties to the lower index;
Nonewhere the policy is inert (sigma = 0for the run).- omegafloat or None
That bin’s angular frequency, rad/s;
Nonewith bin.- reasonstr
How the reference was chosen, or why the policy is inert, for the run’s log.
- chordCarrierChord or None, optional
The reference element’s operator alone (
carrier_chord()), for the step cap and a backend that forms its shift on the host;Nonewhen inert.
- property active: bool[source]#
Return whether the shift can be nonzero.
- Returns:
- bool
Falsewhen the run takessigma = 0, the present arithmetic exactly.
- chord: CarrierChord | None = None#
- chord_phase(z1, z2)[source]#
Return the largest carrier phase over the batch from the chord alone.
- Parameters:
- z1, z2float
The proposed step’s ends, m.
- Returns:
- float
max_b |Im (Phi(z2) - Phi(z1))|at the reference element, rad; 0 when the policy is inert.
- Raises:
- BackendError
If the reference has no chord (a separable operator).
- phase(exponent)[source]#
Return the largest carrier phase over the batch, for the step cap.
- Parameters:
- exponentnumpy.ndarray
xover a proposed step.
- Returns:
- float
max_b |Im x[b, 0, 0, bin]|, rad; 0 when the policy is inert.
- shift(exponent)[source]#
Return each batch member’s shift for a trial’s exponent.
- Parameters:
- exponentnumpy.ndarray
x = Phi(z + h) - Phi(z), in the canonical layout.
- Returns:
- numpy.ndarray
Purely imaginary, shape
(n_batch, 1, 1, 1), broadcasting against the state.
- Raises:
- BackendError
If the policy is inert: such a run takes the unshifted arithmetic.
- solprop.backends.exponential.EXPONENTIAL_REPRESENTATIONS = ('constant', 'separable', 'expansion', 'table')#
The linear-operator representations the exponential formulation steps (SEP 16).
A constant operator’s reference flow over a step is its exact flow and its residual is the source alone,
R_n = F. A varying one (expansion,table) takes the compensated reference of SEP 16 section 4.2 (phase 4): the chord over the step and the transported compensation(D(z_j) - B_n) u_j, withDthe derivative of the representation itself.
- solprop.backends.exponential.MAX_PHI_ORDER = 8#
Highest phi function evaluated: the corrector’s
MAX_ADAMS_ORDER + 1nodes needphi_1tophi_{MAX_ADAMS_ORDER + 1}, and one more serves a neighbouring order.
- solprop.backends.exponential.PHI_JOIN = 3.0#
|x|above which the phi functions are recurred up fromexp(x).Below it the upward recurrence loses digits to the subtraction of
1/(k-1)!: at order eight, 291 ulp of the natural scale at|x| = 2and 32 at 3, against augmented exponentials. Above it the scaled series would need more than three doublings. Three keeps both sides within the witnesses’ 256 ulp with a margin and bounds the doublings, the most expensive part of the near branch (SEP 16 phase 3; eight, the SEP 15 study’s join, cost up to four).
- solprop.backends.exponential.carrier_chord(linear, index)[source]#
Return the reference element’s operator alone, or
Nonefor a separable one.- Parameters:
- linearsolprop.translate.linop.LinearOperator
The cumulative operator.
- indexint
The reference bin.
- Returns:
- CarrierChord or None
Nonefor the separable (spatial) representation, which the carrier frame refuses.
- solprop.backends.exponential.carrier_reference(problem, method)[source]#
Return where a run’s carrier frame takes its shift, or
Nonewhen off.The reference rule of SEP 35 section 6.1. An envelope grid without the third harmonic subtracts
beta_0, so its shift would be the table’s rounding: the policy is inert there and the run is the present arithmetic exactly. An envelope grid with the third harmonic keeps the carrier phase whole, its operator is the field grid’s, and it is treated as one. The reference frequency is the grids’omega0; a custom frame with another reference changes only how much of the rotation the shift removes, never the step’s exactness.- Parameters:
- problemsolprop.translate.problem.KernelProblem
The problem.
- methodsolprop.stepper.multistep.Multistep
The method.
- Returns:
- CarrierReference or None
Noneforcarrier_frame="off"or the interaction formulation.
- solprop.backends.exponential.exponential_weights(nodes, x, upper=1.0, *, helpers=Helpers(name='numba'))[source]#
Return the exponential Adams weights of distinct nodes at each argument.
w_j = int_0^upper exp((upper - theta) x) ell_j(theta) dtheta, so thatexp(upper x) u_n + h sum_j w_j F_jadvancesu' = D u + Fbyupper hwhenFis the polynomial interpolating the samplesF_jat the nodes andx = h D.- Parameters:
- nodesnumpy.ndarray or list of float
Distinct normalised positions
(z_j - z_n) / h.- xnumpy.ndarray or complex
h Dper element, dimensionless.- upperfloat, optional
The fraction of the step integrated, in
[0, 1].- helperssolprop._helpers.Helpers, optional
The implementation of the Lagrange basis (SEP 29 section 6.6); the shared Numba one by default.
- Returns:
- numpy.ndarray
One weight per node along a new leading axis, each of x’s shape.
- Raises:
- StepperError
If the nodes are not distinct and finite, upper lies outside
[0, 1]or an argument overflows.
Examples
At
x = 0the weights are the ordinary Adams-Moulton ones:>>> import numpy as np >>> from solprop.backends.exponential import exponential_weights >>> (24 * exponential_weights([1, 0, -1, -2], 0.0)).real.round(12).tolist() [9.0, 19.0, -5.0, 1.0]
- solprop.backends.exponential.phi_functions(x, order)[source]#
Return
phi_0(x)tophi_order(x)for each element of x.phi_0(x) = exp(x)andphi_r(x) = int_0^1 exp((1 - theta) x) theta**(r-1) / (r-1)! dtheta.- Parameters:
- xnumpy.ndarray or complex
The arguments, dimensionless (a step times the linear operator). Their real parts must not exceed 700, where
expoverflows.- orderint
The highest function, in
[1, MAX_PHI_ORDER].
- Returns:
- numpy.ndarray
phi_r(x)along a new leading axis of lengthorder + 1.
- Raises:
- StepperError
If an argument is not finite or overflows, or the order is out of range.
Examples
>>> import numpy as np >>> from solprop.backends.exponential import phi_functions >>> values = phi_functions(np.array([0.0, 1.0]), 2) >>> np.round(values.real, 12).tolist() [[1.0, 2.718281828459], [1.0, 1.718281828459], [0.5, 0.718281828459]]
- solprop.backends.exponential.refuse_carrier_frame(problem, backend, *, delivered=frozenset({}))[source]#
Refuse a carrier frame where it is not yet delivered (SEP 35 section 5).
- Parameters:
- problemsolprop.translate.problem.KernelProblem
The problem.
- backendstr
The backend’s name, for the message.
- deliveredfrozenset of str, optional
The policies this backend steps; none by default.
- Raises:
- BackendError
Naming the policy and what does not deliver it.
- solprop.backends.exponential.refuse_formulation(problem, backend)[source]#
Refuse the exponential formulation where it is not yet delivered (SEP 16).
The exponential formulation steps constant, separable and varying diagonal operators (phases 2–4) and the constant-Schur and frozen-residual sections of a coupled flow (phase 5); a CF4 section is excluded (Q3) and refused by name before any source is evaluated.
- Parameters:
- problemsolprop.translate.problem.KernelProblem
The problem.
- backendstr
The backend’s name, for the message.
- Raises:
- BackendError
Naming what is unsupported.