solprop.driver.runner#

Run one translated simulation many times on one backend, input by input.

SimulationRunner keeps a backend between runs that differ only in their input, and check_derived_problem() refuses a derived problem that differs in anything else. The largest field each optmat rate saw is reported here after a run, a runner’s or a simulation’s own. The manual page is docs/guide/setup/running.md.

Functions

check_derived_problem(constructed, derived, ...)

Refuse a derived problem that is not the constructed one but for its input.

Classes

SimulationRunner(simulation)

One translated problem and one backend, run for many inputs (SEP 22 section 5.2).

class solprop.driver.runner.SimulationRunner(simulation)[source]#

Bases: Displayed

One translated problem and one backend, run for many inputs (SEP 22 section 5.2).

Built by runner(): the problem is translated (or the cached translation reused) and one backend is constructed, once. Each run() then derives the input with with_input(), loads it into the same backend and runs the save-plane loop, returning that input’s own handler. A large problem so pays its backend’s allocation and transform planning once rather than for every input.

A run on the reused backend repeats a fresh backend’s run, to the rounding that separates any two runs: loading an input restores everything the march reads (the reference’s solprop.backends.host.driver.HostDriver.set_initial(), the native backend’s own load). Each run’s record is its own input’s, so each has its own configuration hash.

Use it as a context manager, or call close(): the backend holds about fifteen copies of the state until then. A closed runner refuses run(). A run that raises leaves the runner open, since the next input resets everything; a backend that closed itself closes the runner.

Parameters:
simulationSimulation

The run to repeat. Its settings, and the translation they fix, are used as they are; only the input changes from run to run.

Raises:
DriverError

If the simulation has a TDSE response, whose atomic binding has its own lifecycle and is never reused.

Examples

>>> from solprop.driver import Simulation
>>> from solprop.pulses import SechPulse
>>> 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=1.2e-12,
...     width=100e-15, peak_power=9.8, shape="sech", n_save=3, rtol=1e-6,
... )
>>> def pulse(power):
...     return SechPulse(wavelength=835e-9, width=100e-15, peak_power=power)
>>> with simulation.runner() as runner:
...     outputs = [
...         runner.run(pulse(power), configuration={"peak_power": power},
...                    progress="none")
...         for power in (5.0, 9.8)
...     ]
>>> [output.n_saved for output in outputs], runner.closed
([3, 3], True)
property backend: Backend[source]#

Backend every run is stepped on.

close()[source]#

Close the backend, releasing its buffers; calling it twice does nothing.

A run in progress on another thread finishes first: the close waits for it.

property closed: bool[source]#

Whether the runner, and its backend, are closed.

run(initial, *, output=None, configuration=None, noise='keep', progress=None, progress_period=10.0, input_identity=None)[source]#

Run one input on the runner’s backend and return its handler.

Parameters:
initialPulse, SpatialPulse or numpy.ndarray

The input, as with_input() takes it. An array the record keeps by digest (recorded_input()) is not copied: it is read while this call loads it, and the runner holds no reference to it, nor to any copy, once it is loaded, so a caller that keeps none itself has it freed before the first step.

outputsolprop.output.store.Output or pathlib.Path or str or None, optional

Where this input’s planes go: a handler, a path for an HDF5 file, or None for a new MemoryOutput.

configurationcollections.abc.Mapping or None, optional

Caller keys recorded in this input’s run record and hash, such as the delay of a scan (with_input()).

noiseNoiseRealisation, {‘keep’} or None, optional

The noise, as for with_input(): kept by default, or replaced by another realisation of the same model.

progressProgressReporter, {‘auto’, ‘bar’, ‘log’, ‘none’} or None, optional

Where progress goes (solprop.driver.run.run_problem()).

progress_periodfloat, optional

Seconds between the line reporter’s periodic lines, s.

input_identitystr or None, optional

What an array input is, recorded in its place and not checked, so that its bytes are not digested (with_input(), whose warning applies: a wrong identity passes a resume and a scan’s cache).

Returns:
solprop.output.store.Output

This input’s handler, closed; a memory handler stays readable.

Raises:
DriverError

If the runner is closed or already running an input; if the derived problem is not the runner’s but for its input (a different launch position, or a shared leaf replaced); if the noise model differs from the runner’s, which the backend could not carry; or if input_identity is empty or names anything but an array input.

solprop.driver.runner.check_derived_problem(constructed, derived, constructed_request, derived_request)[source]#

Refuse a derived problem that is not the constructed one but for its input.

What a SimulationRunner checks before loading an input into the backend it built for constructed (SEP 22 section 5.2): the leaves with_input() shares are the same objects, the statistics too, the stepper and the flags, which it rebuilds, agree field by field (the save planes elementwise), and the launch position and the noise model are the backend’s.

Parameters:
constructedsolprop.translate.problem.PropagationProblem

The problem the backend was built for.

derivedsolprop.translate.problem.PropagationProblem

The problem of one input.

constructed_requestsolprop.translate.run_request.RunRequest

The request the backend was built for.

derived_requestsolprop.translate.run_request.RunRequest

The request of the input’s run.

Raises:
DriverError

Naming the first leaf or setting that differs.

Examples

>>> from solprop.driver import Simulation
>>> from solprop.driver.runner import check_derived_problem
>>> 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()
>>> derived = simulation.with_input(problem.initial.field0)
>>> check_derived_problem(
...     problem, derived.translate(), simulation._run_request(),
...     derived._run_request(),
... ) is None
True