Recording and ground truth#
Recording#
.. py:pydantic_model:: Recording :module: minisim :canonical: minisim.recording.Recording
Bases: :py:class:~pydantic.main.BaseModel
A complete simulated recording: the spec, the observed movie, and the truth.
observed holds the integer-valued sensor counts in a float container (per
Output.store_dtype). snapshots is populated only when
Output.save_intermediates is set, keyed by each step’s stage name;
stage() reads them.
:Fields:
- :py:obj:ground_truth (minisim.recording.GroundTruth) <minisim.recording.Recording.ground_truth>
- :py:obj:observed (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* frame, * height, * width], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)]) <minisim.recording.Recording.observed>
- :py:obj:snapshots (dict[str, xarray.core.dataarray.DataArray]) <minisim.recording.Recording.snapshots>
- :py:obj:spec (minisim.spec.Spec) <minisim.recording.Recording.spec>
.. py:pydantic_field:: Recording.spec :module: minisim :type: Spec :required:
.. py:pydantic_field:: Recording.observed :module: minisim :type: NDArray[Shape[’* frame, * height, * width’], float] :required:
.. py:pydantic_field:: Recording.ground_truth :module: minisim :type: GroundTruth :required:
.. py:pydantic_field:: Recording.snapshots :module: minisim :type: dict[str, xr.DataArray] :optional:
GroundTruth#
.. py:pydantic_model:: GroundTruth :module: minisim :canonical: minisim.recording.GroundTruth
Bases: :py:class:~pydantic.main.BaseModel
The per-recording truth: structural targets + per-cell and per-effect fields.
The planted vs observed footprint split is load-bearing: A_observed is
what CNMF can actually recover (tests match against it), while A_planted is
the ideal, optics-free target that quantifies the irreducible limit. Both are
exposed as dense (unit, height, width) arrays via properties, but neither is
stored dense:
Footprints are stored sparse, as canvas-coordinate patches in :attr:
planted(a :class:~minisim.footprint.FootprintStack); :attr:fov_offset/ :attr:fov_shapecrop them to the sensor FOV.The observed footprint is not stored at all: it is the deterministic blur
gain · (planted ⊛ Gaussian(sigma_px))of the planted one, so it is regenerated on demand from the per-unit :attr:observed_sigma_px/ :attr:observed_gainscalars. Deep cells’ observed footprints are near-full-canvas, so storing them dominated memory and disk; regenerating is bit-identical and far cheaper to keep.
Per-effect fields are None when their step is absent from the recording.
:Fields:
- :py:obj:C (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* unit, * frame], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)]) <minisim.recording.GroundTruth.C>
- :py:obj:S (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* unit, * frame], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)]) <minisim.recording.GroundTruth.S>
- :py:obj:amplitude_per_cell (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* unit], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)]) <minisim.recording.GroundTruth.amplitude_per_cell>
- :py:obj:bleaching (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* unit, * frame], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)] | None) <minisim.recording.GroundTruth.bleaching>
- :py:obj:centers_um (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* unit, 3], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)]) <minisim.recording.GroundTruth.centers_um>
- :py:obj:detectable (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* unit], numpy.bool]) <minisim.recording.GroundTruth.detectable>
- :py:obj:focal_depth_um (float | None) <minisim.recording.GroundTruth.focal_depth_um>
- :py:obj:fov_offset (tuple[int, int]) <minisim.recording.GroundTruth.fov_offset>
- :py:obj:fov_shape (tuple[int, int]) <minisim.recording.GroundTruth.fov_shape>
- :py:obj:illumination (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* height, * width], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)] | None) <minisim.recording.GroundTruth.illumination>
- :py:obj:in_focus (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* unit], numpy.bool]) <minisim.recording.GroundTruth.in_focus>
- :py:obj:leakage (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* height, * width], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)] | None) <minisim.recording.GroundTruth.leakage>
- :py:obj:neuropil_population (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* frame], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)] | None) <minisim.recording.GroundTruth.neuropil_population>
- :py:obj:neuropil_spatial (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* component, * height, * width], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)] | None) <minisim.recording.GroundTruth.neuropil_spatial>
- :py:obj:neuropil_temporal (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* component, * frame], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)] | None) <minisim.recording.GroundTruth.neuropil_temporal>
- :py:obj:observed_gain (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* unit], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)] | None) <minisim.recording.GroundTruth.observed_gain>
- :py:obj:observed_sigma_px (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* unit], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)] | None) <minisim.recording.GroundTruth.observed_sigma_px>
- :py:obj:planted (minisim.footprint.FootprintStack) <minisim.recording.GroundTruth.planted>
- :py:obj:shifts (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* frame, 2], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)] | None) <minisim.recording.GroundTruth.shifts>
- :py:obj:vignette (numpydantic.vendor.nptyping.base_meta_classes.NDArray[numpydantic.vendor.nptyping.base_meta_classes.Shape[* height, * width], (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)] | None) <minisim.recording.GroundTruth.vignette>
.. py:pydantic_field:: GroundTruth.planted :module: minisim :type: FootprintStack :required:
.. py:pydantic_field:: GroundTruth.fov_offset :module: minisim :type: tuple[int, int] :required:
.. py:pydantic_field:: GroundTruth.fov_shape :module: minisim :type: tuple[int, int] :required:
.. py:pydantic_field:: GroundTruth.observed_sigma_px :module: minisim :type: NDArray[Shape[’* unit’], float] | None :value: None
.. py:pydantic_field:: GroundTruth.observed_gain :module: minisim :type: NDArray[Shape[’* unit’], float] | None :value: None
.. py:pydantic_field:: GroundTruth.C :module: minisim :type: NDArray[Shape[’* unit, * frame’], float] :required:
.. py:pydantic_field:: GroundTruth.S :module: minisim :type: NDArray[Shape[’* unit, * frame’], float] :required:
.. py:pydantic_field:: GroundTruth.centers_um :module: minisim :type: NDArray[Shape[’* unit, 3’], float] :required:
.. py:pydantic_field:: GroundTruth.amplitude_per_cell :module: minisim :type: NDArray[Shape[’* unit’], float] :required:
.. py:pydantic_field:: GroundTruth.in_focus :module: minisim :type: NDArray[Shape[’* unit’], bool] :required:
.. py:pydantic_field:: GroundTruth.detectable :module: minisim :type: NDArray[Shape[’* unit’], bool] :required:
.. py:pydantic_field:: GroundTruth.shifts :module: minisim :type: NDArray[Shape[’* frame, 2’], float] | None :value: None
.. py:pydantic_field:: GroundTruth.illumination :module: minisim :type: NDArray[Shape[’* height, * width’], float] | None :value: None
.. py:pydantic_field:: GroundTruth.vignette :module: minisim :type: NDArray[Shape[’* height, * width’], float] | None :value: None
.. py:pydantic_field:: GroundTruth.leakage :module: minisim :type: NDArray[Shape[’* height, * width’], float] | None :value: None
.. py:pydantic_field:: GroundTruth.bleaching :module: minisim :type: NDArray[Shape[’* unit, * frame’], float] | None :value: None
.. py:pydantic_field:: GroundTruth.neuropil_temporal :module: minisim :type: NDArray[Shape[’* component, * frame’], float] | None :value: None
.. py:pydantic_field:: GroundTruth.neuropil_spatial :module: minisim :type: NDArray[Shape[’* component, * height, * width’], float] | None :value: None
.. py:pydantic_field:: GroundTruth.neuropil_population :module: minisim :type: NDArray[Shape[’* frame’], float] | None :value: None
.. py:pydantic_field:: GroundTruth.focal_depth_um :module: minisim :type: float | None :value: None
finalize#
.. py:function:: finalize(scene, spec) :module: minisim
Distill an exhausted Scene into a frozen, typed Recording.
Keeps each cell’s canvas-coordinate planted footprint (sparse) plus its
canvas-frame position rebased to the sensor FOV, drops cells left entirely in
the motion margin, records the per-unit optics scalars (so A_observed can be
regenerated rather than stored), assembles the per-cell structural truth, sets
detectable from the realized optical × illumination peak versus the sensor
noise floor, reads the per-effect fields off scene.truth, and downcasts the
working movie to Output.store_dtype for observed.