Scene construction#

The scene layer is the mutable working state that pipeline steps read and write (canvas, movie, per-cell footprints). Most users never touch it directly; it is public so step authors and notebooks can. finalize() turns a built Scene into a Recording.

Scene#

.. py:class:: Scene(acq, rng, cells=, truth=, snapshots=, _fill=0.0, _margin_px=0, _movie=None) :module: minisim :canonical: minisim.scene.Scene

Bases: :py:class:object

The mutable working state a pipeline of steps mutates in place.

Holds the acquisition (which owns every µm↔px / s↔frame conversion), the RNG every stochastic step draws from, the movie being built, the per-cell records, the per-effect ground-truth side channel, and the optional per-stage snapshots. Unlike a Spec it is not frozen - mutation is the point.

The working movie is held in float64: effects accumulate additively and multiplicatively across ~10 steps in honest radiometric units, and only the final sensor step quantizes to integer counts. The downcast to Output.store_dtype happens in finalize(), not here.

.. py:property:: Scene.movie :module: minisim :type: ~xarray.core.dataarray.DataArray

  The working movie, materialized on first access (lazy; see fields above).

.. py:property:: Scene.has_movie :module: minisim :type: bool

  Whether a movie buffer exists yet - ``True`` once a pixel step (or a
  ``.movie`` read) has materialized it. ``finalize`` uses this to skip the
  observed-movie cast for a cell-domain-only partial build.

.. py:property:: Scene.canvas_shape :module: minisim :type: tuple[int, int]

  The tissue-canvas ``(height, width)`` **without** materializing the movie.

  Equals the movie's spatial shape once one exists (so a hand-set oversized
  canvas is honored); otherwise the sensor FOV padded by the motion margin.
  Lets cell-domain steps (``place_neurons``, ``optics``) size their grid
  without forcing the buffer into existence.

.. py:method:: Scene.zeros(acq, rng=None, margin_px=0) :module: minisim :classmethod:

  A blank scene whose movie is all zeros - the base for additive builds.

.. py:method:: Scene.ones(acq, rng=None, margin_px=0) :module: minisim :classmethod:

  A scene whose movie is all ones - the substrate for multiplicative-field tests.

  A ``vignette`` or ``leakage`` step applied to an all-ones movie yields the
  bare field, which is exactly what a single-step test inspects.

Cell#

.. py:class:: Cell(center_um, footprint_planted=None, observed_sigma_px=None, observed_gain=None, trace=None, spikes=None, amplitude=None, bleach=None, in_focus=None, optical_brightness=None, detectable=None) :module: minisim :canonical: minisim.scene.Cell

Bases: :py:class:object

One simulated neuron - the per-cell record steps fill in, pre-composite.

The fields mirror the per-cell structural columns of the eventual GroundTruth output one-for-one, so finalize() can stack them with no remapping. Each is populated by the step that owns it and is None until then:

  • center_um - set by place_neurons (the cell exists once it has a location). Placement is now purely spatial; brightness is not set here.

  • footprint_planted - the sharp, peak-normalized soma mask, also from place_neurons; the ideal CNMF target.

  • trace / spikes / amplitude - the noise-free calcium trace C, spike train S, and the per-cell brightness/expression gain that scales the whole trace, all from cell_activity. The gain is biology (how much fluorescence this cell emits per spike); measurement noise, and hence any SNR, emerges later from optics and sensor, not here.

  • bleach - the intact-fluorophore envelope B(t) from the optional bleaching step; composite emits trace · bleach, leaving trace the clean calcium. None until/unless bleaching runs.

  • observed_sigma_px / observed_gain / in_focus / optical_brightness - from the optics step. The observed (optically degraded) footprint is not stored: it is a deterministic function gain · (planted Gaussian(sigma_px)) of the planted footprint (see :func:minisim.footprint.degrade_footprint), so the optics step keeps only the two scalars and composite / GroundTruth.A_observed regenerate the footprint on demand. in_focus is the geometric in-focus flag and optical_brightness the depth-driven peak-brightness scalar.

  • detectable is not an optics-only property and so is not set by the optics step: it is a whole-pipeline flag (optical brightness × illumination falloff, judged against the sensor noise floor) assembled in finalize().

center_um is (z, y, x) in µm (depth first); pixel coordinates are a conversion away via acq.um_to_px and are not stored, to avoid drift.

.. py:method:: Cell.observed_footprint() :module: minisim

  The optically degraded footprint, regenerated from the planted one.

  Returns the planted footprint blurred + dimmed by the optics step's
  scalars (``observed_sigma_px``/``observed_gain``), or the planted footprint
  unchanged when the optics step has not run, or ``None`` if the cell has no
  footprint yet. Regenerated, not stored: it is a deterministic function of
  the planted footprint (see :func:`minisim.footprint.degrade_footprint`),
  and deep cells' observed footprints are near-full-canvas, so storing them
  would dominate memory. ``composite`` and ``GroundTruth.A_observed`` call this.

GroundTruthBuilder#

.. py:class:: GroundTruthBuilder(shifts=None, illumination=None, vignette=None, leakage=None, neuropil_temporal=None, neuropil_spatial=None, neuropil_population=None, focal_depth_um=None) :module: minisim :canonical: minisim.scene.GroundTruthBuilder

Bases: :py:class:object

Per-effect ground-truth side channel - each non-cell step writes its own.

The per-cell truth lives on :attr:Scene.cells; this accumulator holds the per-effect fields that have no natural per-cell home. Each is None until the step that produces it runs, so a None value is the honest signal that the effect is absent from this recording:

  • shifts - rigid (dy, dx) per frame, from brain_motion.

  • illumination / vignette / leakage - the static (height, width) optical fields (excitation falloff, collection falloff, additive glow).

  • neuropil_temporal / neuropil_spatial - the diffuse-background components; neuropil_population - the (frame,) population driver that modulates them (None when no cells were active to drive it).

The steps that fill these slots live in :mod:minisim.steps, and finalize() reads them into the frozen GroundTruth.