Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion brukerapi/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1577,9 +1577,10 @@ def acquisition_affines(self):
the reconstruction's ``VisuFGOrderDesc`` records; for ``NI == NSLICES``
object *k* is slice *k*.

:raise: :UnsupportedDatasetType: for anything but a 2-D or 3-D spatial
:raises UnsupportedDatasetType: for anything but a 2-D or 3-D spatial
fid/rawdata acquisition, one without a gradient matrix, or a PV360
one without a known subject position

"""
if self.type not in ("fid", "rawdata"):
raise UnsupportedDatasetType(f"an acquisition affine for {self.path}, which is not a raw acquisition,")
Expand Down
9 changes: 9 additions & 0 deletions docs/source/compatibility.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,12 @@ Data contract and limitations
``VisuCoreFrameThickness`` stays the source for the thickness (for a 3-D
acquisition that parameter is the whole slab, not a plane step). It is
available wherever ``affine_of_package`` is.
* ``Dataset.acquisition_affines()`` generates the acquisition-side equivalent
for 2-D/3-D spatial FID and rawdata datasets, one transform per 2-D slice or
one per 3-D volume. It uses the encoded matrix size rather than the raw sample
array shape and returns the same Visu/DICOM patient frame as ``affine``.
ParaVision 5.1/6/7 gradient matrices already encode the subject position;
PV360 matrices require the declared ``ACQ_patient_pos`` conversion. Method
slice-package geometry is a warning-emitting fallback for missing ``acqp``
values. Spectroscopy/CSI and incomplete or unknown geometry raise
``UnsupportedDatasetType``.
47 changes: 47 additions & 0 deletions docs/source/dataset.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,53 @@ Accessing the latter emits ``FutureWarning``; use ``raw`` or ``kspace`` for
new code. EPI and non-Cartesian PV360 jobs are intentionally not reconstructed
by ``kspace``.

.. _raw-acquisition-geometry:

Raw acquisition geometry
------------------------

Spatial FID and PV360 rawdata datasets can generate affine matrices before an
image has been reconstructed. ``acquisition_affines()`` returns one matrix per
2-D slice; ``acquisition_affine(index)`` returns a selected matrix. A 3-D
acquisition has one matrix whose third column is the partition step.

.. code-block:: python

acquisition = Dataset("path/to/fid")
affines = acquisition.acquisition_affines()
first_slice_affine = acquisition.acquisition_affine(0)

Each 4x4 matrix maps a voxel index in the image produced by Fourier transforming
the encoded k-space matrix to millimetres in the Visu/DICOM patient frame:

.. code-block:: python

patient_position = first_slice_affine @ [i, j, 0, 1]

The first two columns contain the read and phase voxel steps, the third contains
the slice or partition step, and the last column locates voxel ``(0, 0, 0)``.
This is the same patient frame used by a reconstructed 2dseq
``Dataset.affine``, so acquisition and reconstruction geometry can be compared
directly. To produce a NIfTI RAS affine, negate the patient x and y axes:

.. code-block:: python

import numpy as np

nifti_affine = np.diag([-1, -1, 1, 1]) @ first_slice_affine

Geometry is derived primarily from ``ACQ_grad_matrix``, the ``ACQ_*_offset``
values and ``ACQ_fov``. Method slice-package parameters are used as fallbacks
when acquisition parameters are absent, with a ``RuntimeWarning`` because they
are not equivalent for every ParaVision version. Spectroscopy/CSI, non-spatial
or non-2-D/3-D acquisitions, missing orientation metadata, and PV360 data with
an unknown subject position raise ``UnsupportedDatasetType``.

The returned list is indexed by physical slice, not by every acquisition
object. If echoes, repetitions, or other dimensions make ``NI`` differ from
``NSLICES``, their object-to-slice nesting can only be recovered from the
reconstruction metadata.

Metadata views
--------------

Expand Down
13 changes: 13 additions & 0 deletions docs/source/tutorials/how-to-fid.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ metadata. An explicit override is available when inference is ambiguous:

dataset = Dataset('path/to/fid', scheme_id='RADIAL')

For a 2-D or 3-D spatial acquisition, generate the geometry of the image that
a Fourier transform of the encoded k-space matrix would produce:

.. code-block:: python

slice_affines = dataset.acquisition_affines()
first_slice_affine = dataset.acquisition_affine(0)

The matrices map voxel indices to millimetres in the Visu/DICOM patient frame,
the same frame as a reconstructed 2dseq ``affine``. There is one matrix per
2-D slice and one for a 3-D volume. See :ref:`raw-acquisition-geometry` for the
coordinate convention, limitations, and NIfTI conversion.

Random-access ``mmap=True`` is currently supported for ``2dseq`` only. Load a
FID normally, then select the desired k-space array slice.

Expand Down
13 changes: 13 additions & 0 deletions docs/source/tutorials/how-to-rawdata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ metadata-reordered array. BART consumers can request its 16-axis layout:
kspace = rawdata.kspace
bart_kspace = rawdata.to_kspace(bart=True)

Generate patient-space geometry for a spatial rawdata acquisition in the same
way as for a FID:

.. code-block:: python

slice_affines = rawdata.acquisition_affines()
first_slice_affine = rawdata.acquisition_affine(0)

The declared ``ACQ_patient_pos`` is applied when converting PV360 gradient
directions to the Visu/DICOM patient frame. An unknown position raises
``UnsupportedDatasetType``. See :ref:`raw-acquisition-geometry` for the full
coordinate convention and limitations.

``rawdata.data`` is retained for compatibility and exposes the historical
decoded job layout. It emits ``FutureWarning`` because that layout differs from
FID ``data``. Prefer ``raw`` or ``kspace`` in new applications. EPI and
Expand Down