solprop.translate.problem#

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

PropagationProblem 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

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.

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.

Functions

debug_summary(problem[, stats])

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

validate_run(problem, request)

Check a problem and the request it is run with, before anything is allocated.

Classes

Flags(single_mode, scalar_pol, has_plasma, ...)

Static booleans a kernel specialises on at compile time.

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

The initial state and the noise realisation of one trajectory.

PropagationProblem(grid_kind, shape, flags, ...)

Everything a backend needs, and nothing it does not.

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

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

Translation(problem, request)

What translation returns: the numerical problem and its run's request.

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_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, has_plasma, has_raman, 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.

has_plasmabool

A plasma response is compiled.

has_ramanbool

A Raman kernel is compiled.

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, 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_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, request = 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_temporal_absorber: bool#
mode_averaged: bool#
n_channels: int = 0#
n_raman: int = 0#
scalar_pol: bool#
single_mode: bool#
class solprop.translate.problem.Initial(field0, noise0, noise_model, z=0.0)[source]#

Bases: object

The initial state and the noise realisation of one trajectory.

Section 6 of the kernel contract. Both arrays are in the lab frame and the FFT convention and read-only; the noise is C-contiguous, and so is the state unless it is a broadcast view.

Every array is the problem’s own, so that nothing the caller does to an array it passed, afterwards, changes the problem, and the caller’s array is never frozen:

  • the state and the noise are copied, complex128, C-contiguous and read-only;

  • a broadcast state (zero strides, as from numpy.broadcast_to()) copies only the block it repeats, converted first, and broadcasts that copy, so it costs the block’s bytes rather than one state’s;

  • an array the problem already holds, which a replaced or re-translated problem passes back, is taken as it is, and so is one solprop built for the problem itself (hold), so that neither is copied twice.

Attributes:
field0numpy.ndarray

Initial state, complex128, shape (n_modes, n_pol, n_omega), in the square root of watts; possibly a read-only broadcast view, never written. A group of trajectories is a sequence of problems, one per member (SEP 47 section 6.7), never a leading axis here.

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.

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, 8), dtype=complex)
>>> Initial(state, None, "none").noise_model
'none'

A broadcast input stays a broadcast, over a copy of the row it repeats:

>>> row = np.ones((1, 1, 8), dtype=complex)
>>> held = Initial(np.broadcast_to(row, (4, 1, 8)), None, "none").field0
>>> held.shape, held.strides[0], np.shares_memory(held, row)
((4, 1, 8), 0, False)
field0: Complex[ndarray, 'n_modes n_pol n_omega']#
noise0: Complex[ndarray, 'n_modes_n n_pol_n n_omega_n'] | None#
noise_model: Literal['none', 'input', 'modified']#
z: float = 0.0#
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.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.NoiseModel#

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

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

class solprop.translate.problem.PropagationProblem(grid_kind, shape, flags, grids, linear, responses, initial, route, split_crossing=None)[source]#

Bases: object

Everything a backend needs, and nothing it does not.

The seam of docs/dev/architecture.md section 3: the numerical meaning of a run and nothing of how it is run. The tableau, controller, step limits, schedule, planes and statistics are the run’s policy, which a RunRequest carries beside it (SEP 47 section 5.2; kernel contract sections 7 and 8). Construct both with assemble() rather than by hand; a backend checks the pair with validate_run() before it allocates, which assemble() already does.

Attributes:
grid_kind{‘field’, ‘envelope’}

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

shapetuple of int

The canonical single-trajectory state shape (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).

responsessolprop.translate.responses.CompiledResponses

The compiled nonlinear term (section 5).

initialInitial

Initial state and noise (section 6).

routesolprop.translate.routes.ModalRoute, GeneralRoute or SpatialRoute

What differs between routes, in exactly one variant of a closed union, each with the fields its executor needs (SEP 47 section 6.2): the transform (section 4) and the route’s own leaves (solprop.translate.routes).

split_crossingsolprop.boundaries.SplitCrossing or None, optional

The split temporal collar’s crossing limit (version 43): each bin’s walk-off bucket, the collar’s width and the launch’s limit, which the boundary monitor reads again from the state at every check. None under the in-stage scheme or without a temporal collar.

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, request = 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
((1, 1, 3072), 'envelope')
property device_ready: bool[source]#

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().

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).problem.device_ready
True
flags: Flags#
grid_kind: Literal['field', 'envelope']#
grids: Grids#
initial: Initial#
linear: LinearOperator#
responses: CompiledResponses#
route: Route#
shape: tuple[int, int, int]#
split_crossing: SplitCrossing | None = None#
property transform: Transform[source]#

The route’s transform, which every route variant carries.

Synthesis and projection (section 4).

validate()[source]#

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

The part of validate_run() that needs no run request: every array finite, read-only, of the stated dtype and shape, and C-contiguous but for the initial state, which may be a broadcast view (Initial); the masks Boolean; the breakpoints strictly increasing and 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 hard kinks interval edges; the Raman rows agreeing with the fine grid and with each other; the general modal route and the coupled flow ones solprop executes (solprop.translate.admission.check_general_route()). What depends on the method, the step limits, the schedule, the planes or the statistics – the tables covering the run, the schedule landing on its targets, the collar’s stability, the exponent budget, the split collar’s crossing and the method’s admission – is checked by validate_run(), which a backend calls before it allocates.

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, request = 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(request)[source]#

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

The part of validate_run() 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.

Parameters:
requestsolprop.translate.run_request.RunRequest

The run’s request, with the planes left beyond the new launch.

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], wavelength=835e-9,
...     wavelength_limits=(500e-9, 2e-6), trange=1e-12,
...     width=100e-15, peak_power=9.8, shape="sech",
... )
>>> problem = simulation.translate()
>>> problem.validate_launch(simulation._run_request()) is None
True
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 native, 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 (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’]

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]#

Last save plane, where the run stops, 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
class solprop.translate.problem.Translation(problem, request)[source]#

Bases: NamedTuple

What translation returns: the numerical problem and its run’s request.

Attributes:
problemPropagationProblem

The numerical meaning (SEP 47 section 5.2).

requestsolprop.translate.run_request.RunRequest

Every policy of a fresh run of it, its step limits resolved against the problem; for_run() adapts it to one run.

problem: PropagationProblem#

Alias for field number 0

request: RunRequest#

Alias for field number 1

class solprop.translate.problem.TranslationReuse(transform, initial, phi_expansion, prefactor_expansion, raman_undamped, transverse=None)[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.

transverseSpatialAbsorberDesign or None

The transverse boundary the reused transform and expansions were built with, kept as they are (SEP 40).

initial: Initial#
phi_expansion: ParameterExpansion | None#
prefactor_expansion: ParameterExpansion | None#
raman_undamped: Mapping[str, Float[ndarray, '... n_to_doubled']]#
transform: Transform#
transverse: SpatialAbsorberDesign | None = None#
solprop.translate.problem.debug_summary(problem, stats=None)[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:
problemPropagationProblem

A problem, assembled and validated.

statssolprop.stats.StatsSpec or None, optional

The statistics its run collects, listed when given; they are the run’s policy, not the problem’s.

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], wavelength=835e-9,
...     wavelength_limits=(500e-9, 2e-6), trange=1e-12,
...     width=100e-15, peak_power=9.8, shape="sech", n_save=3,
... )
>>> print(debug_summary(simulation.translate()).splitlines()[0])
kernel problem: envelope grid, route modal
solprop.translate.problem.validate_run(problem, request)[source]#

Check a problem and the request it is run with, before anything is allocated.

Everything PropagationProblem.validate() checks, in the same order, and with it what depends on the run’s policy: the method’s admission on the route, the save planes following the launch, the statistics the route admits, the request’s own arrays, the propagator mode on a separable route, the tables and a general guide’s leaves covering the run, a replayed schedule landing on every save plane and hard kink, the in-stage collar’s stability, the split collar’s crossing, the exponent budget and, last, dense observation’s admission (SEP 14 section 5). A backend calls this where it is built (SEP 47 section 5.2), so an unsupported combination is refused by name before any workspace exists.

Parameters:
problemPropagationProblem

The translated problem.

requestsolprop.translate.run_request.RunRequest

The run’s request.

Raises:
TranslationError

Naming the field or setting that failed.

Warns:
solprop.exceptions.ExponentBudgetWarning

When a step the run cannot shrink comes within a tenth of the exponent limit.

Examples

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