Skip to main content

turbotwix

A fast, and opiniated, Siemens TWIX (.dat, VB and VD/VE) reader.

  • 6x faster than pymapvbvd on a full Cartesian read, and able to pull a single shot out of a 24 GiB file in a couple of milliseconds without ever loading the rest.
  • Use modern python (type annotations) and numpy structured dtype array.
  • NB: It does not implement slice-geometry parsing or ramp-sampling regridding.

Disclosure

This library is not affiliated with Siemens, and the TWIX format is not documented by them. The format has been reverse-engineered from the files and the existing implementations:

Without them, turbotwix would not exists.

Usage

import turbotwix as tw

f = tw.open_twix("meas.dat")
f  # TwixFile(..., measurements=['AdjCoilSens', 'bold_spiral...'])

lines = f.lines  # one strided read of the line headers
lines.image  # LineTable: imaging lines only
lines.noise  # noise-calibration lines, for pre-whitening
len(lines.image), lines.shape  # 4800, (44, 15000)

samples = f.read(lines.image)  # (4800, 44, 15000) complex64

f.lines, f.hdr and f.read act on the last measurement (f.scan), which is the scan itself, the measurements before it are usually calibration data you don't necessary need. They are still there, by index or by iteration:

len(f)  # 2
f[0].protocol_name  # 'AdjCoilSens'
noise = f[0].lines.noise  # a calibration measurement, explicitly

Selections are boolean queries and compose, so a partial read is just a smaller selection. Nothing else is touched on disk:

img = f.lines.image
rep0 = img[img.counter("Rep") == 0]  # one volume's shots
vol = f.read(rep0)  # (40, 44, 15000), 201 MiB
shot = f.read(img[5:6])  # one shot, whatever the file's size

lines.has(tw.Flag.REFLECT)  # any of the 64 eval-info bits, by name
lines.image.headers()  # full scan headers on demand: SliceData,
# IceProgramPara, timestamps, centre indices

Read into your own buffer to bound memory on files that do not fit in RAM. The copy goes straight from the mapped file into it, with no intermediate buffer:

buf = np.empty((len(rep0), 44, 15000), dtype=np.complex64)
for r in np.unique(img.counter("Rep")):
    sel = img[img.counter("Rep") == r]
    f.read(sel, out=buf[: len(sel)])
    ...

The header/text protocol is parsed per buffer on first access, by attribute or by key:

f.hdr.Meas.alTR[0]
f.scan.protocol_name, f.scan.patient_name

You can also use a context manager if you want:

with tw.open_twix("meas.dat") as f:
    samples = f.read(f.lines.image)

The data model

A TWIX measurement is a list of acquisition lines, each with metadata and a (ncha, ncol) block of samples. turbotwix hands you exactly that: a queryable line table, and reads that return (ncha, n_lines, ncol) — channel first, matching its on-disk order, contiguous.

You can query and filter the lines, and when you want it get a numpy array of the data you need

PMU

Physiological (ECG/pulse/respiration) data interleaved with the acquisition, if any:

pmu = f.scan.pmu  # empty if this measurement carries no PMU data
pmu.signal["ECG1"]  # normalized waveform
pmu.trigger["PULS"]  # matching boolean trigger channel
pmu.timestamp["ECG1"]  # per-sample clock, 2.5 ms ticks since midnight

Cartesian data

dense = f.read(dims=("Lin", "Par"))  # (Lin, Par, Cha, Col)

read(dims=...) raises if several lines land on the same grid position — that normally means a counter is missing from dims, not that the data wants averaging — and names the counters responsible. dims="minimal" picks the axes for you: the counters that vary, minus those the others already determine.

Correctness

turbotwix is checked against two existing readers:

they are the prior art for this format, and the ground truth tests/test_parity.py verifies against.

turbotwix vs. twixtools vs. pymapvbvd

turbotwix twixtools pymapvbvd
Language Python (numpy, mmap) Python Python/MATLAB
Full Cartesian read fastest (~6x pymapvbvd) slower slower
Partial / out-of-core read yes, mmap-backed, no full load no, reads the whole file no, reads the whole file
Line selection / query API boolean queries over a line table list of dicts struct/index based
Slice-geometry parsing no yes no
Ramp-sampling regridding no yes yes
Oversampling removal no yes yes
PMU (ECG/pulse/resp) parsing yes yes no

turbotwix trades the signal-processing conveniences (regridding, oversampling removal, geometry) for raw read speed and the ability to pull a small selection out of a file that doesn't fit in RAM. twixtools and pymapvbvd remain the more complete choice when you need those conveniences and can afford to load the full measurement.

Performance

Full read of a 234 MB Cartesian measurement, cold page cache, each library in its own process (scripts/bench_read.py):

library time (s) peak anon (MB) mmap (MB) maxrss (MB)
turbotwix 0.35 140 159 296
pymapvbvd 0.82 192 38 228
twixtools 0.69 206 41 242

The case this doesn't show is the one the design is really for: a selection out of a file far larger than RAM, where the reference readers have no choice but to assemble the whole array first. On a 24 GiB interleaved spiral measurement, turbotwix builds the line table in ~65 ms and pulls a single shot out of it in ~3 ms — pymapvbvd and twixtools have no equivalent operation, since without a k-space grid there is nothing partial to fold onto.

The methodology and where the speed comes from are in docs/implementation.md.

Known limitations

  • A measurement whose line offsets are not 8-byte aligned raises UnsupportedLayoutError.
  • Lines of differing (ncha, ncol) are tabled together but cannot be read in one call; select a single-shaped subset.
  • SYNCDATA blocks are not ADC data and never appear in the line table; PMU ones decode separately via Measurement.pmu.
  • No ramp-sampling regridding or slice-geometry parsing.
  • No oversampling removal: it is signal processing (an FFT round-trip), and along a non-Cartesian readout it is not meaningful.

Documentation

Development

uv sync                    # numpy + dev tools only
uv run pytest
uv run ruff check .
uv run ty check src
uv sync --group parity     # to also run tests/test_parity.py against real references

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

turbotwix-0.1.2.tar.gz (28.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

turbotwix-0.1.2-py3-none-any.whl (31.4 kB view details)

Uploaded Python 3

File details

Details for the file turbotwix-0.1.2.tar.gz.

File metadata

  • Download URL: turbotwix-0.1.2.tar.gz
  • Upload date:
  • Size: 28.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for turbotwix-0.1.2.tar.gz
Algorithm Hash digest
SHA256 dd0f6a21020600a031429a1cca54e215e6f6b7b3555351422f062236307dcaff
MD5 bbcf471d7f0abc7228f189f464f85067
BLAKE2b-256 84268090392a3f08ec97d5089be189ff3b8edc91964c93abb8d74daf13c22f95

See more details on using hashes here.

Provenance

The following attestation bundles were made for turbotwix-0.1.2.tar.gz:

Publisher: publish.yml on paquiteau/turbotwix

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file turbotwix-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: turbotwix-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 31.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for turbotwix-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 bafd32d182642035ddc8b9bbd0c2b4751708cef7516ab4425819bafc9437c60c
MD5 4dd405c853ffa757a1888db9e593528c
BLAKE2b-256 73f1c94a5e603059fe1a1648f71932b7d674c35fa9196a499f801e2ca9797099

See more details on using hashes here.

Provenance

The following attestation bundles were made for turbotwix-0.1.2-py3-none-any.whl:

Publisher: publish.yml on paquiteau/turbotwix

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.0

2 files

This release

0.1.2 This release

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page