solprop.translate.responses#
Response definitions compiled into one fused time-domain pass.
A response says what polarisation a medium produces from the field at a point
(solprop.nonlinear.responses); a backend needs coefficients, a table and an
ordering it can execute without knowing any physics. This module performs that
compilation for the responses that exist: the instantaneous Kerr term, the delayed
Raman term, the ionisation rate as a spline table, the UPPE prefactor and the temporal
absorber. Section 5 of docs/dev/kernel-contract.md is the class
CompiledResponses, field for field.
What is not compiled yet is refused rather than half-built. The spectral-domain
responses have a field in the contract and no compiler here, so it stays
empty and its flag stays false; anything else raises a
solprop.exceptions.TranslationError naming the response, so nothing reaches a
backend that would evaluate a term it does not have. A response that declares it is
undefined on the problem’s grid is refused with that reason: the plasma model is written
for a resolved carrier and has no envelope form.
The Raman fraction is not this module’s business. A response that declares
fraction is one whose author already reduced the Kerr coefficient beside it –
solprop.nonlinear.gnlse.kerr_susceptibility() does exactly that for the GNLSE –
and a molecular gas’s Raman response is absolute, with the full electronic chi3
beside it. Applying (1 - f_R) here would either double the reduction or invent one,
and would reduce the Kerr term even with Raman switched off.
The Raman drive form is a property of the problem. Whether a field grid’s drive
keeps the 2 omega beat is not a property of each response: a drive that keeps it
radiates a third harmonic through the later multiplication by the field, and a grid
built without one does not oversample enough to hold it. So the compiler checks that
the declared Kerr and Raman responses agree about thg on a field grid, and refuses
a field-grid Raman response with no Kerr response beside it. That is why the answer is
a field of RamanCoefficients rather than of either response.
The prefactor carries the crop scale of the oversampling round trip; the pad scale
is in the synthesis, for the reason given in solprop.translate.modal. It is zero
outside the active band rather than one: raw, unnormalised polarisation left in the
out-of-band bins would be seen by every Runge-Kutta stage and every error estimate.
It also follows z. Re n_eff(omega, z) moves with the gas and the bore, so on a
gradient fill or a taper the prefactor is not one array but a path. Rather than being
evaluated afresh at every stage, it is resolved once, the way Phi is
and in whichever of Phi’s two representations the mode set allows: an expansion in
the scalar paths the modes declare, with the plain products of the basis polynomials as
its weights because the prefactor is a value at z and not a cumulative one, or an
adaptive Chebyshev table of z over the same span and split on the same declared kinks.
Either is one pass per stage through prefactor_at(). A mode set that does not vary
along z carries the array instead, in prefactor_constant, and a backend takes that
fast path.
Module Attributes
Least oversampling a third-harmonic term needs, so that |
|
Which cubic a general modal guide's instantaneous response is. |
|
The model identity each instantaneous form is recorded under. |
|
The inverse of |
|
The model tag a compiled record carries when a region declares a delayed term. |
|
What joins the model tags of one compiled record's |
Functions
|
Compile a set of responses into the nonlinear term a kernel executes. |
|
Classify a run's active band for each dispersive response it declares. |
|
Sample the dispersive responses' multipliers on a grid's fine layout. |
|
Return the |
|
Return the dimensionless rank-four tensor of an isotropic Kerr medium. |
|
Reduce a Kerr response on a grid to the numbers a fused pass needs. |
|
Reduce a plasma response to the coefficients a fused pass needs. |
|
Return the prefactor at one position, taking the fast path when there is one. |
|
Compile a Raman response into the leaf of section 5, or |
|
Compile one material region's declared responses into the seam's leaf. |
|
Return where the response paths kink, each with the name of its path. |
|
Return the response kinks inside the run that no step is made to land on. |
Classes
|
The nonlinear term of the propagation equation, ready for a kernel. |
|
SEP 6's frequency-dependent electronic response, reduced to arrays. |
|
The instantaneous third-order polarisation, reduced to numbers. |
|
Bind an independent exposure scan to a labelled population. |
|
The plasma response, reduced to two constants, a path and a table. |
|
The delayed response of a Raman-active medium, as a fused pass needs it. |
|
Say which material responds at each node, and with what tensor and kernel. |
|
One step of the fused time-domain traversal, in execution order. |
- class solprop.translate.responses.CompiledResponses(response_order, kerr_coefficients, ionisation_table, plasma_channels, raman_terms, density, spectral_responses, prefactor_representation, prefactor, prefactor_expansion, prefactor_constant, temporal_absorber, temporal_absorber_fine, absorber_scheme='nonlinear', separable=None, labels=('medium', ), species_names=('medium', ), species_densities=(), envelope_plasma=None, regional_responses=None, dispersive_kerr=None, plasma_integral=<factory>)[source]#
Bases:
objectThe nonlinear term of the propagation equation, ready for a kernel.
Section 5 of the kernel contract. Every array is a read-only, C-contiguous copy of the stated dtype.
- Attributes:
- response_ordertuple of ResponseStage
The fused-pass sequence, in execution order.
- kerr_coefficientsKerrCoefficients or None
The compiled Kerr term, or
Nonewhen no Kerr response was declared.- ionisation_tabletuple of RateTable
Channel rate tables, identity-matched to plasma_channels.
- plasma_channelstuple of PlasmaChannel
Independent labelled populations with rates, potentials and density paths.
- raman_termstuple of RamanCoefficients
Raman-active components with their amplitude densities and total-density linewidth tables. Each component may carry rotation, vibration or both.
- labelstuple of str
Unique component labels, including non-ionising and zero-density components.
- species_namestuple of str
Chemical names in label order; a species may occur under several labels.
- species_densitiestuple of PiecewiseChebyshev
Number densities in m^-3, in label order.
- densitysolprop.translate.chebyshev.PiecewiseChebyshev
Number density along z, in m^-3 for a gas or dimensionless 1 for a medium whose
chi3is already absolute, as a table.- spectral_responsestuple of EnvelopePlasmaAssembly
Typed post-transform assembly; empty or the
envelope_plasmarecord.- envelope_plasmaEnvelopePlasmaAssembly or None
Independent envelope populations, cycle data and spectral multipliers.
- prefactor_representation{‘constant’, ‘expansion’, ‘table’}
Which representation carries the prefactor, following section 3’s choice for
Phiand made the same way. The first two are the device form; the z table is the oracle’s general representation (solprop.translate.problem.KernelProblem.device_ready).- prefactorsolprop.translate.chebyshev.PiecewiseChebyshev or None
The UPPE or envelope prefactor times the crop scale, as a table along z with value shape
(n_modes, n_pol, n_omega), complex128, in m/(V s) per unit polarisation. Purely imaginary and exactly zero outside the active band at every position. The table spans the same z range asPhi. Present when prefactor_representation is"table"and also for"constant", whose one interval of degree 0 is exact; absent for"expansion".- prefactor_expansionsolprop.translate.expansion.ParameterExpansion or None
The same quantity as an expansion in the mode set’s scalar paths, with the plain products of the basis polynomials as its weights rather than their integrals, since the prefactor is not cumulative. Present exactly when prefactor_representation is
"expansion".- prefactor_constantnumpy.ndarray or None
The prefactor itself, complex128, shape
(n_modes, n_pol, n_omega), present exactly when prefactor_representation is"constant"– every mode reportsz_constant– so that a backend takes the array rather than a Clenshaw pass. The mirror ofsolprop.translate.linop.LinearOperator.phi_constant.- temporal_absorbernumpy.ndarray or None
The temporal collar as a rate in 1/m on the coarse time axis, shape
(n_t,), orNone.- temporal_absorber_finenumpy.ndarray or None
The same rate on the fine time axis, shape
(n_to,), which the"nonlinear"absorber scheme needs, orNone.- absorber_scheme{‘split_step’, ‘nonlinear’}
Which of the two exact applications of the temporal rate to use (
solprop.translate.masks.AbsorberScheme).- separablesolprop.translate.spatial.SeparableOperator or None
Shared constant spatial operator and prefactor coefficients, present exactly for representation
"separable"; identical tolinear.separable.- regional_responsesRegionalResponseTables or None
Kernel schema 12: the node-region response assignment of a general modal guide, preserving the existing gas law and table identities.
Noneon every route that goes through the compiled fused pass above.- dispersive_kerrDispersiveKerrTerms or None
Kernel schema 24: SEP 6’s frequency-dependent electronic response, one channel per population, or
None.- plasma_integralRunningIntegral
Kernel schema 25: the running-integral rule of the field-grid plasma column (SEP 18), one per problem because the channels share the two current integrals. The plain trapezoid without field plasma channels.
- Raises:
- TranslationError
If the constant prefactor does not have the table’s value shape, an absorber rate is present without the other, or the three Raman fields are not all present or all absent.
Examples
>>> from solprop.grid import EnvelopeGrid >>> from solprop.nonlinear.gnlse import problem_from >>> from solprop.translate.responses import compile_responses >>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (500e-9, 2e-6), 4e-12) >>> problem = problem_from([0.0, 0.0, -1e-26], omega_ref=grid.omega0, gamma=0.1, ... shock=False) >>> compiled = compile_responses([problem.kerr], grid, problem.mode, density=1.0, ... z_max=1.0, shock=False, prefactor_index=1.0) >>> compiled.response_order (<ResponseStage.KERR: 'kerr'>, <ResponseStage.ACCUMULATE: 'accumulate'>)
- density: PiecewiseChebyshev#
- dispersive_kerr: DispersiveKerrTerms | None = None#
- property electronic_thg: bool | None[source]#
Return the field grid’s harmonic form, read off the electronic term.
- Returns:
- bool or None
Whether the electronic cubic keeps the third harmonic on a field grid – the constant Kerr term’s real cubic, or the dispersive term’s full sector – or
Nonewith no electronic term.
- envelope_plasma: EnvelopePlasmaAssembly | None = None#
- property harmonic_carrier: bool[source]#
Return whether the pass needs
grids.carrier_2w0.- Returns:
- bool
True when an envelope grid’s constant Kerr term radiates the harmonic, or its dispersive term keeps the full cubic.
- kerr_coefficients: KerrCoefficients | None#
- property n_species: int[source]#
Return the number of labelled populations.
- Returns:
- int
Length of the species axis, including inactive populations.
- plasma_channels: tuple[PlasmaChannel, ...]#
- property plasma_coefficients: PlasmaChannel | None[source]#
Return the one-channel leaf for the original specialised execution path.
- Returns:
- PlasmaChannel or None
The sole channel, or
Nonewhen there are zero or multiple channels.
- plasma_integral: RunningIntegral#
- property population_channels: tuple[PlasmaChannel | EnvelopePlasmaChannel, ...][source]#
Return labelled population channels in material order.
- Returns:
- tuple
Field channels or envelope channels. Their stage density and initial population paths share the same scalar packing order.
- prefactor: PiecewiseChebyshev | None#
- prefactor_expansion: ParameterExpansion | None#
- property prefactor_span: tuple[float, float][source]#
Return the range of z the prefactor covers.
- Returns:
- tuple of float
(first breakpoint, last breakpoint)in m, the same asPhi’s.
- property prefactor_value_shape: tuple[int, ...][source]#
Return the shape of the prefactor at one position.
- Returns:
- tuple of int
(n_modes, n_pol, n_omega), whichever representation carries it.
- property raman_coefficients: RamanCoefficients | None[source]#
Return the one-component Raman leaf for its original arithmetic.
- Returns:
- RamanCoefficients or None
The sole component, or
Nonewhen there are zero or multiple terms.
- raman_terms: tuple[RamanCoefficients, ...]#
- regional_responses: RegionalResponseTables | None = None#
- response_order: tuple[ResponseStage, ...]#
- separable: SeparableOperator | None = None#
- species_densities: tuple[PiecewiseChebyshev, ...] = ()#
- spectral_responses: tuple[EnvelopePlasmaAssembly, ...]#
- solprop.translate.responses.DELAYED_MODEL_ID: Final[str] = 'silica-tensor-raman'#
The model tag a compiled record carries when a region declares a delayed term.
- class solprop.translate.responses.DispersiveKerrTerms(evaluator, sector, carrier, labels, coefficients, positive, filters, outputs, products, densities, regions=None)[source]#
Bases:
objectSEP 6’s frequency-dependent electronic response, reduced to arrays.
The reference is
solprop.nonlinear.responses.DispersiveKerrResponse.evaluate(), whose arithmeticsolprop.nonlinear.responses.dispersive_cubic()is, and whose multipliers these arrays are, sampled on the problem’s own fine spectral layout at absolute frequency. Each labelled species is its own channel with its own multipliers and density. How the channels combine is the evaluator’s (groups()):the polynomial is the exact per-species sum,
P = sum_s coefficient_s rho_s cubic_s(E), which a backend may regroup exactly (species of equal leg bound share their derivative fields);the symmetric evaluator takes, for the channels that act at the same nodes – every channel, or one general modal region’s – one filter from their mixture’s Kerr diagonal, rebuilt from the channels’ densities at every stage:
P = F G_mix[w (G_mix E)^3]withF = sum_s coefficient_s rho_sandg_mix = [sum_s coefficient_s rho_s g_s^4 / F]^(1/4)(solprop.nonlinear.responses.mixture_filter(); SEP 6 section 6, adopted for mixtures on 2026-10-08). One species is its own operator exactly.
- Attributes:
- evaluator{‘symmetric’, ‘polynomial’}
Which evaluator every channel takes.
- sector{‘full’, ‘conserving’}
Which quartets are kept: the full cubic (
thg=True) or the number-conserving sector (thg=False).- carrierbool
Whether the pass needs
grids.carrier_2w0: true exactly for the full sector on an envelope grid, whose harmonic groups sit+-2 omega0from the envelope’s carrier.- labelstuple of str
The channel’s population label, one per channel, in species order.
- coefficientstuple of float
eps0 gamma3_0per channel, the static coefficient per unit density.- positivenumpy.ndarray
Pi_+on the fine spectral layout, bool, shape(n_omega_fine,).- filtersnumpy.ndarray
Each channel’s input multiplier, float64, shape
(n_channels, n_omega_fine): the symmetric factorg, or the polynomial’s bounded leg weight in m^-2.- outputsnumpy.ndarray or None
The polynomial’s two output multipliers per channel, float64, shape
(n_channels, 2, n_omega_fine);Nonefor the symmetric evaluator.- productsnumpy.ndarray or None
The polynomial’s two constant product weights per channel, float64, shape
(n_channels, 2), in m^4;Nonefor the symmetric evaluator.- densitiestuple of PiecewiseChebyshev
Each channel’s number density along z, m^-3.
- regionsnumpy.ndarray or None
On the general modal route, the node region each channel acts in, int32, shape
(n_channels,), non-negative: a region’s gas fill contributes one channel per species, and a node responds to the channels of its own region.Noneon every other route, where a channel is a population of the run’s material and acts at every node.
- Raises:
- TranslationError
If the vocabulary, the channel counts or the array shapes disagree.
- densities: tuple[PiecewiseChebyshev, ...]#
- evaluations(densities)[source]#
Return the cubics the reference evaluates at a stage, and their factors.
The polarisation is
sum factor cubic(E; weights)over the returned terms, each acting at the nodes of its channel’s region: one per channel for the polynomial, the exact per-species sum; one per group for the symmetric evaluator, its mixture filter built from the group’s densities here (solprop.nonlinear.responses.mixture_filter()), one species’ its own.- Parameters:
- densitiessequence of float
Each channel’s number density at the stage, m^-3, in channel order.
- Returns:
- tuple of tuple
(channel, factor, weights): the first channel of the term, whose region it acts in;eps0 gamma3_0 rhosummed over its channels, C/V^3; and its multipliers.
- filters: Float[ndarray, 'n_channels n_omega_fine_f']#
- groups(keys=None)[source]#
Return the channels that combine, each group in channel order.
For the symmetric evaluator a group is the channels that act at the same nodes, whose mixture filter they share (
solprop.nonlinear.responses.mixture_filter()). For the polynomial a group is the channels whose leg-weight rows are equal bit for bit and that act at the same nodes: they share their derivative fields, and summing their coefficient tables is an exact rewriting of the per-species sum.- Parameters:
- keyssequence of int or None, optional
A key per channel that must also agree within a group;
Nonetakes the leaf’s node regions, or a single key where it has none.
- Returns:
- tuple of tuple of int
The groups, in the order of their first channel.
- property n_channels: int[source]#
Return the number of species channels.
- Returns:
- int
One per labelled population with a dispersive response.
- positive: Bool[ndarray, 'n_omega_fine']#
- solprop.translate.responses.KERR_FORM_MODEL_IDS: Final[Mapping[str, str]] = {'analytic': 'isotropic-kerr', 'real': 'isotropic-kerr-real'}#
The model identity each instantaneous form is recorded under.
The form is a physical model choice and so lives in
model_id, which is already a representation tag inside the resume identity. It is not a new leaf field: adding one would move a contract row and bump the kernel schema, and there is nothing else the form needs to carry.
- solprop.translate.responses.KERR_MODEL_FORMS: Final[Mapping[str, str]] = {'isotropic-kerr': 'analytic', 'isotropic-kerr-real': 'real'}#
The inverse of
KERR_FORM_MODEL_IDS, which a backend reads a form back from.A model identity outside this mapping is refused by name rather than executed as one of the two, because a caller who declares a model this package does not know must not have it silently evaluated as another.
- class solprop.translate.responses.KerrCoefficients(coefficient, cubic_form, self_factor, conjugate_factor, harmonic_factor, analytic_signal, take_real, density=None)[source]#
Bases:
objectThe instantaneous third-order polarisation, reduced to numbers.
The reference implementation is
solprop.nonlinear.responses.KerrResponse.evaluate(), and these coefficients are read off it rather than re-derived, so the compiled pass and the oracle cannot drift apart. Two cubic forms exist, because a field grid resolves the carrier and an envelope grid does not:"real"P_p = coefficient rho (sum_q E_q^2) E_p— the full cubic of a real field, which already carries the third harmonic and the counter-rotating terms."analytic"P_p = coefficient rho [self (sum_q |a_q|^2) a_p + conjugate (sum_q a_q^2) conj(a_p)], pluscoefficient rho harmonic exp(2 i omega_0 t) (sum_q a_q^2) a_pwhen the harmonic is wanted on an envelope grid. For one component the first collapses to(3/4)|a|^2 a.
- Attributes:
- coefficientfloat
eps0 chi3per unit of the density path, in m^2/V^2 when the density is dimensionless and m^5/V^2 when it is a number density in m^-3. The density is the contract’sdensitytable and multiplies this at every position.- cubic_form{‘real’, ‘analytic’}
Which of the two forms above the pass evaluates.
- self_factorfloat
Weight of the
(sum |a_q|^2) a_pterm;0.5in the analytic form.- conjugate_factorfloat
Weight of the
(sum a_q^2) conj(a_p)term;0.25in the analytic form.- harmonic_factorfloat
Weight of the third-harmonic term;
0.25on an envelope grid that radiates it, zero otherwise.- analytic_signalbool
Whether the pass must form the analytic signal of the real field first. True on a field grid in the analytic form, false on an envelope grid, where the state already is one.
- take_realbool
Whether the polarisation is the real part of the result. True on a field grid.
- densityPiecewiseChebyshev or None
The scale multiplying coefficient at each z. A composite uses sum(rho*gamma3) with coefficient=eps0; a single response retains its original coefficient and density operation order. None is used only by the standalone leaf builder.
Examples
>>> from solprop.grid import EnvelopeGrid >>> from solprop.nonlinear.responses import KerrResponse >>> from solprop.translate.responses import kerr_coefficients >>> grid = EnvelopeGrid.from_limits(1.0, 1030e-9, (700e-9, 2e-6), 2e-12) >>> coefficients = kerr_coefficients(KerrResponse(chi3=2e-28, thg=False), grid) >>> coefficients.cubic_form, coefficients.self_factor ('analytic', 0.5)
- density: PiecewiseChebyshev | None = None#
- type solprop.translate.responses.KerrForm = Literal['analytic', 'real']#
Which cubic a general modal guide’s instantaneous response is.
"analytic"isP = eps0 chi3 (2 |E|^2 E + (E.E) E*) / 4on the analytic signal, which carries the fundamental band alone;"real"isP = eps0 chi3 (E.E) Eon the real three-component field, which is the field route’s own model and carries the third harmonic with it. The two agree on the fundamental.
- solprop.translate.responses.MODEL_ID_SEPARATOR: Final[str] = '+'#
What joins the model tags of one compiled record’s
model_id.The identity is a
+-joined list whose first tag is the instantaneous form (KERR_FORM_MODEL_IDS) and whose remaining tags name the delayed models, in compilation order. A backend reads the form back from the first tag and refuses an identity it does not know rather than executing it as one it does.
- class solprop.translate.responses.PlasmaChannel(charge_mass_ratio, ionisation_potential, preionisation, rate, label, density, electrons_per_event=1.0)[source]#
Bases:
PlasmaCoefficientsBind an independent exposure scan to a labelled population.
- Attributes:
- charge_mass_ratiofloat
Free-current coefficient in C²/kg, positive.
- ionisation_potentialfloat
Energy paid per event in J, positive.
- preionisationsolprop.translate.chebyshev.PiecewiseChebyshev
Initial ionised fraction along z, dimensionless in [0, 1].
- ratesolprop.translate.ionisation.RateTable
Rate in s^-1 against field amplitude in V/m.
- labelstr
Unique component label in the compiled species order.
- densitysolprop.translate.chebyshev.PiecewiseChebyshev
Population number density in m^-3 along z.
- electrons_per_eventfloat
Electrons released per ionisation event; exactly 1 in schema 6.
- density: PiecewiseChebyshev#
- class solprop.translate.responses.PlasmaCoefficients(charge_mass_ratio, ionisation_potential, preionisation, rate)[source]#
Bases:
objectThe plasma response, reduced to two constants, a path and a table.
Section 5 of the kernel contract. The reference implementation is
solprop.nonlinear.responses.PlasmaResponse.evaluate(), and these are the only numbers it needs beyond the field and the density: the free-electron current is(e^2/m_e) int f E dtand the ionisation loss isI_p W (1 - f) E / |E|^2, withf = 1 - (1 - f_0) exp(-int W dt)– the pre-ionised fraction enters inside the exponential, so the ionised fraction never exceeds one.preionisationis a path along z because the response declares it as one, even where the value the user gave is a plain number: a backend reads one value per plane with a Clenshaw pass and never sees asolprop.profiles.ZProfile. Equality is by identity (eq=False), as it is for every group of the contract that holds arrays.- Attributes:
- charge_mass_ratiofloat
e^2 / m_ein C^2/kg, positive: the constant of the free-electron current. Carried rather than assumed so that a backend contains no physical constant.- ionisation_potentialfloat
Ionisation potential of the species in J, positive. It is what fixes the size of the loss current, whose work against the field is exactly one potential per electron freed.
- preionisationsolprop.translate.chebyshev.PiecewiseChebyshev
The fraction already ionised before the pulse, as a scalar table along z, with values in
[0, 1].- ratesolprop.translate.ionisation.RateTable
The ionisation rate in s^-1 against field amplitude in V/m, the same object
CompiledResponses.ionisation_tablecarries. It is exactly zero below itsfield_min, which is what makes the loss current’s division by the field finite.
- Raises:
- TranslationError
If either constant is not positive and finite.
Examples
>>> from solprop.nonlinear.optmat_rates import OptmatRate >>> from solprop.nonlinear.responses import PlasmaResponse >>> from solprop.translate.responses import plasma_coefficients >>> response = PlasmaResponse("Ar", OptmatRate("Ar", 800e-9), preionisation=0.25) >>> compiled = plasma_coefficients(response, (1e9, 1e11), z_max=1.0) >>> float(compiled.preionisation(0.5)), compiled.rate.field_min > 0.0 (0.25, True)
- preionisation: PiecewiseChebyshev#
- class solprop.translate.responses.RamanCoefficients(undamped, decay_rates, fraction, thg, tensor_weights, tensor_capable, label='medium', density=None)[source]#
Bases:
objectThe delayed response of a Raman-active medium, as a fused pass needs it.
A leaf of section 5 of the kernel contract, like
PlasmaCoefficients, so its fields are not rows of that document. It replaces the three separate rows of contract version 2 and carries the drive form, which they had nowhere to put: which real quadratic form drives the coherence on a field grid –E^2, or the cycle-averaged|E_a|^2/2– is a property of the problem, and the translation layer checks that the declared Kerr and Raman responses agree about it.- Attributes:
- undampednumpy.ndarray
Each independently damped term’s undamped response, float64, shape
(n_terms, n_to_doubled): causal fromt = 0, tapered by the grid’s temporal collar and zero-padded to the doubled grid (solprop.translate.raman.undamped_kernels()).n_termsis 1 for a glass or a vibration-only gas and 2 for a gas with a rotation and a vibration. The rows arehitself and carry noeps0; the response writes it outside the convolution integral (docs/guide/media/raman-numerics.md).- decay_ratestuple of solprop.translate.chebyshev.PiecewiseChebyshev
The decay rate
1 / tau_2of each term along z as a scalar table, one per row of undamped, composed from the term’s dephasing and the density path (solprop.translate.raman.decay_rate_profiles()). Finite everywhere.- fractionfloat
f_Rmultiplying the summed kernel, in(0, 1]; 1 for an absolute molecular response.- thgbool
Whether a field grid’s drive keeps the
2 omegabeat and so radiates a third harmonic through the later multiplication by the field. Ignored on an envelope grid, whose drive is|A|^2/2whatever this says, because a quadratic drive cannot carry the beat there.- tensor_weightsnumpy.ndarray
Read-only float64 weights, shape
(n_terms, 2), multiplying the trace and traceless effective kernels. Isotropic rows are(1, 0)and rank-two rows(1/4, 3/4). Scalar-only rows use(1, 0)but do not establish vector capability. Every row keeps its own decay rate.- tensor_capablebool
Whether every declared term has an established vector contraction.
- labelstr
Stable component label; the standalone leaf builder uses “medium”.
- densityPiecewiseChebyshev or None
Component amplitude density in m^-3, distinct from the total density used for linewidths. None is used only by the standalone leaf builder.
- Raises:
- TranslationError
If the kernel is not two-dimensional, the number of decay-rate tables does not match its rows, or the fraction is outside
(0, 1].
Examples
>>> import numpy as np >>> from solprop.profiles import Constant >>> from solprop.translate.linop import profile_table >>> from solprop.translate.responses import RamanCoefficients >>> rates = (profile_table(Constant(1e12), 0.0, 1.0),) >>> leaf = RamanCoefficients( ... np.zeros((1, 8)), rates, 0.18, thg=False, ... tensor_weights=np.array([[1.0, 0.0]]), tensor_capable=False, ... ) >>> leaf.n_terms, leaf.thg (1, False)
- decay_rates: tuple[PiecewiseChebyshev, ...]#
- density: PiecewiseChebyshev | None = None#
- property n_terms: int[source]#
Return the number of independently damped terms.
- Returns:
- int
The number of kernel rows, which is also the number of decay-rate tables.
- tensor_weights: Float[ndarray, 'n_tensor_terms 2']#
- undamped: Float[ndarray, 'n_terms n_to_doubled']#
- class solprop.translate.responses.RegionalResponseTables(response_region, chi3, instantaneous_tensor, delayed_tensor, delayed_kernel, kernel_valid_samples, temporal_weight, model_id, policy_id)[source]#
Bases:
DisplayedSay which material responds at each node, and with what tensor and kernel.
The optional leaf of contract section 5 that a general modal guide carries: the numeric arrays of a general response oracle, assigned to the node regions of
solprop.translate.modal_tables.ModalTransformTables. The existing gas and glass response owners remain the source of every law; this record is the compiled form of those laws and not a second physics.The delayed term is the silica tensor Raman model:
n_termsis zero for a region that declares the instantaneous cubic alone and two – the trace and traceless rank-two channels – for one that declares asolprop.nonlinear.raman.SilicaTensorResponsebeside it. Region indices are node region indices and are never species or plasma channel indices.- Attributes:
- response_regionnumpy.ndarray
Non-negative int32 region index per response, shape
(n_responses,). Each entry selects the material region ofModalTransformTables.region_indexthe response acts in.- chi3numpy.ndarray
Third-order susceptibility in m^2/V^2, shape
(n_intervals, n_deg, n_responses), as Chebyshev coefficients along z so that a declared density path enters exactly once.- instantaneous_tensornumpy.ndarray
Dimensionless rank-four instantaneous tensor, shape
(n_responses, n_components, n_components, n_components, n_components)with one, two or three Cartesian components.- delayed_tensornumpy.ndarray
The same for each delayed term, shape
(n_responses, n_terms, n_components, n_components, n_components, n_components), contracted asP_i = eps0 chi3 D_ijkl E_j H_klwithHthe convolved pair history, so it is symmetric in its last two indices; the term axis is empty for a purely instantaneous response.- delayed_kernelnumpy.ndarray
Causal response kernels in 1/s on the doubled fine time axis, shape
(n_intervals, n_deg, n_responses, n_terms, 2 * n_to): the causal half carries the kernel and the second half is the zero padding that makes a transform product the linear convolution. The Raman fraction is already in them, so a record multiplies bychi3alone.- kernel_valid_samplesnumpy.ndarray
Int32 count of kernel samples inside each term’s support, shape
(n_responses, n_terms): the length of the causal half, beyond which the stored kernel is the zero padding and not the response.- temporal_weightnumpy.ndarray
Non-negative quadrature weight in s per fine time sample, shape
(n_to,).- model_id, policy_idstr
Non-empty physical-model and numeric-policy identities. Scalar identities, never arrays, enter resume identity.
- Raises:
- TranslationError
Naming the field that failed.
Examples
>>> import numpy as np >>> from solprop.translate.responses import RegionalResponseTables >>> tables = RegionalResponseTables( ... np.zeros(1, dtype=np.int32), np.full((1, 1, 1), 2.2e-52), ... np.ones((1, 3, 3, 3, 3)), np.zeros((1, 0, 3, 3, 3, 3)), ... np.zeros((1, 1, 1, 0, 16)), np.zeros((1, 0), dtype=np.int32), ... np.full(8, 1e-15), "isotropic-kerr", "dense-nodes", ... ) >>> tables.n_responses, tables.n_components, tables.n_terms (1, 3, 0)
- chi3: Float[ndarray, 'n_intervals_chi3 n_deg_chi3 n_responses_chi3']#
- delayed_kernel: Float[ndarray, 'n_intervals_kernel n_deg_kernel n_responses_kernel n_terms_kernel n_to_doubled_kernel']#
- delayed_tensor: Float[ndarray, 'n_responses_delayed n_terms_delayed n_components_delayed_i n_components_delayed_j n_components_delayed_k n_components_delayed_l']#
- instantaneous_tensor: Float[ndarray, 'n_responses_instant n_components_instant_i n_components_instant_j n_components_instant_k n_components_instant_l']#
- kernel_valid_samples: Int32[ndarray, 'n_responses_support n_terms_support']#
- property n_components: int[source]#
Return how many Cartesian components each tensor contracts over.
- Returns:
- int
At least one and at most
solprop.translate.problem.MAX_N_COMPONENTS.
- property n_responses: int[source]#
Return how many responses the record assigns.
- Returns:
- int
The length of
response_region.
- property n_terms: int[source]#
Return how many delayed terms each response carries.
- Returns:
- int
Zero for a purely instantaneous response, two for the silica tensor Raman model’s trace and rank-two channels.
- response_region: Int32[ndarray, 'n_responses_region']#
- temporal_weight: Float[ndarray, 'n_to_temporal_weight']#
- class solprop.translate.responses.ResponseStage(*values)[source]#
Bases:
StrEnumOne step of the fused time-domain traversal, in execution order.
The translation layer compiles the declared set of responses into a single pass per column rather than into one pass per response. The names are the passes of
docs/dev/architecture.mdsection 8; a backend specialises on the sequence at compile time.- Attributes:
- INTENSITYstr
Form
|E|^2(or|A|^2) once, for everything that needs it.- IONISATION_RATEstr
Look the ionisation rate up in its spline table.
- PLASMA_SCANstr
Integrate the electron density along t; sequential, three running sums.
- PLASMA_CURRENTstr
The plasma current and loss terms.
- KERRstr
The instantaneous third-order polarisation.
- DISPERSIVE_KERRstr
SEP 6’s frequency-dependent electronic polarisation: filtered fields, their products and the output multipliers on the fine grid.
- RAMAN_DRIVEstr
Write the driving term of the Raman convolution.
- ACCUMULATEstr
Sum the contributions into
P(t)and apply the temporal window.- ENVELOPE_CYCLEstr
Form the averaged rate and both directional moments.
- ENVELOPE_POPULATIONstr
Scan cycle-averaged exposure and retain surviving neutrals.
- ENVELOPE_SOURCESstr
Form separate Drude drive and loss-current streams before projection.
Examples
>>> from solprop.translate.responses import ResponseStage >>> ResponseStage.KERR, str(ResponseStage.ACCUMULATE) (<ResponseStage.KERR: 'kerr'>, 'accumulate')
- ACCUMULATE = 'accumulate'#
- DISPERSIVE_KERR = 'dispersive_kerr'#
- ENVELOPE_CYCLE = 'envelope_cycle'#
- ENVELOPE_POPULATION = 'envelope_population'#
- ENVELOPE_SOURCES = 'envelope_sources'#
- INTENSITY = 'intensity'#
- IONISATION_RATE = 'ionisation_rate'#
- KERR = 'kerr'#
- PLASMA_CURRENT = 'plasma_current'#
- PLASMA_SCAN = 'plasma_scan'#
- RAMAN_DRIVE = 'raman_drive'#
- solprop.translate.responses.THG_OVERSAMPLING = 6.0#
Least oversampling a third-harmonic term needs, so that
3 omega_maxis resolved.conventions.mdsection 3: a cubic response reaching3 omega_maxneedsffac = 6, and4suffices without the harmonic. A grid built withthg=Falsehasffac = 2on an envelope grid, so a harmonic term on it would alias silently.
- solprop.translate.responses.compile_responses(responses, grid, mode, *, density, z_max, n_pol=1, mode_averaged=True, shock=True, prefactor_index=None, ionisation_field_range=None, absorber=None, absorber_scheme='nonlinear', mandatory_edges=(), margin=0.05, tol=1e-12, n_max=64, max_intervals=512, representation='auto', translated_prefactor=None, mixture=None, regional_responses=None, regional_dispersive=None, reuse_prefactor=None, reuse_raman=None)[source]#
Compile a set of responses into the nonlinear term a kernel executes.
The instantaneous Kerr response, the delayed Raman response and the plasma response are compiled. A response of any other kind raises rather than being silently dropped, because a problem that reaches a backend missing a term it declared would run, converge and be wrong.
A plasma response carries its own ionisation rate, so it supplies the run’s ionisation_table; without one there is no rate table.
A Raman response fills the three rows of section 5 from
solprop.translate.raman.build_raman_kernels()andsolprop.translate.raman.decay_rate_profiles(), and addsraman_driveto response_order afterkerr. It is refused on a two-component problem, which would need a tensor kernel no backend can consume, and on a field grid it is refused without a Kerr response beside it, or beside one that disagrees aboutthg: the drive form is a property of the problem and reaches a backend through the Kerr row.- Parameters:
- responsessequence
The declared responses: at most one
solprop.nonlinear.responses.KerrResponse, at most onesolprop.nonlinear.raman.RamanResponseand at most onesolprop.nonlinear.responses.PlasmaResponse, each defined on this grid.- gridsolprop.grid.TimeGrid
The grid; decides the cubic form and supplies the crop scale.
- modeMode or sequence of Mode
The mode, or the ordered set of a multimode problem, whose effective index and effective area enter the prefactor.
- densitysolprop.profiles.ZProfile or float
Number density along z in m^-3, or 1.0 for a medium whose
chi3is absolute.- z_maxfloat
Length the run covers, m, positive and finite.
- n_polint, optional
Polarisation components, 1 or 2.
- mode_averagedbool, optional
Whether to use the mode-averaged prefactor, which folds in the effective-area conversion. Default
True.- shockbool, optional
Keep the
omegadependence of the prefactor’s numerator, which is the optical shock term. DefaultTrue.- prefactor_indexfloat or None, optional
Replace the effective index in the prefactor by this constant. The GNLSE passes 1.0.
- ionisation_field_rangetuple of float or None, optional
Lower and upper field amplitude in V/m a plasma response’s rate table must cover; refused without a plasma response. Refused when the rate handed over is already a
solprop.translate.ionisation.RateTable, which states its own span.- absorbersolprop.boundaries.Absorber or None, optional
The collar rates; only its temporal part is used here, the spectral part being already inside the linear operator.
- absorber_scheme{‘split_step’, ‘nonlinear’}, optional
Which application of the temporal rate the backend will use.
- mandatory_edgesarray_like, optional
Positions in z that must be interval edges of the prefactor table.
solprop.translate.problem.assemble()passes the cumulative operator’shard_kinks, which is the union of the mode set’s declared breakpoints, so that the two tables split on the same edges; a standalone caller should do the same, because a table left to locate a kink by bisection spends intervals on it and is less accurate there.- marginfloat, optional
Fraction of z_max the density and prefactor tables extend beyond the end.
- tolfloat, optional
Target bound on the uniform error of the tables.
- n_maxint, optional
Highest Chebyshev degree tried on an interval of the prefactor table before it is bisected.
- max_intervalsint, optional
Interval budget of the prefactor’s tables; exceeding it warns.
- representation{‘auto’, ‘expansion’, ‘table’}, optional
Which representation to build for the prefactor, as
solprop.translate.linop.build_phi()takes forPhi, and chosen the same way. A z-constant mode set takes the constant fast path whatever this says.- translated_prefactorobject, optional
An already translated normalisation the caller owns, including the temporal crop scaling: spatial geometry’s, or the general modal route’s constant crop scale, whose
-i omegalives in its own record instead. A PiecewiseChebyshev, ParameterExpansion or SeparableOperator record. Requiresmode=Noneandmode_averaged=False. The material responses still use the same compiler and validation as modal propagation.- mixtureMixture or None, optional
Explicit species and component paths for a spatial material. Modal assembly also discovers the mixture carried by its modes. None keeps the legacy path.
- regional_responsesRegionalResponseTables or None, optional
The compiled per-region response of a general modal guide, carried through to contract section 5’s optional leaf unchanged. It is not compiled here: the general route’s responses belong to the guide’s material regions and are built by
regional_responses().- regional_dispersiveDispersiveKerrTerms or None, optional
The compiled dispersive channels of a general modal guide’s gas regions (SEP 6), carried through to
dispersive_kerrunchanged, beside regional_responses; they are not compiled here either.- reuse_prefactorParameterExpansion or None, optional
Coefficients of the unchanged prefactor function on the same grid and fixed parameters; range checks decide whether its terms may be shared.
- reuse_ramanMapping or None, optional
Labelled undamped rows for unchanged Raman models and time grid. Densities and decay-rate tables are rebuilt.
- Returns:
- CompiledResponses
Section 5 of the kernel contract.
- Raises:
- TranslationError
If a response cannot be compiled, more than one response of a kind is given, a Raman response arrives on a problem this layer cannot compile it for, a field range arrives without a plasma response, or an argument is out of range.
Examples
>>> import numpy as np >>> from solprop.grid import EnvelopeGrid >>> from solprop.nonlinear.gnlse import problem_from >>> from solprop.translate.responses import compile_responses >>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (500e-9, 2e-6), 4e-12) >>> problem = problem_from([0.0, 0.0, -1e-26], omega_ref=grid.omega0, gamma=0.1, ... shock=False) >>> compiled = compile_responses([problem.kerr], grid, problem.mode, density=1.0, ... z_max=1.0, shock=False, prefactor_index=1.0) >>> compiled.prefactor.value_shape, compiled.prefactor_constant.shape ((1, 1, 4096), (1, 1, 4096)) >>> bool(np.all(compiled.prefactor_constant[0, 0][~grid.active_mask] == 0.0)) True
- solprop.translate.responses.dispersive_regions(responses, grid, *, vector)[source]#
Classify a run’s active band for each dispersive response it declares.
SEP 6, section 4.10: the active band,
omega_min / 2to1.1 omega_max, holds every output the grid can carry, and each part of it is supported, bounded or best effort for each gas. A run is never refused for the frequencies its field occupies; one whose band leaves a gas’s support is logged once, at INFO, naming the gas and the band.- Parameters:
- responsessequence of object
The run’s declared responses; the dispersive ones are classified.
- gridsolprop.grid.TimeGrid
The run’s grid.
- vectorbool
Whether the field at a node has two polarisation components, which takes the any-polarisation band edge.
- Returns:
- tuple of solprop.physdata.nonlinear_data.ElectronicRegions
One per dispersive response, in declaration order.
- solprop.translate.responses.dispersive_terms(responses, labels, densities, grid, *, regions=None)[source]#
Sample the dispersive responses’ multipliers on a grid’s fine layout.
- Parameters:
- responsessequence of DispersiveKerrResponse
The declared responses, one per channel, agreeing on evaluator and
thg.- labelssequence of str
Each response’s population label.
- densitiessequence of PiecewiseChebyshev
Each population’s number density table, m^-3.
- gridsolprop.grid.TimeGrid
The grid, whose
omega_finegives the absolute frequency of every bin.- regionssequence of int or numpy.ndarray or None, optional
On the general modal route, the node region of each channel;
Noneelsewhere.
- Returns:
- DispersiveKerrTerms
The compiled leaf.
- Raises:
- TranslationError
If the responses disagree on evaluator or
thg, or the full cubic is asked for on an envelope grid that does not oversample enough to hold it.
- solprop.translate.responses.instantaneous_model_id(form, *, delayed)[source]#
Return the
model_ida compiled regional record carries.- Parameters:
- form{‘analytic’, ‘real’}
The instantaneous cubic’s form.
- delayedbool
Whether the record carries the silica tensor Raman term.
- Returns:
- str
For example
isotropic-kerr-real+silica-tensor-raman.
- Raises:
- TranslationError
If the form is not one this package compiles, named rather than surfacing as a bare lookup failure – the same refusal
isotropic_kerr_tensor()makes.
Examples
>>> from solprop.translate.responses import instantaneous_model_id >>> instantaneous_model_id("real", delayed=True) 'isotropic-kerr-real+silica-tensor-raman'
- solprop.translate.responses.isotropic_kerr_tensor(form='analytic')[source]#
Return the dimensionless rank-four tensor of an isotropic Kerr medium.
The instantaneous third-order polarisation of an isotropic medium in the analytic-signal convention is
P_i = eps0 chi3 (2 |E|^2 E_i + (E.E) conj(E_i)) / 4(
docs/guide/media/nonlinear.md), and writing it as the general contractionP_i = eps0 chi3 T_ijkl E_j E_k conj(E_l)thatRegionalResponseTablescarries gives Kleinman-symmetricT_ijkl = (d_ij d_kl + d_ik d_jl + d_il d_jk) / 4,whose three terms contribute
E_i (E.E*),E_i (E.E*)andconj(E_i) (E.E)respectively. The conjugated field is the last index, which is the index convention of the record and of the reference pass that reads it.On the real three-component field the same contraction is the real cubic
P = eps0 T:EEEthe legacy field route evaluates, whose scalar limit isP = eps0 chi3 E^3. Each of the three delta terms then contributesE_i (E.E), so the normalisation is a third and not a quarter:T_ijkl = (d_ij d_kl + d_ik d_jl + d_il d_jk) / 3.The two are one model in two representations. For a narrowband real field
E = Re(A e^(-i w t))the real cubic’s fundamental component has analytic signal3 eps0 chi3 |A|^2 A / 4, which is exactly what the analytic form returns; the real cubic carries the third harmonic beside it and the analytic form does not.- Parameters:
- form{‘analytic’, ‘real’}, optional
Which field the tensor is contracted against: the analytic signal, the default, or the real three-component field.
- Returns:
- numpy.ndarray
The tensor, shape
(3, 3, 3, 3), dimensionless.
- Raises:
- TranslationError
If form is neither.
Examples
>>> import numpy as np >>> from solprop.translate.responses import isotropic_kerr_tensor >>> field = np.array([0.3 + 0.2j, -0.1 + 0.4j, 0.05 - 0.15j]) >>> direct = (2 * np.vdot(field, field).real * field ... + (field @ field) * field.conj()) / 4 >>> contracted = np.einsum("ijkl,j,k,l->i", isotropic_kerr_tensor(), ... field, field, field.conj()) >>> bool(np.allclose(contracted, direct)) True >>> real = np.array([0.3, -0.1, 0.05]) >>> cubic = np.einsum("ijkl,j,k,l->i", isotropic_kerr_tensor("real"), ... real, real, real) >>> bool(np.allclose(cubic, (real @ real) * real)) True
- solprop.translate.responses.kerr_coefficients(response, grid)[source]#
Reduce a Kerr response on a grid to the numbers a fused pass needs.
- Parameters:
- responsesolprop.nonlinear.responses.KerrResponse
The response; its
chi3is per unit of the density path.- gridsolprop.grid.TimeGrid
The grid, which decides the cubic form and whether a harmonic term is resolved.
- Returns:
- KerrCoefficients
The compiled coefficients.
- Raises:
- TranslationError
If a third-harmonic term is asked for on an envelope grid that does not oversample enough to resolve it, where it would alias into the fundamental without any sign that it had.
Examples
>>> from solprop.constants import EPS0 >>> from solprop.grid import FieldGrid >>> from solprop.nonlinear.responses import KerrResponse >>> from solprop.translate.responses import kerr_coefficients >>> grid = FieldGrid.from_limits(1.0, 800e-9, (200e-9, 4e-6), 200e-15) >>> compiled = kerr_coefficients(KerrResponse(chi3=1.0), grid) >>> compiled.cubic_form, compiled.coefficient == EPS0, compiled.take_real ('real', True, True)
- solprop.translate.responses.plasma_coefficients(response, field_range, *, z_max, margin=0.05, tol=1e-12)[source]#
Reduce a plasma response to the coefficients a fused pass needs.
The response’s own rate is what the run uses. A
solprop.translate.ionisation.RateTablehanded to the response is taken as it stands, because it is already the compiled form; anything else is tabulated over field_range, which the caller must state – a table cannot choose its own span.- Parameters:
- responsesolprop.nonlinear.responses.PlasmaResponse
The declared response.
- field_rangetuple of float or None
Lower and upper field amplitude in V/m the rate table must cover. Ignored, and refused, when the response already carries a table.
- z_maxfloat
Length the run covers, m. The pre-ionisation table spans
[0, z_max (1 + margin)], the same range asPhi.- marginfloat, optional
Fraction of z_max the table extends beyond the end.
- tolfloat, optional
Target bound on the uniform error of the pre-ionisation table.
- Returns:
- PlasmaCoefficients
The compiled coefficients.
- Raises:
- TranslationError
If a rate that is not already a table is given without a field range, or a field range is given beside a table that does not need one.
Examples
>>> from solprop.nonlinear.optmat_rates import OptmatRate >>> from solprop.nonlinear.responses import PlasmaResponse >>> from solprop.translate.responses import plasma_coefficients >>> compiled = plasma_coefficients( ... PlasmaResponse("Ar", OptmatRate("Ar", 800e-9)), (1e9, 1e11), z_max=1.0 ... ) >>> f"{compiled.ionisation_potential:.4e}" '2.5250e-18'
- solprop.translate.responses.prefactor_at(responses, z, *, helpers=None)[source]#
Return the prefactor at one position, taking the fast path when there is one.
The one way a backend evaluates the prefactor, as
solprop.translate.linop.delta_phi()is the one way it evaluates the linear flow: the array ofprefactor_constantwhen the mode set does not vary, and one Clenshaw pass over the table otherwise. Going through this function rather than reading the table’s arrays keeps the representation the translation layer’s business, which is what lets it change without touching a backend.- Parameters:
- responsesCompiledResponses
Section 5 of the kernel contract.
- zfloat
Position along the waveguide, m, inside the table’s span.
- helperssolprop._helpers.Helpers or None, optional
The evaluating backend’s Chebyshev helpers, for a z table read during a run;
None, the default, takes the shared translation-time evaluation.
- Returns:
- numpy.ndarray
The prefactor times the crop scale, complex128, shape
(n_modes, n_pol, n_omega); the stored array itself on the fast path.
- Raises:
- TranslationError
If z lies outside the table.
Examples
>>> from solprop.grid import EnvelopeGrid >>> from solprop.nonlinear.gnlse import problem_from >>> from solprop.translate.responses import compile_responses, prefactor_at >>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (500e-9, 2e-6), 4e-12) >>> problem = problem_from([0.0, 0.0, -1e-26], omega_ref=grid.omega0, gamma=0.1, ... shock=False) >>> compiled = compile_responses([problem.kerr], grid, problem.mode, density=1.0, ... z_max=1.0, shock=False, prefactor_index=1.0) >>> prefactor_at(compiled, 0.5) is compiled.prefactor_constant True
- solprop.translate.responses.raman_coefficients(raman, kerr, grid, density, *, n_pol, span, tol, undamped=None)[source]#
Compile a Raman response into the leaf of section 5, or
None.The expensive half of the kernel is sampled once per grid and the cheap half becomes one scalar table along z per term, so that what crosses the seam is arrays and paths and no physics object (
docs/guide/media/raman-numerics.md, “Sampling the kernel”).The fraction is
solprop.nonlinear.raman.RamanResponse.scaleand notfractionitself, so that an absolute molecular response carries the 1 the contract’s row promises rather than aNonethe other two rows would then have to match.- Parameters:
- ramansolprop.nonlinear.raman.RamanResponse or None
The declared response.
- kerrKerrResponse or DispersiveKerrResponse or None
The electronic response declared beside it, constant or dispersive, which fixes the field grid’s drive form.
- gridsolprop.grid.TimeGrid
The grid supplying the fine time axis and the temporal collar.
- densitysolprop.profiles.ZProfile
The number density along z, which the decay rates are composed with.
- n_polint
Polarisation components of the state.
- spanfloat
End of the tabulated range, m: the same
z_max (1 + margin)asPhi.- tolfloat
Target bound on the uniform error of the decay-rate tables.
- undampednumpy.ndarray or None, optional
Undamped kernel rows to share for an identical model and fine time grid.
- Returns:
- RamanCoefficients or None
The compiled coefficients, or
Nonewhen no Raman response was declared.
- Raises:
- TranslationError
If two physical components request a scalar-only declaration, or a field grid has no compatible Kerr response to establish the drive form.
Examples
>>> from solprop.grid import EnvelopeGrid >>> from solprop.nonlinear.raman import response_for >>> from solprop.profiles import Constant >>> from solprop.translate.responses import raman_coefficients >>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (500e-9, 2e-6), 4e-12) >>> response = response_for("SiO2", amplitude=1e-22, fraction=0.18, thg=False) >>> leaf = raman_coefficients( ... response, None, grid, Constant(1.0), n_pol=1, span=1.0, tol=1e-12 ... ) >>> leaf.n_terms, leaf.thg (1, False)
- solprop.translate.responses.regional_responses(chi3, regions, *, raman=None, n_to, dt_fine, form='analytic', policy_id='dense-nodes')[source]#
Compile one material region’s declared responses into the seam’s leaf.
An absolute
chi3per responding region, the isotropic instantaneous tensor ofisotropic_kerr_tensor()in the declared form, and – for a region that declares one – the two delayed channels ofsolprop.nonlinear.raman.SilicaTensorResponse. A node whose region names no response has no polarisation, which is how a linear cladding is declared.One susceptibility, shared. Where a delayed response is declared, the instantaneous tensor is scaled by its
1 - f_Rand the delayed kernels carry(3/2) f_R(solprop.nonlinear.raman.SILICA_TENSOR_AMPLITUDE), so the record multiplies bychi3once and the two shares add to onechi3on the fundamental band: a field-domain delayed kernel of integralXacts there like a Kerr term of(2/3) X, because its drive is the cycle average, so(2/3)(3/2) f_R + (1 - f_R) = 1. Every response of one record carries the same number of delayed terms, because the leaf’s term axis is shared; a region with no delayed response gets zero kernels on that axis, which contribute nothing.chi3is stored as one Chebyshev coefficient on one interval, because a declared material is constant along a constant guide; a z-varying susceptibility needs the density path of the legacy compiler and is not compiled here.- Parameters:
- chi3sequence of float
Absolute third-order susceptibility of each response, m²/V², finite.
- regionssequence of int
The node region each response acts in, non-negative, one per
chi3.- ramansequence or None, optional
The delayed response each region declares, or
Nonein that slot for a region with none;Nonefor the whole sequence means no region declares one. One entry perchi3.- n_toint
Fine time samples of the run’s grid, positive.
- dt_finefloat
Fine sample spacing in s, positive; the temporal quadrature weight.
- form{‘analytic’, ‘real’}, optional
Which cubic the instantaneous tensor is: the analytic-signal one, the default, which carries the fundamental band alone, or the real cubic of the field route, which carries the third harmonic. It fixes both the tensor and the first tag of the
model_ida backend reads the form back from (KERR_FORM_MODEL_IDS).- policy_idstr, optional
Numeric-policy identity recorded on the leaf.
- Returns:
- RegionalResponseTables
The validated leaf of contract section 5.
- Raises:
- TranslationError
If the sequences disagree in length, or the record does not validate.
Examples
>>> from solprop.nonlinear.raman import SilicaTensorResponse >>> from solprop.translate.responses import regional_responses >>> tables = regional_responses([2.2e-22], [0], n_to=16, dt_fine=1e-16) >>> tables.n_responses, tables.n_components, tables.n_terms (1, 3, 0) >>> tables.model_id 'isotropic-kerr' >>> delayed = regional_responses( ... [2.2e-22], [0], raman=[SilicaTensorResponse()], ... n_to=16, dt_fine=1e-16, form="real", ... ) >>> delayed.n_terms, delayed.model_id (2, 'isotropic-kerr-real+silica-tensor-raman')
- solprop.translate.responses.response_kinks(responses, density=None)[source]#
Return where the response paths kink, each with the name of its path.
A step lands only on the hard kinks of
Phi, which the mode set declares. A response can carry a path the modes know nothing about: a plasma response’s pre-ionisation along z, or a density path given tosolprop.translate.problem.assemble()explicitly. Its breakpoints are where the right-hand side is not smooth, so they must become hard kinks as well, or a step straddles them and the integrator loses its order there.- Parameters:
- responsessequence of object
The declared responses; the plasma responses’ pre-ionisation paths are read.
- densityZProfile, float or None, optional
An explicit density path in m^-3, when one replaces the modes’ own.
- Returns:
- tuple of tuple
(z, name)pairs, z in m, in declaration order; a number, or a path whoseis_constantis true, declares none.
Examples
>>> import numpy as np >>> from solprop.nonlinear.optmat_rates import OptmatRate >>> from solprop.nonlinear.responses import PlasmaResponse >>> from solprop.profiles import PiecewiseLinear >>> from solprop.translate.responses import response_kinks >>> path = PiecewiseLinear(np.array([0.0, 0.4, 1.0]), np.array([0.0, 0.1, 0.1])) >>> rate = OptmatRate("Ar", 800e-9) >>> response_kinks([PlasmaResponse("Ar", rate, preionisation=path)]) ((0.0, 'preionisation'), (0.4, 'preionisation'), (1.0, 'preionisation'))
- solprop.translate.responses.unlanded_kinks(kinks, hard_kinks, z_max, *, slack)[source]#
Return the response kinks inside the run that no step is made to land on.
- Parameters:
- kinkssequence of tuple
(z, name)pairs fromresponse_kinks(), z in m.- hard_kinksnumpy.ndarray
The linear operator’s hard kinks in m, shape
(n_kinks,).- z_maxfloat
End of the run in m; a kink at or beyond it, or at or before the entrance, needs no landing.
- slackfloat
Distance in m within which a hard kink counts as the same position.
- Returns:
- tuple of tuple
The
(z, name)pairs strictly inside(0, z_max)with no hard kink within slack; empty when every one is landed on.
Examples
>>> import numpy as np >>> from solprop.translate.responses import unlanded_kinks >>> kinks = ((0.4, "preionisation"), (0.7, "preionisation")) >>> unlanded_kinks(kinks, np.array([0.4]), 1.0, slack=1e-12) ((0.7, 'preionisation'),)