Skip to content

Raw acquisitions carry no geometry: ACQ_grad_matrix / ACQ_patient_pos / ACQ_*_offset are never read (spec 5.4, 12) #166

Description

@gdevenyi

From §6.2 ("Genuine functional gaps") of a format-conformance review against
FILE_FORMAT.md.

The gap

grep -r "ACQ_grad_matrix\|ACQ_GradientMatrix\|ACQ_patient_pos\|ACQ_slice_offset\|ACQ_read_offset\|ACQ_phase1_offset" brukerapi/
returns nothing. A fid or rawdata.jobN dataset therefore has no geometry
of any kind
: raw k-space cannot be related to anatomy without re-parsing
acqp by hand, even though every parameter needed is right there. §12's
PV5/PV6-vs-PV360 distinction is not modelled either.

With #156 a reconstructed 2dseq has a spec-correct patient-frame affine; the
acquisition side has nothing equivalent.

Proposal

Add an acquisition-side geometry derivation, mirroring the 2dseq one:

  1. Gradient → magnet. ACQ_grad_matrix[i] is a 3×3 per object, read in
    C-order (the review confirmed the order: orthonormality error 2.2e-16 in
    C-order vs 0.994 in F-order). PV360 writes ACQ_GradientMatrix, which §12
    says maps gradient → magnet directly.
  2. Magnet → patient, PV5/PV6 only: ACQ_patient_pos negates and exchanges
    gradient axes (§12 spells out each case; Foot_Supine is the identity).
    This stage must not be applied to PV360 — the pv_version property
    added in Fix the API surface: metadata groups, reports, CLI options, version gates (A5-A9, D9, D10, R7, R9, J6, J7) #164 makes that switch cheap.
  3. Offsets and spacing. ACQ_slice_offset / ACQ_read_offset /
    ACQ_phase1_offset / ACQ_phase2_offset give the object centre;
    ACQ_slice_sepn / ACQ_slice_thick and ACQ_fov give spacing and extent.
  4. API. Dataset.acquisition_affine(object=0) and
    Dataset.acquisition_affines() on fid/rawdata, returning the same
    Visu/DICOM patient frame the 2dseq affine uses, so the two are directly
    comparable. Objects are ordered by ACQ_obj_order exactly as the data is.

Acceptance test

For every experiment that also has a reconstruction, the derived first-voxel
position of object k should reproduce VisuCorePosition[k] of the matching
2dseq to within a fraction of a voxel. The review corpus offers ~1,400
fid/2dseq pairs, so this is checkable at scale rather than by inspection, and it
is the same oracle #156 was validated against.

Happy to take this on if the direction looks right.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions