Simulation#
simulate#
.. py:function:: simulate(spec, *, until=None, perf=None) :module: minisim
Run a full recording specification and return the typed Recording.
Seeds the RNG from spec.seed (so a spec + seed fully determines the
output), sizes the motion margin, runs the steps in spec.steps order -
already the canonical pipeline order, since Spec sorts the list on
construction, so the order a caller listed them in is irrelevant - optionally
snapshots each movie stage, and finalizes. until stops after the named
stage (a step.name, e.g. "vignette"); an until that matches no
step raises rather than silently running the whole pipeline.
Pass a :class:~minisim.perf.PerfTracker as perf to record per-step (and
finalize) wall time; it is a no-op when None (the default), so an
un-profiled run pays nothing for the instrumentation.
simulate_cached#
.. py:function:: simulate_cached(spec, *, root=None) :module: minisim
Return the recording for spec, loading from cache or simulating on a miss.
:param spec: The recording spec; its :attr:~minisim.spec.Spec.cache_key
is the cache key.
:param root: Cache directory. Defaults to :func:cache_dir ($MINISIM_CACHE or
~/.cache/minisim).
.. rubric:: Notes
A hit is served by :meth:Recording.load, which re-verifies the stored spec
hash; a miss runs :func:simulate and persists the result with
:meth:Recording.save before returning it.
simulate_video#
.. py:function:: simulate_video(spec, path, *, chunk_frames=None, fps=None, vmin=0.0, vmax=None, codec=’Y800’, progress=True, perf=None) :module: minisim
Simulate spec straight to a grayscale video at path, streaming to disk.
Renders and digitizes the recording in frame chunks and writes each to an
incrementally-opened cv2.VideoWriter, so the whole movie is never held in
memory (unlike simulate(spec).observed, which is). The produced counts match
simulate(spec).observed exactly.
vmax sets the count mapped to white (vmin → black); it defaults to the
sensor’s full ADC range (2**bit_depth - 1) when the spec has a sensor
step, so the file faithfully shows the true ADC utilization (a dim, honest
frame). For a sensorless (continuous-intensity) spec there is no natural scale,
so vmax must be given. codec is a 4-character opencv fourcc; it defaults
to "Y800": uncompressed 8-bit grayscale, so the file carries the exact counts
with no compression artifacts (large: ~n_frames * H * W bytes). For a small
lossy file pass "MJPG". Writing uses opencv’s bundled ffmpeg, so no system
ffmpeg or mediapy extra is needed. Returns path.
Pass a :class:~minisim.perf.PerfTracker as perf to record where the
streamed write spends its time: the one-off setup (cell steps + footprint
build), each per-chunk render sub-phase (composite, neuropil,
motion_crop, photon_field, leakage, digitize), and the
encode+write tail. It is a no-op when None (the default).
sweep#
.. py:function:: sweep(base, axes) :module: minisim
Yield one validated SweptSpec per point in the Cartesian product of axes.
:param base: The spec every combination starts from; never mutated. :param axes: Maps a dotted override path to the list of values to sweep it over. Path forms:
* ``"acquisition.optics.na"`` - walk nested models;
* ``"steps.<kind>.<field>"`` - address the step with that (unique) ``kind``,
e.g. ``"steps.place_neurons.density_per_mm3"``;
* ``"seed"`` - a top-level field.
:Yields: SweptSpec – The base with this combination of overrides applied and all cross-field
validators re-run - an axis value that yields an invalid combination
(na=-1, a soma larger than the FOV, …) raises here. An empty axes
yields the base once with axes={}.
:raises ValueError: For a path naming an unknown field, an unknown step kind, or one that descends into a non-model (scalar) field.
.. py:pydantic_model:: SweptSpec :module: minisim :canonical: minisim.sweep.SweptSpec
Bases: :py:class:~minisim.spec.Spec
A Spec tagged with the sweep-axis values that produced it.
A genuine Spec subclass, so it drops into simulate() and Recording
unchanged. axes is excluded from serialization, so it never reaches
model_dump_json and therefore leaves :meth:Spec.cache_key identical to
the equivalent plain spec - sweeping does not perturb cache dedup, and the tag
simply vanishes when a recording is persisted.
:Fields:
- :py:obj:axes (dict) <minisim.sweep.SweptSpec.axes>
.. py:pydantic_field:: SweptSpec.axes :module: minisim :type: dict :optional:
Chosen value per swept dotted-path, for tidy benchmark rows.