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
Canonical component of an unrotated HE_1m mode. |
|
Most entries the state's polarisation axis may have. |
|
Cartesian components of the local physical field a general modal guide resolves. |
|
Landing stretch factor ( |
|
Which shot-noise model the run carries (see |
|
Whether the backend tabulates the stage propagators or recomputes them. |
|
|
|
|
|
Fraction of |
|
Largest inverse conditioning a general modal coupled flow is admitted at. |
|
The |
|
The |
|
Largest |
Functions
|
Turn the physics objects of a run into a validated kernel problem. |
|
Return a short array-free description of an assembled problem, for a log. |
|
Return the buffers per node and component SEP 6's dispersive response adds. |
|
Warn when a run's declared steps exceed its coupled flow's advisory limit. |
Classes
|
Static booleans a kernel specialises on at compile time. |
|
The initial state, the noise realisation and the batch parameters. |
|
Everything a backend needs, and nothing it does not. |
|
The tableau, the controller and the schedule of a run. |
|
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(seedocs/dev/decisions.md). Assembly derives its actual default from the mode set’sprincipal_componenttraits, 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_limitdefaults 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.mdsection 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_MAXabove which translation warns of a step it cannot shrink: such a run completes only while its field stays belowexpof 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:
objectStatic 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)
- 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)
- class solprop.translate.problem.Initial(field0, noise0, noise_model, batch_params, z=0.0)[source]#
Bases:
objectThe 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 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, the noise and the batch parameters are copied, complex128 (float64 for the parameters), 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_batch, n_modes, n_pol, n_omega), in the square root of watts; possibly a read-only broadcast view, never written.- 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'
A broadcast input stays a broadcast, over a copy of the row it repeats:
>>> row = np.ones((1, 1, 1, 8), dtype=complex) >>> held = Initial(np.broadcast_to(row, (4, 1, 1, 8)), None, "none", {}).field0 >>> held.shape, held.strides[0], np.shares_memory(held, row) ((4, 1, 1, 8), 0, False)
- field0: Complex[ndarray, 'n_batch n_modes n_pol n_omega']#
- class solprop.translate.problem.KernelProblem(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'), transverse=None, split_crossing=None)[source]#
Bases:
objectEverything a backend needs, and nothing it does not.
The seam of
docs/dev/architecture.mdsection 3. Construct it withassemble()rather than by hand; callvalidate()before handing it to a backend, whichassemble()already does.- Attributes:
- 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.
- transversesolprop.spatial_absorber.SpatialAbsorberDesign or None, optional
A free-space run’s resolved transverse boundary (version 41).
- 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.
Noneunder 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 = 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, 1, 3072), 'envelope')
- property device_ready: bool[source]#
Return whether both z-varying arrays are in the seam’s device form.
True when
Phiand 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 withn_termsof 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 throughsolprop.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
- linear: LinearOperator#
- responses: CompiledResponses#
- split_crossing: SplitCrossing | None = None#
- stepper: StepperSettings#
- tdse: TDSEDescriptor | None = None#
- transverse: SpatialAbsorberDesign | None = None#
- 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.mdsection 7). What is checked: 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 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], wavelength=835e-9, ... wavelength_limits=(500e-9, 2e-6), trange=1e-12, ... width=100e-15, peak_power=9.8, shape="sech", ... ) >>> simulation.translate().validate_launch() is None True
- solprop.translate.problem.LOG_DBL_MAX = 709.782712893384#
log(DBL_MAX), about 709.78: the largest exponentexpreturns 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 finiteexp(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
1e3the action is still good to about1e-13relative, 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, anddz_maxis 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 checkMAX_N_POLperforms 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
synthesisis 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 = 1andMAX_N_COMPONENTSlocal 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_ida 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:tabulatefornumpy_ref, whose two complex exponentials per stage the table is worth memoising, andrecomputefornative, where both signs come from one realexpand asincosin the stage that formed them, so the table buys residency and nothing else (docs/dev/backends.mdsection 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:
objectThe 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.
Nonefor 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
Nonefor 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);Falsegrows 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);
Falselands on them. The end of the run and every hard kink are landed on either way.- step_planesint
A positive
kalso saves the end of everyk-th accepted step: the march’spropagate_toreturns there, short of its target, and is called again (SEP 14 phase 3).0saves 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]
- controller: PIController#
- integrator: Multistep | LowStorageRungeKutta | None = None#
- schedule: FixedSchedule | None#
- 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_idof a multimode capillary taper’s coupling without a wall.
- class solprop.translate.problem.TranslationReuse(transform, initial, phi_expansion, prefactor_expansion, raman_undamped, transverse=None)[source]#
Bases:
objectCarry 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).
- phi_expansion: ParameterExpansion | None#
- prefactor_expansion: ParameterExpansion | None#
- transverse: SpatialAbsorberDesign | None = None#
- 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, spatial_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.mdsection 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 — asolprop.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.
Nonetakes the mode’s owndensitypath when it declares one and 1.0 otherwise, which is the convention a medium with an absolutechi3uses. 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.
Nonebuildssolprop.linear.Frame.comoving()for the grid, keepingbeta_0when a third-harmonic term is present on an envelope grid (solprop.translate.responses.declares_harmonic_carrier()). A frame given withsubtract_beta0=Truebeside that term is refused.- 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.
Nonebuilds 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").Nonetakes the union of the mode set’s nonzero components at the entrance, from each mode’sprincipal_component(0.0):("x",)for HE_1m modes atphi = 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.
Noneusessolprop.stepper.controller.default_dz_min()of the run length.- stretchfloat or None, optional
Landing stretch factor.
NoneusesDEFAULT_STRETCH.- interval_capbool or None, optional
Whether a step is capped at its operator-table interval’s width.
Nonecaps 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
modifiednoise 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.
Nonecollects none.- batch_paramsmapping or None, optional
Per-member scalars to record, each of length
n_batch.- shockbool, optional
Keep the
omegadependence of the prefactor’s numerator, which is the optical shock term. DefaultTrue.- 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.
NonetakesDEFAULT_SPATIAL_NODE_BUDGETon a free-space, line or planar grid andDEFAULT_NODE_BUDGETotherwise.- spatial_gridRadialGrid, FreeGrid, PlanarGrid or None, optional
Radial or Cartesian geometry, or the hybrid planar grid (
solprop.modes.slab.PlanarGrid); requiresmodes=Noneand 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:
modesare 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 orshock=Falseis 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 itPhicarries the mode-independent carrier alone and the modal part of the flow becomeslinear.coupled_flow, which every backend executes (a CF4 sectionnumpy_refalone). 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_1mchannels, in a frozen-residuallinear.coupled_flowwhose diagonal is each channel’s own propagation constant, lossless or not (solprop.modes.capillary.taper_coupling_block()says which sets). The defaultTrue;Falsekeeps the adiabatic diagonal route, in which each channel propagates on its own. It has no effect on any other mode set or route, andFalsebeside 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.
field0is 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);
Nonekeepssolprop.spatial.EVANESCENT_RATE. Refused without a spatial grid.- spatial_absorbersolprop.spatial_absorber.SpatialAbsorber or None, optional
The transverse boundary (SEP 40): resolved against the grid, the medium and the noise-free field0 into the safety ramp, folded into the operator as
SeparableOperator.kperp_rate, and a real-space collar on request, as the geometry’sabsorber_rate; its design isKernelProblem.transverse.None, the default here, carries neither. Refused 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, orSINGLE. 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, a frame that removes
beta_0is given beside a third-harmonic term on an envelope grid, or the assembled problem failsKernelProblem.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.mdasks 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], 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.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 GforGgroups 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
validatediagnostic in the manner of the in-stage absorber’sstable_stepwarning: it names the term, the section, the frequency, the residual normK, the conditioning factor and the limit, and it does not change the caller’s tolerances or schedule. The limit is0.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_maxand, 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'