Skip to main content
MRSandbox Logo

MRSandbox

A simulation sandbox for magnetic resonance spectroscopy


MRSandbox creates magnetic resonance spectra from first principles. A virtual brain provides the tissue composition at any voxel position, a virtual scanner provides the field strength and the hardware limits, and fully flexible pulse sequences probe both through a density matrix engine. Every quantity is a configurable parameter that can be fixed, sampled from literature ranges, or read from a quantitative map. The simulations are written with Keras operations and run batched and differentiable on JAX, PyTorch, and TensorFlow.

from mrsandbox import Brain, Press, Scanner, VirtualScan

brain = Brain.load("icbm152")                      # the MNI average brain, fetched once and cached
scan  = VirtualScan(brain, Scanner.preset("generic_3t"), Press(te1_s=0.011, te2_s=0.019))
data  = scan.voxel(position_mm=(10, -20, 5), size_mm=20).acquire(seed=7)    # NIfTI-MRS

MRSandbox is under active development and grows with my research. It is a personal research toolbox and interfaces are adjusted as we see fit.

Install

pip install mrsandbox

Python 3.11 or newer. JAX comes with the install as the Keras backend the physics is measured on; mrsandbox[torch] and mrsandbox[tensorflow] add the other two. Acquisitions play their spurious echoes and eddy phase through Augmentrum, which comes with the install. The console comes with mrsandbox[console], the tests, ruff and pypulseq with mrsandbox[dev]. The wheel ships no data: the measured cohorts' readings come from this repository and the large public data (the digital heads, the measured maps, the raw datasets the calibrations are read from) from their publishers, fetched on first use into ~/.cache/mrsandbox, checksum verified where the publisher states one; MRSANDBOX_CACHE moves the cache.

What it does

Every example runs as it stands after from mrsandbox import *.

# a scanner as the data know it: the Prisma's noise record, read off raw in vivo scans, comes with it
profile = ScannerProfile.preset("siemens_prisma_3t")
scan = profile.scan(brain, SemiLaser(te_s=0.026, tr_s=2.0))

# or your own scanner, replicated from one of its raw files (coils and transients apart)
mine = ScannerProfile.read("my_scan.nii.gz", scan.voxel((0, -45, 35), 20, compiled=True), "my Prisma")
mine.save("my_prisma.json")

# or a whole folder of scans at once (spectra with their water references, a T1 image, maps, a
# noise scan): the room that comes back says what every file gave, and scans as that scanner
room = replicate("my_session_folder")
scan = room.twin(SemiLaser(te_s=0.026, tr_s=2.0))
# every quantity is a parameter: fix it, draw it from a range, or read it from a map
fever = VirtualScan(brain, Scanner.preset("generic_3t"), Press(te1_s=0.011, te2_s=0.019),
                    params=Params(water=dict(temperature_c=(36.0, 40.0)), conc=dict(GABA=2.5)))
# J-difference editing emerges from the density matrix; HERMES and HERCULES ship too
gaba = Multiplex(brain, Scanner.preset("generic_3t"), MegaPress.pair(),
                 combinations={"difference": {"on": 1.0, "off": -1.0}})
stack = gaba.acquire((0, -45, 35), 30.0, seed=1)          # NIfTI-MRS on DIM_EDIT, one truth
edited = gaba.combine(stack, "difference")
# spectroscopic imaging, a phantom on the table, a stream of training data
image = scan.mrsi(center_mm=(0, -10, 35), matrix=(8, 8), voxel_mm=12.0).acquire(seed=1)
sphere = VirtualScan(Phantom.spectre(temperature_c=21.0), Scanner.preset("generic_3t"), Press(te1_s=0.011, te2_s=0.019))
batches = scan.generator((0, -45, 35), 20.0, batch_size=16, seed=0)

The data are NIfTI-MRS with the receiver's centre at 4.65 ppm. The header of every acquisition carries its ground truth: the drawn parameters, the tissue in the voxel, the calibration records in force and where the scan departs from the conditions they were measured under.

The console

The virtual scanner console: three exam cards planned and run on the QSM challenge head, the last one's spectrum live

The head is the QSM reconstruction challenge 2.0 head (Marques et al. 2021, MRM 86:526). Data were provided (in part) by the Donders Institute for Brain, Cognition and Behaviour.

uvx --from "mrsandbox[console]" mrsandbox-console

A virtual scanner console. Choose the scanner (a preset, or your own saved profile), the receive array, and who lies on the table, or bring your own anatomy, B0, and B1+ maps. Leaf through three planes, place the voxel or the MRSI grid, switch water suppression and OVS, fill the exam cards, and run them: the spectrum builds up over the transients, which come with the drift and motion of a real run. Design your own sequence from blocks, your own pulse shapes among them, and see its pulse sequence diagram and its spectrum. Open any parameter of the simulation through the gears, as a number, a range, or a map. Review the spectra beside the truth, and export what a scanner exports: the raw transients as NIfTI-MRS and the sequence as Pulseq.

Overview

flowchart LR
    subgraph values [Values]
        DB[(Database)] --> PR[Params]
    end
    subgraph world [Virtual World]
        BR[Brain<br/>Phantom]
        HW[Scanner<br/>Hardware]
        SQ[Sequences<br/>Events, Shapes, Timings]
    end
    subgraph physics [Physics]
        SP[Spins] --> EN[Engine]
        BK[Backend] --> EN
    end
    PR --> BR
    PR --> HW
    PR --> SQ
    BR --> SC[Virtual Scan<br/>Voxel]
    HW --> SC
    SQ --> SC
    SC --> EN
    EN --> OUT[[NIfTI-MRS+]]

One line per folder; the docstrings hold the rest.

  • params/ holds the parameter system: values that are fixed, drawn, per tissue, or mapped, in composable trees.
  • database/ stores literature values as cited Python dicts: concentrations, relaxation, shifts, pulses, phantoms.
  • phantom/ defines the subjects: brains with continuous tissue fractions, phantoms of solution, and the water, lipid, macromolecule, and downfield sources.
  • resources/ fetches large public datasets on first use into a checksummed cache. The wheel ships no data.
  • hardware/ describes scanners with their limits, the digital receiver, and receive arrays with their noise.
  • sequences/ builds sequences as event lists: PRESS, STEAM, semi-LASER, MEGA-PRESS, HERMES, HERCULES, water suppression, ideal or with the localization and the pulses played.
  • spins/ and engine/ hold the spin systems and run the density matrix, plain or as one compiled graph per design.
  • scan/ composes it all: VirtualScan, Voxel, MRSI, Multiplex, the training Generator, the ScannerProfile, the calibration records, and the readers that make a record from raw data.
  • io/ reads and writes Pulseq, and reads Philips (data/list, sdat/spar, lab/raw) and Varian files.
  • console/ is the virtual scanner console.
  • backend/ contains the propagator mathematics; tests/ mirrors the package and asserts the physics.

Validation

Every physical claim is gated by a test, and the simulation is checked against independent references.

  • An in-test complex128 oracle and Clarke's fsl_denmatsim (correlation above 0.9999) check the engine. The parity tests need the externals/denmatsim submodule (FMRIB's GitLab); without it they skip.
  • Shaped pulses reproduce the bandwidth products of de Graaf's Table 5.1, and analytic laws hold exactly where they should.
  • Raw in vivo data check the whole: played HERMES and HERCULES reproduce the edited spectra of two scanners of two vendors (public OpenNeuro data) without a fit.
  • Numbers calibrated on in vivo data live as records with the exact conditions of their measurement. Only quantities read off raw data enter a record, never what a fitting program reported.

Citation

MRSandbox is described in an ISMRM 2027 abstract (submitted). Until it is out, cite the repository:

Merkofer JP. MRSandbox: a simulation sandbox for magnetic resonance spectroscopy. 2026. https://github.com/julianmer/MRSandbox

Licence

MIT, see the LICENSE file.

Metadata

Release files for mrsandbox 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mrsandbox 0.1.0
File Size Uploaded Provenance Actions
mrsandbox-0.1.0.tar.gz 2.2 MB Without provenance Details for mrsandbox-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mrsandbox 0.1.0
File Interpreter ABI Platform Actions
mrsandbox-0.1.0-py3-none-any.whl Python 3 none any Details for mrsandbox-0.1.0-py3-none-any.whl

Total release size: 4.4 MB

Release files / mrsandbox-0.1.0.tar.gz

Download URL mrsandbox-0.1.0.tar.gz
Size 2.2 MB
Tags Source
SHA-256 checksum
How to use checksums
00395fb3d4e1d4bfc00a6474f9e10bb93ba9bf4823a9f7ec251af9b2cf3ef683
BLAKE2b-256 checksum
How to use checksums
b2bc1d3814f4dea11f048cfbabbaf678aa1fcb1b7a7b3fe40f51d371d02d7423
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / mrsandbox-0.1.0-py3-none-any.whl

Download URL mrsandbox-0.1.0-py3-none-any.whl
Size 2.2 MB
Tags Python 3
SHA-256 checksum
How to use checksums
93e33c1932a112b9fd3c0a1e6ffd650f25ff7a79a72baeb62bf636b4c49319b9
BLAKE2b-256 checksum
How to use checksums
0d6b0f1b0451b402dd54641df08e674d7682a01d97ffe8a2c705592fdbe6cd4c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for mrsandbox 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page