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.