Importer Development#
MRax reconstruction code is vendor-neutral. Importers are responsible for turning scanner-specific files into a small, stable contract:
a frame-major image array on
DataSet.dataan optional raw k-space array on
DataSet.kspace, sorted and corrected according to the importer contractan optional Cartesian sampling mask on
DataSet.sampling_maskmetadata on
DataSet.kspace_metadatathat explains how the raw data was sorted and which vendor reconstruction steps were applied before the data entered MRax
This separation keeps mrax.reco.pipeline and mrax.reco.variational
independent from vendor-specific file formats.
Validation status#
Importer documentation includes validation scope. The Bruker path has been tested on ParaVision 360 3.6 data. The Pulseq path supports synthetic demos and has not been validated on measured scanner data. Tests for new import paths compare array ordering, observables, and reconstruction previews against a known sequence or vendor output.
What “Reconstruction-Ready K-Space” Means#
In MRax, reconstruction-ready k-space means:
the raw samples have already been sorted into the correct logical acquisition order for the sequence
the array uses MRax’s internal axis conventions (for Cartesian 2D data:
(frame, coil?, ky, kx))vendor reco metadata that acts directly in k-space has already been applied
missing samples remain zero so the sampling pattern is still explicit
This is different from a vendor’s final display image. A vendor may still apply additional image-domain operations such as cropping, transposition, sum-of-squares coil combination, magnitude conversion, or integer storage mapping after the FFT.
The practical consequence is:
DataSet.kspaceis suitable for direct use by FFT- or model-based reconstruction codeDataSet.datacan remain the vendor image, or optionally a preview reconstruction, as long as the raw k-space path is preserved separately
Three Separate Problems#
When implementing a new importer, keep these three layers separate:
Sequence ordering#
This answers: “Which sample belongs to which frame, slice, echo, or phase-encode line?”
Examples:
Pulseq RARE/TurboSE: one shot acquires
rare_factorlines from the same slice, then the acquisition moves to the next sliceBruker multi-slice scans:
PVM_ObjOrderListmay interleave slices or packagesEPI: the readout polarity and line order can alternate
If this step is wrong, the k-space geometry itself is wrong and no later correction can repair it.
Vendor k-space corrections#
This answers: “What metadata must be applied before the FFT so the stored raw data represents the same k-space grid the vendor reconstructs from?”
Typical examples:
quadrature or conjugation flags
readout placement / partial-Fourier zero-filling
phase ramps that implement image shifts
per-channel complex scale factors
These corrections belong in DataSet.kspace because they change the encoded data,
not only the display image.
Image-domain formatting#
This answers: “How does the vendor turn FFT output into the final image written to disk?”
Typical examples:
cropping from FT size to output size
per-frame transposition
sum-of-squares coil combination
magnitude conversion
mapping float images into integer storage ranges
These steps are for vendor comparison and preview images; they are not part of the raw k-space contract.
MRax Import Pipeline#
The usual implementation pattern is:
Parse vendor metadata into a normalized description.
Infer the experiment type and observables.
Read the vendor image product if it exists (for example Bruker
2dseq).Read raw samples if present.
Sort the raw samples into a vendor-neutral k-space array.
Apply vendor k-space corrections.
Attach optional preview reconstructions and sampling masks.
Record the applied correction stages in
kspace_metadata.
Shared helpers in mrax.io.import_definitions already cover the experiment typing,
observable extraction, and generic k-space definition objects once the vendor metadata
has been normalized.
Bruker Case Study#
The Bruker importer is the current reference implementation. ParaVision metadata separates sample ordering, reconstruction parameters, and final image storage.
Sample sorting metadata#
For the currently supported Cartesian Bruker raw import path, the main ordering fields are:
PVM_EncSteps1: phase-encode step orderPVM_ObjOrderList: acquisition-to-output frame orderPVM_SPackArrNSlices: package structure for multi-package localizersPVM_RareFactor: echo train length for RARE/TurboSE
Those fields determine how MRax fills the Cartesian ky dimension and how it maps
acquisition-order slices back into natural output order.
Vendor k-space corrections applied by MRax#
For Bruker Cartesian raw data, MRax exposes public helpers in
mrax.io.bruker_import:
The importer uses these helpers internally, so load_bruker_experiment(...,
load_raw_kspace=True) stores vendor-corrected, reconstruction-ready Cartesian
k-space on DataSet.kspace.
The Bruker k-space helper applies:
RECO_qoptsreadout placement / zero-filling implied by
RECO_ft_sizeRECO_rotateas a phase ramp in k-spaceRecoScaleChanandRecoPhaseChan
The Bruker image formatter then applies:
FFT normalization adjustment
RECO_size/RECO_offsetcutoffsum-of-squares coil combination
RECO_transpositionorVisuCoreTransposition
Metadata fields that are relevant for vendor comparison but do not alter
DataSet.kspace are recorded in kspace_metadata. This includes active
filters such as RECO_pc_mode or RECO_wdw_mode.
For Bruker 2D and 3D non-Cartesian scans, the importer uses ParaVision RecoRegridN
metadata and local traj files to keep samples in the same contract as Pulseq
non-Cartesian imports. PV360 rawdata.job* files are decoded using the
ACQ_jobs block width, receiver count, and RecoSortSize/RecoSortMaps so
the final sample axis is ordered by trajectory interleave and frame. Spiral
navigator/pre/post points are discarded so the last axis of DataSet.kspace
matches the stored trajectory exactly. If ParaVision records a per-sample b0
correction in the reconstruction graph, MRax multiplies it into the retained sample
stream before applying receiver scale/phase corrections. Bruker’s density
compensation is derived from RecoRegridDensCorrFilter for the vendor-comparison
preview (radial rho weights, spiral trajDC Jacobian path when available),
while DataSet.density remains the generic trajectory-based weighting used by the
Pulseq-style NUFFT operators. The resulting metadata records the regridding
trajectory type, MRax density source, vendor density source, vendor-style regrid
options, B0 correction, points per interleave, interleave count, trimming summary,
raw storage layout, sort maps, and any unsupported vendor-only processing.
For 3D radial scans, density estimation uses the radial rho^2 convention. ZTE
scans can include ParaVision RecoInverseFidFilter profile synthesis before
regridding; MRax approximates that step by transforming the shuffled FID profiles into
the readout-frequency domain and applying the numeric readout shift before matching the
profiles to the stored trajectory. The proprietary inverse-FID regularization and
remaining FT/phase-correction details remain vendor-only metadata.
Separate scanner parsing from array operations. When a vendor step is just a numeric
k-space/readout/image operation, map the vendor
metadata to the public helpers in mrax.reco.processing or
mrax.reco.variational rather than adding importer-only array code. That keeps the
same step available to users working with Pulseq, external raw-data readers, or
synthetic arrays.
Mixed slice packages#
Not every Bruker 2D multi-slice scan is an (x, y, z) stack. Localizer-style
scans can contain multiple slice packages with different orientations. In that case,
collapsing frames into a single 3D volume destroys the geometry.
MRax therefore keeps those scans frame-major when:
VisuFGOrderDescindicatesFG_SLICEframe orientations differ across frames, or
frame transposition differs across frames
This is why some Bruker datasets remain (frame, x, y) instead of being promoted to
(1, x, y, z).
Using the Bruker helpers directly#
from mrax.io.bruker_import import (
prepare_bruker_cartesian_kspace,
reconstruct_bruker_cartesian_kspace,
parse_jcamp,
)
reco = parse_jcamp(scan_dir / "pdata" / "1" / "reco")
corrected_kspace, correction_meta = prepare_bruker_cartesian_kspace(raw_kspace, reco)
vendor_like_image = reconstruct_bruker_cartesian_kspace(
corrected_kspace,
reco,
assume_corrections_applied=True,
)
Implementing a New Vendor or Sequence#
When adding an importer, follow this checklist:
Normalize the vendor metadata into explicit experiment descriptors and observables.
Decide whether the sequence is standard Cartesian, RARE/TurboSE, EPI, or non-Cartesian, and sort raw samples accordingly.
Apply vendor metadata that changes the sampled signal before writing
DataSet.kspace.Separate image-domain display/storage operations from the raw k-space contract.
Store a concise summary of applied steps in
DataSet.kspace_metadata.Add a synthetic test for the sorting logic and validate real scanner data locally against an appropriate vendor image product.
When vendor reference code or scanner manuals are needed, keep those resources outside the public MRax repository unless their licenses permit redistribution.