solprop.translate.problem#

The kernel contract: the one object that crosses into a backend.

KernelProblem is a frozen dataclass of plain NumPy arrays and scalars, validated, versioned and documented field by field in docs/dev/kernel-contract.md. A backend may assume everything stated there and nothing else; the translation layer promises everything stated there and nothing else. Changing that document and this module together is the only way to extend the contract, and tests/translate/test_problem.py parses the document’s tables and checks them against this dataclass tree in both directions, so the two cannot drift.

The sections of the contract are grouped into one frozen dataclass each: Flags (section 1), solprop.translate.masks.Grids (2), solprop.translate.linop.LinearOperator (3), solprop.translate.modal.Transform (4), solprop.translate.responses.CompiledResponses (5), Initial (6), StepperSettings (7) and solprop.stats.StatsSpec (8).

Sign convention. Every complex array here is in the FFT convention of docs/dev/conventions.md section 2 — raw forward DFTs, propagation exp(i(omega t - beta z)), linear operator -i beta. The user’s optics-convention inputs are converted by the pulse builders and the observations are converted back by the output layer; backends never conjugate.

Module Attributes

SCHEMA_VERSION

Version of the kernel contract this module implements.

DEFAULT_COMPONENTS

Canonical component of an unrotated HE_1m mode.

MAX_N_POL

Most entries the state's polarisation axis may have.

MAX_N_COMPONENTS

Cartesian components of the local physical field a general modal guide resolves.

DEFAULT_STRETCH

Landing stretch factor (stepper.md section 3).

NoiseModel

Which shot-noise model the run carries (see docs/dev/decisions.md).

PropagatorMode

Whether the backend tabulates the stage propagators or recomputes them.

LOG_DBL_MAX

log(DBL_MAX), about 709.78: the largest exponent exp returns finite.

LOG_FLT_MAX

log(FLT_MAX), about 88.72: binary32's largest finite exp (SEP 33).

EXPONENT_BUDGET

Fraction of LOG_DBL_MAX above which translation warns of a step it cannot shrink: such a run completes only while its field stays below exp of the margin.

DEFAULT_FLOW_CONDITION_LIMIT

Largest inverse conditioning a general modal coupled flow is admitted at.

MOVING_FLOW_CERTIFICATE

The certificate_id a moving solid guide's coupled flow carries.

TAPER_FLOW_CERTIFICATE

The certificate_id of a multimode capillary taper's coupling without a wall.

MAX_GENERAL_FLOW_EXPONENT

Largest dz_max max|G| a general modal coupled flow is executed at.

Functions

assemble(grid, modes, responses, field0, *, ...)

Turn the physics objects of a run into a validated kernel problem.

debug_summary(problem)

Return a short array-free description of an assembled problem, for a log.

dispersive_node_buffers(responses, *, spatial)

Return the buffers per node and component SEP 6's dispersive response adds.

validate_coupled_flow(problem)

Warn when a run's declared steps exceed its coupled flow's advisory limit.

Classes

Flags(single_mode, scalar_pol, single_batch, ...)

Static booleans a kernel specialises on at compile time.

Initial(field0, noise0, noise_model, ...[, z])

The initial state, the noise realisation and the batch parameters.

KernelProblem(schema_version, grid_kind, ...)

Everything a backend needs, and nothing it does not.

StepperSettings(tableau, controller, dz_min, ...)

The tableau, the controller and the schedule of a run.

TranslationReuse(transform, initial, ...)

Carry prequalified reusable data into a material-path update.

solprop.translate.problem.DEFAULT_COMPONENTS = ('x',)#

Canonical component of an unrotated HE_1m mode.

The component an HE_1m Marcatili mode points along at phi = 0 (see docs/dev/decisions.md). Assembly derives its actual default from the mode set’s principal_component traits, so a rotated or vector set is resolved correctly.

solprop.translate.problem.DEFAULT_FLOW_CONDITION_LIMIT: float = 10000.0#

Largest inverse conditioning a general modal coupled flow is admitted at.

Dimensionless, and the same number solprop.modes.capillary.CoherentWall.condition_limit defaults to, because it bounds the same thing: how far the interaction picture’s inverse action may amplify the nonlinear source over one step. A general guide’s block is far below it – a unitary rotation of a lossless split block has an exactly Hermitian-free part and reads 1.0 – so this is a guard and not a tuning knob, and there is no declaration object on this route to put it on.

solprop.translate.problem.DEFAULT_STRETCH = 1.1#

Landing stretch factor (stepper.md section 3).

It stays 1.1 whatever the growth cap: stretching a step by 2 to reach a plane could multiply an order-five defect by 32 (SEP 14 section 4.2).

solprop.translate.problem.EXPONENT_BUDGET = 0.9#

Fraction of LOG_DBL_MAX above which translation warns of a step it cannot shrink: such a run completes only while its field stays below exp of the margin.

class solprop.translate.problem.Flags(single_mode, scalar_pol, single_batch, has_plasma, has_raman, has_spectral_responses, has_noise, has_temporal_absorber, constant_linop, mode_averaged, n_channels=0, n_raman=0)[source]#

Bases: object

Static booleans a kernel specialises on at compile time.

Section 1 of the kernel contract. They are derived from the content of the problem by from_content() and never passed in, so a flag cannot disagree with the arrays it describes.

Attributes:
single_modebool

One mode: n_modes == 1.

scalar_polbool

One polarisation component: n_pol == 1.

single_batchbool

One batch member: n_batch == 1.

has_plasmabool

A plasma response is compiled.

has_ramanbool

A Raman kernel is compiled.

has_spectral_responsesbool

Responses are evaluated after the forward transform.

has_noisebool

A shot-noise realisation is carried and added at every stage.

has_temporal_absorberbool

A temporal collar rate is present.

constant_linopbool

The linear operator does not vary along z, so the propagator is exact and cheap.

mode_averagedbool

The single-node, effective-area case of the multimode pipeline.

n_channelsint

Number of independent labelled plasma populations, non-negative.

n_ramanint

Number of Raman-active components, non-negative; each may have several terms.

Examples

>>> from solprop.translate.problem import Flags
>>> flags = Flags(True, True, True, False, False, False, False, False, True, True)
>>> flags.constant_linop, flags.has_raman
(True, False)
constant_linop: bool#
classmethod from_content(shape, linear, transform, responses, initial)[source]#

Derive the flags from the problem’s own content.

Parameters:
shapetuple of int

The canonical state shape (n_batch, n_modes, n_pol, n_omega).

linearsolprop.translate.linop.LinearOperator

The cumulative operator.

transformsolprop.translate.modal.Transform

The modal transform.

responsessolprop.translate.responses.CompiledResponses

The compiled nonlinear term.

initialInitial

The initial state and noise.

Returns:
Flags

The derived flags.

Examples

>>> import numpy as np
>>> from solprop.grid import EnvelopeGrid
>>> from solprop.nonlinear.gnlse import problem_from
>>> from solprop.pulses import SechPulse
>>> from solprop.stepper import PIController
>>> from solprop.translate.problem import assemble
>>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (500e-9, 2e-6), 4e-12)
>>> gnlse = problem_from([0.0, 0.0, -1.2e-26], omega_ref=grid.omega0,
...                      gamma=0.11, shock=False)
>>> start = SechPulse(wavelength=835e-9, width=1e-13,
...                   peak_power=1.0).build(grid)
>>> problem = assemble(
...     grid, gnlse.mode, [gnlse.kerr], start,
...     controller=PIController(rtol=1e-8, atol=1e-14),
...     save_planes=[1.0], dz_max=0.1, dz_init=1e-3,
...     shock=False, prefactor_index=1.0, density=1.0,
... )
>>> problem.flags.mode_averaged, problem.flags.constant_linop
(True, True)
has_noise: bool#
has_plasma: bool#
has_raman: bool#
has_spectral_responses: bool#
has_temporal_absorber: bool#
mode_averaged: bool#
n_channels: int = 0#
n_raman: int = 0#
scalar_pol: bool#
single_batch: bool#
single_mode: bool#
class solprop.translate.problem.Initial(field0, noise0, noise_model, batch_params, z=0.0)[source]#

Bases: object

The initial state, the noise realisation and the batch parameters.

Section 6 of the kernel contract. Both arrays are in the lab frame and the FFT convention, read-only and C-contiguous.

Attributes:
field0numpy.ndarray

Initial state, complex128, shape (n_batch, n_modes, n_pol, n_omega), in the square root of watts.

noise0numpy.ndarray or None

The shot-noise realisation in the same layout, or None. It is carried along z by the unitary part of the linear flow and added at every stage; the propagating field never contains it.

noise_model{‘none’, ‘input’, ‘modified’}

Which model the realisation belongs to.

batch_paramsmapping

Per-member scalars recorded in the output, each a read-only (n_batch,) float64 array. Empty unless a batch runner filled it (work package 16). The annotation gives the length its own axis name so that __post_init__ is what checks it against the state, which keeps the check reachable in production.

zfloat, optional

Absolute launch position in m, finite and non-negative. Input power normalisation uses the effective index at this position.

Raises:
TranslationError

If the noise layout does not match the state, or the model and the realisation disagree.

Examples

>>> import numpy as np
>>> from solprop.translate.problem import Initial
>>> state = np.zeros((1, 1, 1, 8), dtype=complex)
>>> Initial(state, None, "none", {}).noise_model
'none'
batch_params: Mapping[str, Float[ndarray, 'n_params']]#
field0: Complex[ndarray, 'n_batch n_modes n_pol n_omega']#
noise0: Complex[ndarray, 'n_batch_n n_modes_n n_pol_n n_omega_n'] | None#
noise_model: Literal['none', 'input', 'modified']#
z: float = 0.0#
class solprop.translate.problem.KernelProblem(schema_version, grid_kind, shape, flags, grids, linear, transform, responses, initial, stepper, stats_spec, tdse=None, current_numerator=None, flux=None, precision=Precision(state='double', source='double'))[source]#

Bases: object

Everything a backend needs, and nothing it does not.

The seam of docs/dev/architecture.md section 3. Construct it with assemble() rather than by hand; call validate() before handing it to a backend, which assemble() already does.

Attributes:
schema_versionint

The contract version, SCHEMA_VERSION.

grid_kind{‘field’, ‘envelope’}

Selects r2c/c2r against c2c transforms and the response formulas.

shapetuple of int

The canonical state shape (n_batch, n_modes, n_pol, n_omega).

flagsFlags

Static booleans, derived from the content (section 1).

gridssolprop.translate.masks.Grids

Frequency axis, masks and oversampling data (section 2).

linearsolprop.translate.linop.LinearOperator

The cumulative linear operator (section 3).

transformsolprop.translate.modal.Transform

Synthesis and projection (section 4).

responsessolprop.translate.responses.CompiledResponses

The compiled nonlinear term (section 5).

initialInitial

Initial state, noise and batch parameters (section 6).

stepperStepperSettings

Tableau, controller, caps and schedule (section 7).

stats_specsolprop.stats.StatsSpec

Which statistics to collect (section 8).

tdsesolprop.translate.tdse.TDSEDescriptor or None, optional

Immutable atomic and response-lattice scientific identity. Execution plans remain owned by the driver and cross the seam as an explicit binding.

current_numeratornumpy.ndarray or None, optional

Independent current source numerator, -crop_scale/(2 epsilon_0 c), shape (n_modes, n_pol, n_omega). Zero outside the retained band. Divide by the stage’s real effective index without dividing by frequency.

fluxsolprop.translate.spatial.FluxPlan or None, optional

A spatial run’s plane-measure coefficients (version 35); required with spatial geometry and absent otherwise.

precisionsolprop.translate.precision.Precision, optional

The arithmetic the run is held in (version 36): binary64 by default, or binary32 under SEP 33’s contract. Tables are binary64 here either way.

Examples

>>> from solprop.grid import EnvelopeGrid
>>> from solprop.nonlinear.gnlse import problem_from
>>> from solprop.pulses import SechPulse
>>> from solprop.stepper import PIController
>>> from solprop.translate.problem import assemble
>>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (500e-9, 2e-6), 4e-12)
>>> gnlse = problem_from([0.0, 0.0, -1.2e-26], omega_ref=grid.omega0, gamma=0.11,
...                      shock=False)
>>> start = SechPulse(wavelength=835e-9, width=1e-13, peak_power=1.0).build(grid)
>>> problem = assemble(
...     grid, gnlse.mode, [gnlse.kerr], start,
...     controller=PIController(rtol=1e-8, atol=1e-14), save_planes=[1.0],
...     dz_max=0.1, dz_init=1e-3, shock=False, prefactor_index=1.0, density=1.0,
... )
>>> problem.shape, problem.grid_kind, problem.schema_version
((1, 1, 1, 4096), 'envelope', 36)
current_numerator: Float[ndarray, 'n_modes n_pol n_omega'] | None = None#
property device_ready: bool[source]#

Return whether both z-varying arrays are in the seam’s device form.

True when Phi and the prefactor each evaluate as a weighted sum of a fixed set of arrays over host scalars – the constant fast path with one term and the distance as its weight, or a parameter expansion with n_terms of them (solprop.translate.stage). False when either took the z table, whose evaluation is a Clenshaw pass over an array of the state’s size times the degree: the general representation, which the CPU backends evaluate (the native CPU build into term slots of its own, SEP 29 section 6.6) and an accelerator build refuses through solprop.translate.stage.require_device_ready().

Returns:
bool

Whether neither representation is "table".

Examples

>>> from solprop.grid import EnvelopeGrid
>>> from solprop.nonlinear.gnlse import problem_from
>>> from solprop.pulses import SechPulse
>>> from solprop.stepper import PIController
>>> from solprop.translate.problem import assemble
>>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (500e-9, 2e-6), 4e-12)
>>> gnlse = problem_from([0.0, 0.0, -1.2e-26], omega_ref=grid.omega0,
...                      gamma=0.11, shock=False)
>>> start = SechPulse(wavelength=835e-9, width=1e-13,
...                   peak_power=1.0).build(grid)
>>> assemble(grid, gnlse.mode, [gnlse.kerr], start,
...          controller=PIController(rtol=1e-8, atol=1e-14),
...          save_planes=[1.0], dz_max=0.1, dz_init=1e-3, shock=False,
...          prefactor_index=1.0, density=1.0).device_ready
True
flags: Flags#
flux: FluxPlan | None = None#
grid_kind: Literal['field', 'envelope']#
grids: Grids#
initial: Initial#
linear: LinearOperator#
precision: Precision = Precision(state='double', source='double')#
responses: CompiledResponses#
schema_version: int#
shape: tuple[int, int, int, int]#
stats_spec: StatsSpec#
stepper: StepperSettings#
tdse: TDSEDescriptor | None = None#
transform: Transform#
validate()[source]#

Check every promise the contract makes, raising on the first that fails.

A backend calls this and refuses anything inconsistent (docs/dev/architecture.md section 7). What is checked: the schema version; every array finite, C-contiguous, read-only and of the stated dtype and shape; the masks Boolean; the breakpoints strictly increasing and covering the run including its margin; the hard kinks interval edges; every table along z spanning the same range and, for the prefactor, carrying the state’s value shape; a constant prefactor, when present, standing in for a table that is one interval of degree zero and agreeing with it; the Raman rows agreeing with the fine grid and with each other; the save planes and, when one is replayed, the schedule’s edges containing every plane and kink; and a replayed schedule or a step floor inside the stability limit of an in-stage collar.

Quadrature weights are checked where they exist, in solprop.modes.quadrature: by the time the transform is built only their product with the mode fields survives, so this checks that product is finite instead.

Raises:
TranslationError

Naming the field that failed.

Examples

>>> from solprop.grid import EnvelopeGrid
>>> from solprop.nonlinear.gnlse import problem_from
>>> from solprop.pulses import SechPulse
>>> from solprop.stepper import PIController
>>> from solprop.translate.problem import assemble
>>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (500e-9, 2e-6), 4e-12)
>>> gnlse = problem_from([0.0, 0.0, -1.2e-26], omega_ref=grid.omega0,
...                      gamma=0.11, shock=False)
>>> start = SechPulse(wavelength=835e-9, width=1e-13,
...                   peak_power=1.0).build(grid)
>>> problem = assemble(
...     grid, gnlse.mode, [gnlse.kerr], start,
...     controller=PIController(rtol=1e-8, atol=1e-14), save_planes=[1.0],
...     dz_max=0.1, dz_init=1e-3, shock=False, prefactor_index=1.0,
...     density=1.0,
... )
>>> problem.validate() is None
True
validate_launch()[source]#

Check the launch against the save planes, and a schedule against them.

The part of validate() a replaced input with a new launch position needs again (solprop.driver.simulation.Simulation.with_input()): every other leaf is shared, unchanged, with a problem that was validated whole.

Raises:
TranslationError

If a save plane does not follow the launch, or a replayed schedule does not land on every save plane and hard kink.

Examples

>>> from solprop.driver import Simulation
>>> simulation = Simulation.from_gnlse(
...     0.11, 0.01, [0.0, 0.0, -1.183e-26], lambda0=835e-9,
...     wavelength_limits=(500e-9, 2e-6), trange=1e-12,
...     width=100e-15, peak_power=9.8, pulseshape="sech",
... )
>>> simulation.translate().validate_launch() is None
True
solprop.translate.problem.LOG_DBL_MAX = 709.782712893384#

log(DBL_MAX), about 709.78: the largest exponent exp returns finite.

IEEE Std 754-2019, doi:10.1109/IEEESTD.2019.8766229. A propagator factor exp(h lambda) past it is infinite on every backend (SEP 22 section 4.5).

solprop.translate.problem.LOG_FLT_MAX = 88.72283905206835#

log(FLT_MAX), about 88.72: binary32’s largest finite exp (SEP 33).

solprop.translate.problem.MAX_GENERAL_FLOW_EXPONENT: float = 1000.0#

Largest dz_max max|G| a general modal coupled flow is executed at.

Dimensionless. The backend takes the flow’s action by scaling and squaring a Schur factor, whose relative error grows with the exponent’s norm: at 1e3 the action is still good to about 1e-13 relative, which is the accuracy the diagonal route it replaces has. The exponent a split block produces is tiny – the departure of each channel from the reference is the block’s own splitting, 744 1/m on the TE01/TM01 pair, and dz_max is microns – so this limit exists to catch a block built from channels that were never a degenerate group, whose departures are the whole dispersion and which would silently lose digits.

solprop.translate.problem.MAX_N_COMPONENTS = 3#

Cartesian components of the local physical field a general modal guide resolves.

The count of solprop.translate.modal_tables.ModalTransformTables’ component axis – E_x, E_y and E_z, and the matching H – which is a property of the provider’s fields and not of the state’s polarisation axis. The distinct check MAX_N_POL performs for the legacy routes is kept beside it, unchanged.

solprop.translate.problem.MAX_N_POL = 2#

Most entries the state’s polarisation axis may have.

The transverse components are carried either by the transform’s rows or by the state’s polarisation axis, never by both: a row of synthesis is one Cartesian component at one node, and so is one entry of the state’s polarisation axis, so a problem that set both would count them twice.

It stays 2 at kernel schema 14. A general modal guide’s three Cartesian components are not three state polarisations: one vector eigenmode has E_x, E_y and E_z and stores one amplitude, so the guide carries n_pol = 1 and MAX_N_COMPONENTS local field components. Setting this to 3 would instead admit three independent amplitudes per eigenmode, which is a different and unphysical problem.

solprop.translate.problem.MOVING_FLOW_CERTIFICATE: str = 'general-moving-frozen-residual'#

The certificate_id a moving solid guide’s coupled flow carries.

solprop.translate.problem.NoiseModel#

Which shot-noise model the run carries (see docs/dev/decisions.md).

alias of Literal[‘none’, ‘input’, ‘modified’]

solprop.translate.problem.PropagatorMode#

Whether the backend tabulates the stage propagators or recomputes them.

"auto", the default, is the backend’s own choice, resolved at construction and recorded in the run’s metadata: tabulate for numpy_ref, whose two complex exponentials per stage the table is worth memoising, and recompute for numba_cpu, where both signs come from one real exp and a sincos in the stage that formed them, so the table buys residency and nothing else – 561 us against 574 and 128 KiB against 768 on the soliton case (docs/dev/backends.md section 3.6). Either can still be asked for by name; the two agree bitwise, so the choice is memory and not numbers.

alias of Literal[‘auto’, ‘tabulate’, ‘recompute’]

solprop.translate.problem.SCHEMA_VERSION = 36#

Version of the kernel contract this module implements.

Incremented on every change to the field list of docs/dev/kernel-contract.md. A backend refuses a problem whose version it does not know. Version 2 replaced the prefactor array with a table along z and added prefactor_constant beside it, so that the effective index’s z profile is carried rather than frozen at the entrance. Version 3 replaced the z tables of the operator and the prefactor with expansions in the scalar parameters they depend on, the z table staying behind the same evaluation functions, moved the harmonic carrier into the grids as carrier_2w0, and gathered the Raman rows into raman_coefficients.

Version 4 adds spatial geometry, transverse integration and absorber data, and the constant separable spatial operator/prefactor in the problem and stage bundles.

Version 5 adds required material and transverse square residuals to the separable record, resolving Cartesian cutoff arithmetic from unsquared binary inputs.

Version 6 adds mixture channels and their stage bundles. Version 7 adds the three periodic statistics storage hooks to StepDriver, allowing device rows to be copied once per plane. Problem fields, stage bundles and numerical conventions are unchanged. Version 8 adds the batch protocol, independent member observations and metadata, and the backend free-device-memory query for admission of fixed-schedule fibre batches.

The number also covers the seam a compiled backend subclasses and packs from: the protected surface of solprop.backends.driver.StepDriver a subclass overrides or reads, and the fields of solprop.translate.stage.StageTerms and solprop.translate.stage.StageScalars. tests/backends/test_driver.py holds that surface as a literal, so a change to it fails there until this number is bumped and the literal rewritten in the same commit. A separately built backend refuses a problem of another version and looks the members it relies on up by name; it never compares solprop’s own version.

Version 9 adds envelope plasma cycle data, labelled channels and explicit spectral assembly, and retains rate conventions and species bindings in rate tables. Field plasma channels and stage scalar field names remain unchanged; the population scalar tuples cover whichever plasma representation is active.

Version 10 adds the explicit numeric Raman tensor weights and the per-component capability declaration; scalar Raman retains its operation order. Version 11 adds the modal power-weight row (see docs/dev/decisions.md) in its three representations and the endpoint block of a cumulative parameter expansion; the driver surface and the stage bundles are unchanged and every backend consumes the weight in its statistics pass alone.

Version 12 adds the four optional leaves of the general modal route – linear.coupled_flow, linear.modal_metric, transform.modal_tables and responses.regional_responses – each None by default, and admits int32 across the seam for the region and support indices they carry. A problem with all four None is the version-11 problem, bit for bit, and allocates no new buffer. The driver surface and the stage bundles are unchanged.

Version 13 adds the two coupled-flow rows of the stage bundle – flow_section, which section of linear.coupled_flow the step’s anchor lies in, and flow_weights, the weights its (n_intervals, n_deg) coefficient block is combined over at the stage’s position – so that a varying guide’s frozen generator and explicit residual are evaluated from host scalars rather than from a Clenshaw pass over a leaf. Nothing else moves: no LinearOperator row, no StepDriver signature, no dtype. A problem carrying no coupled flow reports flow_section = -1 and flow_weights = None and is the version-12 problem bit for bit. numpy_ref, numba_cpu and native execute both "frozen_residual" and "constant_schur" sections. The "cf4" sections move nothing either: the Gauss nodes of a CF4 step are not stage positions, and numpy_ref evaluates the leaf’s own expansion at them from z_edges, the degree axis and the step’s flow_section, which the leaf and the bundle already carry.

Version 14 adds one row of the stage bundle, transform_weights: the weights a moving guide’s transform.modal_tables synthesis and projection maps are combined over at the stage’s position, their (n_intervals, n_deg) coefficient axes flattened, separate from flow_weights so that the transform’s sectioning is its own. A problem whose maps do not move reports None and is the version-13 problem bit for bit; nothing else moves.

Version 15 adds the hybrid planar geometry: the SpatialGeometry.kind "slab" (slab modes in x on the transform’s own synthesis and projection, an FFT in y, columns (p, k_y) with the mode index fastest) and one appended SeparableOperator field, kappa_sq, each channel’s complex, frequency-dependent wall term subtracted from the column’s longitudinal square. It is None on every other kind, whose problems are the version-14 problems bit for bit. No KernelProblem field, stage bundle or StepDriver signature moves. numpy_ref, numba_cpu and native CPU execute the kind.

Version 16 appends StepperSettings.integrator: SEP 13’s low-call Adams method stepping the problem instead of the tableau, or None for the Runge-Kutta march, whose problems are the version-15 problems bit for bit. Only numpy_ref executes an integrator; numba_cpu and native refuse it by name, and the driver’s settings refuse it before translation on any other backend. No StepDriver signature moves: the Adams march is the reference backend’s own _march_to.

Version 17 appends StepperSettings.interval_cap and auto_init (SEP 14 phase 1): whether the march caps a step at the width of the operator-table interval it starts in, and whether the start-up rule takes the step after the first from that step’s own error estimate. assemble resolves both from the route: off and on on the diagonal-flow routes, on and off for a coupled flow or a reject-free controller. A problem with the cap on and the rule off is the version-16 problem bit for bit. Every backend inherits the shared march, so none moves; Kokkos follows the version only.

Version 18 appends StepperSettings.interpolate_planes (SEP 14 phase 3): True observes a save plane inside an accepted step – through DOPRI5’s continuous extension, or the Adams march’s own polynomial – instead of landing on it; False (the version-17 problem bit for bit) lands. It replaces SEP 13’s Multistep.dense. The shared march does it with one more StepDriver hook, _dense_stages, the accepted step’s stage derivatives on the host. It also appends StepperSettings.step_planes: a positive k stops propagate_to short of its target at the end of every k-th accepted step, so the driver saves the march’s own steps as planes; 0 (the version-17 march) never stops short.

Version 20 (SEP 16 phase 2) gives StepperSettings.integrator a formulation field, "interaction" (the version-19 method bit for bit) or "exponential", and adds one protected StepDriver hook, _adams_lab_source: one source evaluation returned in the lab frame, untransported, which the exponential formulation integrates against the linear flow. A backend without the hook refuses the exponential formulation by name; no KernelProblem field or stage bundle moves.

Version 21 (SEP 16 phase 3b) adds the protected hook _adams_engine: a backend may return an engine that keeps the Adams history and every state-sized operation of the fused and exponential paths where its state lives (solprop.backends.multistep.AdamsEngine); None, the default, keeps the host engine over the other Adams hooks, the version-20 arithmetic bit for bit. No KernelProblem field or stage bundle moves.

Version 22 (SEP 16 phase 5) adds the protected hook _adams_block: a backend that holds a coupled flow returns the frozen block of the section a step is anchored in, whose matrix moments the exponential formulation’s trial takes. None, the default, is a problem without one. No KernelProblem field or stage bundle moves. Version 23 adds grids.norm_mask, the bins the error norm scores: the controller’s region, by default every active bin rather than the requested band alone, which grids.inband_mask still carries.

Version 24 (SEP 6 phase 1) appends responses.dispersive_kerr, the frequency-dependent electronic response’s leaf (translate.responses.DispersiveKerrTerms): its evaluator and sector, the fine-grid multipliers of each population’s channel and their density tables, beside the dispersive_kerr stage of response_order. It appends one row to the stage bundle, StageScalars.dispersive_kerr_densities, each channel’s number density at the stage. grids.carrier_2w0 is also present for the dispersive full cubic on an envelope grid. A problem without the leaf is the version-23 problem bit for bit, its new bundle row empty. On the general modal route the leaf’s regions names each channel’s node region, a gas region’s species. numpy_ref executes the leaf on every route; numba_cpu and the native backend refuse it by name.

Version 25 (SEP 18 phase 1) appends responses.plasma_integral, the running-integral rule of the field-grid plasma column (solprop.nonlinear.ionisation.RunningIntegral): one per problem, because the channels share the two current integrals. The "trapezoid" rule is the version-24 column bit for bit. The "band" rule filters each of the three integrands with the grid’s symmetric taps before the trapezoid, closes the window’s ends by point reflection and floors the exposure at zero, so plasma_scan and plasma_current read K samples ahead of the one they finalise. numpy_ref, numba_cpu (SEP 18 phase 2) and native CPU (phase 3) execute both rules; a native device build refuses "band" by name. No stage bundle or StepDriver hook moves.

Version 26 (SEP 19 phase 1) appends transform.kind, what the transform represents, stored instead of inferred from the node count: "mode_averaged" for the effective-area route alone, "modal" for every resolved quadrature of any node count and for the general modal tables, and the spatial geometry’s kind otherwise. A one-node quadrature is therefore an ordinary modal transform, with no area conversion in its prefactor. Every existing problem keeps its arithmetic bit for bit.

Version 27 (SEP 20 phase 1) widens what tdse may carry without changing any field: a solprop.tdse-descriptor.v3 descriptor names a haCC model and its pinned setup record, and may carry an atomic window whose gate, read through TDSEDescriptor.source_gate(), replaces grids.t_window_fine as the time_collar source gate. A version-26 consumer would misread such a descriptor, so the version moves; version-1 and version-2 descriptors are unchanged bit for bit.

Version 28 (SEP 25) moves no field: StepDriver._stage_bundles, a trial’s stage bundles read together, joins the driver surface a separately built backend is built against, so a version-27 consumer refuses the problem.

Version 29 (SEP 24 phase 1) widens StepperSettings.integrator to Multistep | LowStorageRungeKutta | None: the low-storage interaction-picture RK4 march, which replays a schedule in three registers and records no estimate. It adds the protected hook StepDriver._low_storage_engine and the driver attributes _low_storage and _in_flight to the surface, and _stage_bundles keeps the bundles of every anchor it is asked for until the next hoist (the march reads three). A backend that does not execute the march refuses it by name, because a widened field would otherwise read as no integrator and run DOPRI5. Every problem without it keeps its arithmetic bit for bit.

Version 30 (SEP 26 phase 1) moves no field: tdse may carry a solprop.tdse-descriptor.v4 descriptor, the gated_derivative source filter of an SAE or haCC response, windowed or on the grid collar. Its source subtracts the gate’s edge term, F[g' S] / (i omega), using TDSEDescriptor.source_gate_derivative(), so a version-29 consumer would misread it; translation admits it only when its steady-current certificate is at most 1e-10 (SEP 26’s further fixed 128-sample taper minimum was later dropped as a defect, with no field change).

Version 31 (SEP 22 phase 2) appends SeparableOperator.kperp_rate, a transverse collar’s power rate per column, which joins the field attenuation on the active band (D -= kperp_rate / 2 there); zeros, the default, are the version-30 operator to the last bit. StepDriver.observe gains the keyword field: False observes the step history and statistics’ position without crossing the field or the noise phase to the host, and solprop.backends.protocol.Observation carries field=None. StepDriver.held_observation returns the state a low-storage march held at its last field-free plane. SeparableOperator.evanescent_rate may now be set by the run (SimulationSettings.evanescent_rate).

Version 32 (SEP 24 phase 3) moves no field of the problem: solprop-native executes the low-storage march with a resident engine, so an older wheel, which refuses it, must be refused in turn. solprop.backends.low_storage.LowStorageEngine gains atomic, whether its step is one native call no signal interrupts (the march then takes the step, the finish and the move in one commit), and StepDriver gains _hold and _held_field on its surface, so a backend may hold the field-free plane’s state where its own state lives.

Within version 32 the source filter was removed with descriptor versions 1 to 4: every tdse descriptor is now solprop.tdse-descriptor.v5, and a native descriptor’s source is always gated and edge-free (TDSEDescriptor.gated). Removing values no consumer could misread needs no bump.

Version 33 (SEP 27) adds grids.t_window_fine_derivative and changes the field plasma column’s outputs to the two products g J and g' J alongside collared non-plasma polarisation. Route assembly combines their spectra with 1/(i omega) and -1/(i omega)**2 only on positive active bins.

Version 34 (SEP 29 phase 2) moves no field of the problem: StepDriver gains the class attribute helpers, the backend’s implementation of the per-stage Chebyshev rows and the Adams basis, which the shared driver, march and engines pass down (solprop._helpers). An older native build does not set it and would run solprop’s Numba helpers, so it is refused.

Version 35 (SEP 34) adds flux, the spatial run’s plane-measure coefficients (solprop.translate.spatial.FluxPlan): every spatial statistic is the axial Poynting flux of the medium at its plane, weighted by the admittance c k_z / omega of that plane’s root, with the complex admittance for local flux. A radial gas path’s cumulative operator gains the forward amplitude term -ln(Y_z(z)/Y_z(0))/2. A problem without spatial geometry carries no plan.

Version 36 (SEP 33) adds precision, the arithmetic the run is held in (solprop.translate.precision.Precision). Every table stays binary64 at the seam; a backend that admits single precision narrows its tables on upload, and every other backend refuses a single-precision problem by name.

class solprop.translate.problem.StepperSettings(tableau, controller, dz_min, dz_max, dz_init, stretch, schedule, save_planes, propagator_mode, integrator=None, interval_cap=True, auto_init=False, interpolate_planes=False, step_planes=0)[source]#

Bases: object

The tableau, the controller and the schedule of a run.

Section 7 of the kernel contract. The tolerances and the norm choice live in the controller and nowhere else.

Attributes:
tableausolprop.stepper.tableau.Tableau

Nodes, matrix, solution weights, error weights b - b_hat, orders and the first-same-as-last flag.

controllersolprop.stepper.controller.PIController

Tolerances, safety, growth caps, the PI exponents, the lag, the reject-free switch, the estimator order and the norm weights.

dz_minfloat

Floor on the controller’s proposal, m. A proposal below it raises rather than being clamped silently; it never applies to a landing step.

dz_maxfloat

Cap on the proposal, m.

dz_initfloat

First step, m.

stretchfloat

Landing stretch factor: a target within this multiple of the capped proposal is landed on directly. 1 switches it off.

schedulesolprop.stepper.schedule.FixedSchedule or None

A fixed schedule to replay, whose edges must contain every save plane and hard kink. None for an adaptive run; lockstep batches require one.

save_planesnumpy.ndarray

Positions in z the driver will ask for, m, shape (n_z,), increasing. Steps land on them exactly; there is no dense output.

propagator_mode{‘auto’, ‘tabulate’, ‘recompute’}

Whether the backend tabulates the stage propagator factors or recomputes them. "auto" leaves the choice to the backend, which records what it resolved.

integratorsolprop.stepper.multistep.Multistep or LowStorageRungeKutta or None

A low-call Adams method to step with instead of the tableau (SEP 13), the low-storage RK4 march (SEP 24), or None for the Runge-Kutta march. With a schedule an Adams method replays the schedule’s steps (SEP 16 section 5); the low-storage march replays one and nothing else.

interval_capbool

Whether a step is capped at the width of the operator-table interval it starts in. The cumulative table makes the flow exact across intervals, so the cap is off on the diagonal-flow routes and on for a coupled flow, whose flow error the embedded estimate does not see (SEP 14 section 4.1).

auto_initbool

Whether the start-up rule takes the step after the first from the first step’s own error estimate (PIController.start_factor); False grows from dz_init at the growth cap.

interpolate_planesbool

Step across the save planes and observe each inside its accepted step, through the tableau’s continuous extension or the Adams march’s own polynomial (SEP 14 phase 3); False lands on them. The end of the run and every hard kink are landed on either way.

step_planesint

A positive k also saves the end of every k-th accepted step: the march’s propagate_to returns there, short of its target, and is called again (SEP 14 phase 3). 0 saves the requested planes only.

Raises:
TranslationError

If the step caps are not ordered, the stretch is below one, the save planes are not increasing and positive, or the low-storage march is asked for without a schedule, with interpolated planes or with a schedule step longer than dz_max.

Examples

>>> from solprop.stepper import DOPRI5, PIController
>>> from solprop.translate.problem import StepperSettings
>>> settings = StepperSettings(DOPRI5, PIController(rtol=1e-8, atol=1e-14),
...                            1e-9, 0.1, 1e-3, 1.1, None, [0.5, 1.0], "tabulate")
>>> settings.save_planes.tolist()
[0.5, 1.0]
auto_init: bool = False#
controller: PIController#
dz_init: float#
dz_max: float#
dz_min: float#
integrator: Multistep | LowStorageRungeKutta | None = None#
interpolate_planes: bool = False#
interval_cap: bool = True#
propagator_mode: Literal['auto', 'tabulate', 'recompute']#
save_planes: Float[ndarray, 'n_z'] | Sequence[float]#
schedule: FixedSchedule | None#
step_planes: int = 0#
stretch: float#
tableau: Tableau#
property z_end: float[source]#

Return the last save plane, where the run stops.

Returns:
float

The largest save plane, m.

Examples

>>> from solprop.stepper import DOPRI5, PIController
>>> from solprop.translate.problem import StepperSettings
>>> StepperSettings(DOPRI5, PIController(rtol=1e-8, atol=1e-14), 1e-9, 0.1,
...                 1e-3, 1.1, None, [0.5, 1.0], "tabulate").z_end
1.0
solprop.translate.problem.TAPER_FLOW_CERTIFICATE: str = 'taper-frozen-residual'#

The certificate_id of a multimode capillary taper’s coupling without a wall.

class solprop.translate.problem.TranslationReuse(transform, initial, phi_expansion, prefactor_expansion, raman_undamped)[source]#

Bases: object

Carry prequalified reusable data into a material-path update.

This host-side construction record is outside the kernel contract. Its caller must establish unchanged geometry, grid and operator functions before supplying their data; solprop.driver.simulation.Simulation.with_mixture() performs those checks. New parameter paths are checked against each expansion’s ranges.

Attributes:
transformTransform

Unchanged transverse geometry, quadrature and grid transform.

initialInitial

Unchanged initial field, noise and batch parameters.

phi_expansionParameterExpansion or None

Cumulative-operator coefficients, only if its sampled function is unchanged.

prefactor_expansionParameterExpansion or None

Prefactor coefficients, under the same function-identity requirement.

raman_undampedMapping

Component label to undamped rows, for unchanged Raman models and time grid.

initial: Initial#
phi_expansion: ParameterExpansion | None#
prefactor_expansion: ParameterExpansion | None#
raman_undamped: Mapping[str, Float[ndarray, '... n_to_doubled']]#
transform: Transform#
solprop.translate.problem.assemble(grid, modes, responses, field0, *, controller, save_planes, dz_max, dz_init, density=None, noise=None, frame=None, loss=LossPolicy(max_alpha=None), absorber=None, absorber_scheme='nonlinear', quadrature=None, components=None, tableau=Tableau(name='DOPRI5', nodes=array([0., 0.2, 0.3, 0.8, 0.88888889, 1., 1.]), matrix=array([[0., 0., 0., 0., 0., 0., 0.], [0.2, 0., 0., 0., 0., 0., 0.], [0.075, 0.225, 0., 0., 0., 0., 0.], [0.97777778, -3.73333333, 3.55555556, 0., 0., 0., 0.], [2.95259869, -11.59579332, 9.82289285, -0.29080933, 0., 0., 0.], [2.84627525, -10.75757576, 8.90642272, 0.27840909, -0.2735313, 0., 0.], [0.09114583, 0., 0.4492363, 0.65104167, -0.32237618, 0.13095238, 0.]]), solution_weights=array([0.09114583, 0., 0.4492363, 0.65104167, -0.32237618, 0.13095238, 0.]), error_weights=array([0.00123264, 0., -0.00425277, 0.03697917, -0.0508638, 0.04190476, -0.025]), order=5, embedded_order=4, first_same_as_last=True), integrator=None, schedule=None, dz_min=None, stretch=None, interval_cap=None, auto_init=False, interpolate_planes=False, step_planes=0, propagator_mode='auto', stats_spec=None, batch_params=None, shock=True, prefactor_index=None, ionisation_field_range=None, node_budget=None, spatial_grid=None, medium=None, margin=0.05, tol=1e-12, polarisation_taper=False, general=None, wall=None, taper_coupling=True, reuse=None, initial_z=0.0, evanescent_rate=None, transverse_absorber=None, adiabatic_accuracy=None, precision=Precision(state='double', source='double'))[source]#

Turn the physics objects of a run into a validated kernel problem.

This is the whole of the translation layer’s public entry point: it builds the cumulative linear operator, the masks, the modal transform and the compiled responses, derives the flags from what it built, and validates the result before returning it. Everything it does is expensive once and free thereafter (docs/dev/architecture.md section 7).

The run covers [initial_z, max(save_planes)]. Tables retain absolute positions from zero and cover a further margin beyond the last plane.

Parameters:
gridsolprop.grid.TimeGrid

The field or envelope grid.

modesMode or sequence of Mode

The mode, or the ordered set of a multimode problem. A set needs quadrature.

responsessequence

The declared nonlinear responses; see solprop.translate.responses.compile_responses(). A TDSE response owns the complete gas nonlinearity and refuses another Kerr or plasma term.

field0numpy.ndarray

Initial state, shape (n_modes, n_pol, n_omega) or already batched, complex, in the square root of watts and the internal FFT convention — a solprop.pulses.Pulse.build() result, or a stack of them.

controllersolprop.stepper.controller.PIController

Tolerances, norm and step-control parameters.

save_planesarray_like

Positions in z the driver will ask for, m, increasing and positive.

dz_maxfloat

Cap on the controller’s proposal, m.

dz_initfloat

First step, m.

densitysolprop.profiles.ZProfile or float or None, optional

Number density along z in m^-3. None takes the mode’s own density path when it declares one and 1.0 otherwise, which is the convention a medium with an absolute chi3 uses. Refused beside a mixture and beside a gas medium, which carry their own.

noisesolprop.noise.NoiseRealisation or None, optional

A shot-noise realisation to carry along the run.

framesolprop.linear.Frame or None, optional

The co-moving frame. None builds solprop.linear.Frame.comoving() for the grid, keeping beta_0 when a third-harmonic Kerr term is present on an envelope grid.

losssolprop.linear.LossPolicy, optional

What to do with an attenuation too large to represent.

absorbersolprop.boundaries.Absorber or None, optional

The collar rates. Its spectral part is folded into the linear operator and its temporal part crosses the seam as a rate.

absorber_scheme{‘split_step’, ‘nonlinear’}, optional

Which application of the temporal absorber the backend will use.

quadraturesolprop.modes.quadrature.TransverseQuadrature or None, optional

The fixed transverse rule of a multimode problem. None builds the mode-averaged, single-node transform, which needs exactly one mode.

componentssequence of str or None, optional

The transverse Cartesian components the multimode transform resolves at each node, a non-empty subset of ("x", "y"). None takes the union of the mode set’s nonzero components at the entrance, from each mode’s principal_component(0.0): ("x",) for HE_1m modes at phi = 0, and both for a rotated or mixed set; pass ("x", "y") for a polarisation-resolved mode set (solprop.modes.collection.ModeCollection.with_polarisations()). Only meaningful with a quadrature, and refused without one. The product of its length and the state’s polarisation axis may not exceed two: the components are carried by the transform or by the state, never by both.

tableausolprop.stepper.tableau.Tableau, optional

The Runge-Kutta tableau. Default DOPRI5.

integratorsolprop.stepper.multistep.Multistep or LowStorageRungeKutta, optional

A low-call Adams method instead of the tableau (SEP 13), or the low-storage RK4 march, which replays schedule (SEP 24).

schedulesolprop.stepper.schedule.FixedSchedule or None, optional

A fixed schedule to replay. Its edges must contain every save plane and hard kink.

dz_minfloat or None, optional

Floor on the controller’s proposal, m. None uses solprop.stepper.controller.default_dz_min() of the run length.

stretchfloat or None, optional

Landing stretch factor. None uses DEFAULT_STRETCH.

interval_capbool or None, optional

Whether a step is capped at its operator-table interval’s width. None caps it only for a coupled flow or a reject-free controller (SEP 14 section 4.1).

auto_initbool, optional

Whether the start-up rule chooses the step after the first; dz_init is the first. Default False, the convenience interfaces’ choice when no dz_init is given. Off for a coupled flow or a reject-free controller.

interpolate_planesbool, optional

Whether save planes are observed inside accepted steps – through DOPRI5’s continuous extension or the Adams march’s polynomial – rather than landed on (SEP 14 phase 3). Refused beside a coupled flow, the per-step temporal collar and the modified noise model.

step_planesint, optional

Also save the end of every step_planes-th accepted step (SEP 14 phase 3); 0, the default, saves the requested planes only.

propagator_mode{‘auto’, ‘tabulate’, ‘recompute’}, optional

Whether the backend tabulates the stage propagators.

stats_specsolprop.stats.StatsSpec or None, optional

Which statistics to collect. None collects none.

batch_paramsmapping or None, optional

Per-member scalars to record, each of length n_batch.

shockbool, optional

Keep the omega dependence of the prefactor’s numerator, which is the optical shock term. Default True.

prefactor_indexfloat or None, optional

Use this constant in the prefactor and power weight; None uses Re n_eff. The GNLSE passes 1.0, leaving its power normalisation and Phi unchanged.

ionisation_field_rangetuple of float or None, optional

Field amplitudes in V/m a plasma response’s rate table must cover.

node_budgetint or None, optional

Bytes of node-chunk buffers a multimode response pass may hold. None takes DEFAULT_SPATIAL_NODE_BUDGET on a free-space, line or planar grid and DEFAULT_NODE_BUDGET otherwise.

spatial_gridRadialGrid, FreeGrid, PlanarGrid or None, optional

Radial or Cartesian geometry, or the hybrid planar grid (solprop.modes.slab.PlanarGrid); requires modes=None and a bulk medium. The initial columns then contain Hankel spectra in V m, raw Cartesian DFT spectra in V/m, or y-DFT spectra of slab amplitudes in sqrt(W/m) (the planar grid carries its own modes).

mediumsolprop.spatial.SpatialMedium or None, optional

Material and density path for spatial propagation. Its density is used for nonlinear responses; an explicit density is refused beside a gas or a mixture medium, and scales the responses of a glass or a constant index.

marginfloat, optional

Fraction of the run length the tables extend beyond its end.

tolfloat, optional

Target bound on the uniform error of the tables. Raised automatically to the measured round-off floor of the operator (solprop.translate.linop).

polarisation_taperbool, optional

Whether the spectral collar tapers the nonlinear polarisation as well as absorbing the field through the operator. Default False: the taper sets a floor on a broad pulse of the size of its content in the collar.

generalsolprop.translate.general.GeneralModalRoute or None, optional

The seam leaves of a general modal guide. With it the three-component E/H route is assembled instead of the static transverse quadrature: modes are the guide’s channels in state order and supply the diagonal operator, the power weight is the constant one, the prefactor is the crop scale alone and the responses are the route’s own per-region record. A quadrature, components, spatial_grid, medium, density, prefactor_index, declared responses or shock=False is refused beside it by name, and the grid must be a field grid whose active band lies inside the guide’s support.

wallsolprop.modes.capillary.CoherentWall or None, optional

The declaration of a scalar coherent wall block on the capillary route or, with impedance="te_tm", of one azimuthal order, on a constant or a varying guide. With it Phi carries the mode-independent carrier alone and the modal part of the flow becomes linear.coupled_flow, which every backend executes (a CF4 section numpy_ref alone). A general modal guide, a spatial geometry, a polarisation axis and a noise model are refused beside it by name.

taper_couplingbool, optional

Carry the taper coupling on a multimode capillary whose radius varies along z: the moving-basis connection between the HE_1m channels, in a frozen-residual linear.coupled_flow whose diagonal is each channel’s own propagation constant, lossless or not (solprop.modes.capillary.taper_coupling_block() says which sets). The default True; False keeps the adiabatic diagonal route, in which each channel propagates on its own. It has no effect on any other mode set or route, and False beside a wall is refused, because the wall always carries its connection.

reuseTranslationReuse or None, optional

Immutable data prequalified for the same grid, input, geometry and operator functions. New paths still undergo sampled-range checks. None builds fresh.

initial_zfloat, optional

Absolute launch position in m, non-negative and before the first save. field0 is a true-power spectrum at this position; the input boundary applies the corresponding modal power weight exactly once.

evanescent_ratefloat or None, optional

The spatial operator’s evanescent field attenuation cap in m^-1, positive and finite (SEP 22 section 4.4); None keeps solprop.spatial.EVANESCENT_RATE. Refused without a spatial grid.

transverse_absorbersolprop.boundaries.TransverseCollar or None, optional

A transverse-wavevector safety ramp folded into the Cartesian operator as SeparableOperator.kperp_rate (SEP 22 section 4.3). Refused on the radial and hybrid planar kinds and without a spatial grid.

adiabatic_accuracysolprop.adiabatic.AdiabaticAccuracy or None, optional

The budgets a radial medium varying along z must meet for its forward amplitude transport (SEP 34 section 4.5); None, the default, is AdiabaticAccuracy(). A path exceeding them is refused.

precisionsolprop.translate.precision.Precision, optional

The arithmetic the run is held in (SEP 33): DOUBLE, the default, or SINGLE. The tables are built in binary64 either way; what single precision refuses is refused here.

Returns:
KernelProblem

Validated, versioned and ready for a backend.

Raises:
TranslationError

If a response cannot be compiled, an argument is out of range, or the assembled problem fails KernelProblem.validate().

Examples

>>> from solprop.grid import EnvelopeGrid
>>> from solprop.nonlinear.gnlse import problem_from
>>> from solprop.pulses import SechPulse
>>> from solprop.stepper import PIController
>>> from solprop.translate.problem import assemble
>>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (500e-9, 2e-6), 4e-12)
>>> gnlse = problem_from([0.0, 0.0, -1.2e-26], omega_ref=grid.omega0, gamma=0.11,
...                      shock=False)
>>> start = SechPulse(wavelength=835e-9, width=1e-13, peak_power=1.0).build(grid)
>>> problem = assemble(
...     grid, gnlse.mode, [gnlse.kerr], start,
...     controller=PIController(rtol=1e-8, atol=1e-14), save_planes=[0.5, 1.0],
...     dz_max=0.1, dz_init=1e-3, shock=False, prefactor_index=1.0, density=1.0,
... )
>>> problem.flags.single_mode, problem.linear.n_intervals
(True, 1)
solprop.translate.problem.debug_summary(problem)[source]#

Return a short array-free description of an assembled problem, for a log.

The translation summary AGENTS.md asks the translation layer to log: what was built, in which representation, and with which certificates. It reads the assembled record and nothing else, so it can be called on a problem from any source, and it is not a kernel-contract field – adding a row here is not a seam change.

For a general modal guide it carries the certificates that route rests on and that nothing downstream reads again: the sampled Gram defect the identity metric was admitted with, the declared profile error of the frequency interpolation, the gauge, and the guide’s own support in wavelength.

Parameters:
problemKernelProblem

A problem, assembled and validated.

Returns:
str

Several lines of key: value, with no array in them.

Examples

>>> from solprop.driver import Simulation
>>> from solprop.translate.problem import debug_summary
>>> simulation = Simulation.from_gnlse(
...     0.11, 0.01, [0.0, 0.0, -1.183e-26], lambda0=835e-9,
...     wavelength_limits=(500e-9, 2e-6), trange=1e-12,
...     width=100e-15, peak_power=9.8, pulseshape="sech", n_save=3,
... )
>>> print(debug_summary(simulation.translate()).splitlines()[0])
kernel problem schema 36: envelope grid, route modal
solprop.translate.problem.dispersive_node_buffers(responses, *, spatial)[source]#

Return the buffers per node and component SEP 6’s dispersive response adds.

On the fused node path a backend forms the response’s products at the nodes: one node buffer beside other responses for the symmetric evaluator, which a lone one shares with the bare field, and two for the polynomial, whose cube and derivative products take them in turn. A Cartesian or planar column also holds its filtered fields and products in time and their spectra: two buffers per product, the symmetric evaluator’s one (a mixture’s under its mixture filter) and the polynomial’s 1 + 2 G for G groups of equal leg bound (groups()), and the planar nodes’ one or two besides.

Parameters:
responsesCompiledResponses

The compiled responses, with or without the dispersive leaf.

spatialbool

Whether the route’s nodes are Cartesian or planar columns.

Returns:
int

Complex-equivalent buffers per node and component; zero without the leaf.

solprop.translate.problem.validate_coupled_flow(problem)[source]#

Warn when a run’s declared steps exceed its coupled flow’s advisory limit.

A validate diagnostic in the manner of the in-stage absorber’s stable_step warning: it names the term, the section, the frequency, the residual norm K, the conditioning factor and the limit, and it does not change the caller’s tolerances or schedule. The limit is 0.9/(K ||U_s|| ||U_s^-1||) (solprop.translate.coupled.advisory_step()), and the warning says plainly that it is advisory: a wall difference can have positive real eigenvalues – local growth relative to the frozen attenuating frame – and no positive step makes that residual alone contractive, so neither its spectral radius nor a test of the stability polynomial is a complete rule.

The three steps a run can declare are checked: dz_init, dz_max and, when a fixed schedule is replayed, its own largest step, which the controller can neither shorten nor reject.

A flow with a "cf4" section has no explicit residual there and no advisory step, but a flow error the embedded pair cannot see: the largest declared step’s step-doubling defect estimate (solprop.translate.coupled.cf4_defect()) is warned on when it exceeds the controller’s relative tolerance – an asymptotic estimator, and advisory like the first.

Parameters:
problemKernelProblem

The assembled contract. A problem carrying no coupled flow, or one whose residual is identically zero, has nothing to warn about and is returned from in silence.

Warns:
solprop.exceptions.SolpropWarning

Naming the step that exceeds the limit, with the term, the section, the frequency, K, the conditioning factor and the limit; or, for a CF4 flow, the step, the section, the frequency, the defect estimate and the tolerance.

Examples

>>> from solprop.translate.problem import validate_coupled_flow
>>> validate_coupled_flow.__name__
'validate_coupled_flow'