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.0.tar.gz (28.0 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.0-py3-none-any.whl (31.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: turbotwix-0.1.0.tar.gz
  • Upload date:
  • Size: 28.0 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.0.tar.gz
Algorithm Hash digest
SHA256 912f6089d5495773a0974f1f03b32e5deeab7ab30ff95b4bda227f167d570cf8
MD5 9a4212aabbcbad382d96a481e6922289
BLAKE2b-256 b15ce1a63c28f8488bab39a4991c1e3aa1bba95c17e48bb8f22e97385efc89c8

See more details on using hashes here.

Provenance

The following attestation bundles were made for turbotwix-0.1.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: turbotwix-0.1.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4663bfb3e29ccbf6cdc03f19af51b7726651b92e0ea55132f4a85de5dfd56fea
MD5 2af95a5b5a58db667f03da2f81f824c0
BLAKE2b-256 6cee69ab80a65c94411f0b9df931cb02a0e84c4ddee6ef42a695226f744095e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for turbotwix-0.1.0-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

0.1.2

2 files

0.1.1

2 files

This release

0.1.0 This release

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