solprop.output.memory#

The in-memory output handler.

Everything in RAM: the handler for fast, small problems and for the members of a scan, where a file per run would cost more than the run. It stores exactly what solprop.output.hdf5.HDF5Output stores, in the same layout and the same sign convention – both go through solprop.output.schema.PlaneStore – so a test can compare the two bitwise and MemoryOutput.to_file() writes the file the other handler would have written.

The plane-indexed arrays are allocated once, for the planes the run reserved (reserve(); the run loop reserves the entrance and every save plane), or for a block of INITIAL_BLOCK planes when nothing was reserved, and grow by doubling past that rather than by concatenating on every save, which would be quadratic in the number of planes. The field block follows the run’s field retention (retain()): every plane, exactly the named planes, or none at all, in which case no field block is allocated. The step history is variable in length per plane, so it is kept as a list of pieces, concatenated when read, with a per-plane count beside it.

The manual page is docs/guide/results/output.md.

Module Attributes

INITIAL_BLOCK

Planes preallocated when no run size was reserved (architecture.md §13).

Classes

MemoryOutput([block])

Hold a whole run in memory, in the layout an HDF5 file would use.

solprop.output.memory.INITIAL_BLOCK = 16#

Planes preallocated when no run size was reserved (architecture.md §13).

class solprop.output.memory.MemoryOutput(block=16)[source]#

Bases: PlaneStore

Hold a whole run in memory, in the layout an HDF5 file would use.

Reading stays available after close(), unlike the file handler: nothing is released, so a driver may close in a finally and a caller keep reading.

Parameters:
blockint, optional

Planes to preallocate when the run reserved none (reserve()); a reserved count takes its place. The store doubles whenever it is full.

Raises:
OutputError

If block is not positive.

Examples

>>> import numpy as np
>>> from solprop.grid import EnvelopeGrid
>>> from solprop.output import MemoryOutput
>>> from solprop.output.schema import (
...     GridRecord, RunMetadata, SavedPlane, StepperRecord
... )
>>> from solprop.stepper import DOPRI5, PIController
>>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (400e-9, 2e-6), 2e-12)
>>> metadata = RunMetadata(
...     grid=GridRecord.from_grid(grid),
...     modes=(),
...     simulation_kind="mode_averaged",
...     configuration={},
...     stepper=StepperRecord.from_settings(
...         DOPRI5, PIController(rtol=1e-8, atol=0.0)
...     ),
... )
>>> handler = MemoryOutput()
>>> handler.open(metadata)
>>> handler.save(SavedPlane(z=0.0, field=np.ones((1, 1, grid.n_omega), complex)))
>>> handler.n_saved, handler["field"].shape
(1, (1, 1, 1, 2048))
>>> handler.close()
held_bytes(n_planes, plane_bytes, *, kept=None, field_bytes=0)[source]#

Return the bytes the store will allocate for a run’s planes.

The store allocates the planes the run reserves, which the run loop sets to n_planes, or more if a larger count was reserved already; past that it grows by doubling, which this does not foresee. A run that keeps its field on some planes only is charged the field on those alone (SEP 22): its statistics on every plane, its field on kept of them. The step history and the between-planes rows grow with the steps taken and are not counted.

Parameters:
n_planesint

The planes the run will save, the entrance included.

plane_bytesint

The bytes of one plane: the field, the noise phase and the statistics.

keptint or None, optional

How many planes keep their field; None, every allocated one.

field_bytesint, optional

The part of plane_bytes a plane without its field does not hold.

Returns:
int

The planes allocated times their bytes, the field only where it is kept.

Examples

>>> from solprop.output import MemoryOutput
>>> MemoryOutput().held_bytes(201, 1024)
205824
>>> MemoryOutput().held_bytes(201, 1024, kept=2, field_bytes=1000)
6824
property noise_phase: ndarray | None[source]#

Return the stored noise phases, or None when the run had no noise.

Returns:
numpy.ndarray or None

Shape (n_z, n_modes, n_pol, n_omega), rad, in the internal FFT convention, which is where the noise field lives.

Raises:
OutputError

If the run did not keep its field, and so its noise phase, on every plane.

planes()[source]#

Return every stored plane, back in the internal convention.

The inverse of the whole save path: the field comes back through solprop.fourier.spectrum_to_internal(), so a plane that comes out is the plane that went in. This is how to_file() re-feeds the file handler. A plane that kept no field comes back with field=None.

Returns:
list

One solprop.output.schema.SavedPlane per saved plane, in order.

Examples

>>> from solprop.output import MemoryOutput
>>> MemoryOutput().planes()
[]
to_file(path, *, compression=None, compression_opts=None)[source]#

Write the file an solprop.output.hdf5.HDF5Output would have written.

Parameters:
pathpathlib.Path or str

Where to write. An existing file is replaced.

compression{None, ‘gzip’, ‘lzf’}, optional

Dataset compression; None for none.

compression_optsint or None, optional

Level for 'gzip', 0 to 9; not accepted for the other choices.

Raises:
OutputError

If the handler was never opened, or the run was propagated on a general modal guide, which output schema 6 cannot describe.

Examples

>>> import numpy as np, tempfile
>>> from pathlib import Path
>>> from solprop.grid import EnvelopeGrid
>>> from solprop.output import HDF5Output, MemoryOutput
>>> from solprop.output.hdf5 import resume
>>> from solprop.output.schema import (
...     GridRecord, RunMetadata, SavedPlane, StepperRecord
... )
>>> from solprop.stepper import DOPRI5, PIController
>>> grid = EnvelopeGrid.from_limits(1.0, 835e-9, (400e-9, 2e-6), 2e-12)
>>> metadata = RunMetadata(
...     grid=GridRecord.from_grid(grid),
...     modes=(),
...     simulation_kind="mode_averaged",
...     configuration={},
...     stepper=StepperRecord.from_settings(
...         DOPRI5, PIController(rtol=1e-8, atol=0.0)
...     ),
... )
>>> handler = MemoryOutput()
>>> handler.open(metadata)
>>> start = np.ones((1, 1, grid.n_omega), complex)
>>> handler.save(SavedPlane(z=0.5, field=start))
>>> with tempfile.TemporaryDirectory() as folder:
...     path = Path(folder) / "run.h5"
...     handler.to_file(path)
...     resume(path).plane.z
0.5