Python toolkit for quantitative MRI modeling, fitting, and simulation.
Project description
qmrpy
Python toolkit for quantitative MRI (qMRI) modeling, fitting, and simulation.
Statement of need
qMRLab (MATLAB) and DECAES (Julia) provide widely used qMRI reference implementations, but integration into Python workflows can be frictional. qmrpy reimplements key models in Python with a unified API, explicit parameter naming, and reproducible tests so researchers can run model fitting and comparisons inside a single Python environment.
Scope
- Models: T1, T2, B1, QSM, noise, and simulation utilities.
- Interfaces: object-oriented models plus functional wrappers.
- Verification: parity checks for DECAES components and a broad test suite.
Installation
pip install qmrpy
If you use uv:
uv add qmrpy
Quickstart
import numpy as np
from qmrpy.models.t1.vfa_t1 import VfaT1
model = VfaT1(tr_ms=15.0, flip_angle_deg=np.array([2, 5, 10, 15]))
signal = model.forward(m0=1.0, t1_ms=1200.0)
fit = model.fit(signal)
print(fit["t1_ms"], fit["m0"])
Functional API (no object):
import numpy as np
from qmrpy import vfa_t1_fit
signal = np.array([0.02, 0.06, 0.12, 0.18], dtype=float)
fit = vfa_t1_fit(signal, flip_angle_deg=np.array([2, 5, 10, 15]), tr_ms=15.0)
print(fit["t1_ms"], fit["m0"])
EPG-corrected T2 (multi-echo spin-echo):
import numpy as np
from qmrpy.models.t2 import EpgT2
model = EpgT2(n_te=32, te_ms=10.0, t1_ms=1000.0, alpha_deg=180.0)
signal = model.forward(m0=1.0, t2_ms=80.0)
fit = model.fit(signal)
print(fit["t2_ms"], fit["m0"])
Optional B1 correction:
forward(..., b1=0.9), fit(..., b1=0.9), or fit_image(..., b1_map=...).
Functional API (EPG-corrected T2):
import numpy as np
from qmrpy import epg_t2_fit, epg_t2_forward
signal = epg_t2_forward(
m0=1.0, t2_ms=80.0, n_te=32, te_ms=10.0, t1_ms=1000.0, alpha_deg=180.0
)
fit = epg_t2_fit(signal, n_te=32, te_ms=10.0, t1_ms=1000.0, alpha_deg=180.0)
print(fit["t2_ms"], fit["m0"])
B1 mapping integration (example):
import numpy as np
from qmrpy.models.b1 import B1Dam
from qmrpy.models.t2 import EpgT2
b1_model = B1Dam(alpha_deg=60.0)
sig_b1 = b1_model.forward(m0=1.0, b1=0.9)
b1_fit = b1_model.fit(sig_b1)
t2_model = EpgT2(n_te=16, te_ms=10.0, t1_ms=1000.0, alpha_deg=180.0)
sig_t2 = t2_model.forward(m0=1.0, t2_ms=80.0, b1=b1_fit["b1_raw"])
t2_fit = t2_model.fit(sig_t2, b1=b1_fit["b1_raw"])
print(t2_fit["t2_ms"])
Use b1_map for voxel-wise correction:
t2_model.fit_image(data, b1_map=..., mask=...).
API overview
- Names use physical quantity + unit (e.g.,
t1_ms,t2_ms,flip_angle_deg). forward(**params)returns simulated signal(s).fit(signal, **kwargs)returns adictfor a single voxel.fit_image(data, mask=None, **kwargs)returns adictfor images/volumes.datashape is(..., n_obs)andmaskmatches spatial shape.
- Primary estimates use fixed keys (e.g.,
t1_ms,t2_ms,m0); auxiliaries usesnake_case.
Model modules:
qmrpy.models.t1qmrpy.models.t2qmrpy.models.b1qmrpy.models.qsmqmrpy.models.noiseqmrpy.sim
Verification highlights
DECAES parity (reference CSV)
Errors against reference CSV in tests/data (regenerate with uv run scripts/summarize_parity.py --no-qmrlab).
| reg | abs(alpha-alpha_ref) [deg] | abs(mu-mu_ref) | abs(chi2factor-chi2_ref) | max abs(dist-dist_ref) |
|---|---|---|---|---|
| none | 0 | N/A | N/A | 2.22045e-15 |
| gcv | 1.99e-10 | 4.79026e-08 | N/A | 1.12119e-06 |
| lcurve | 1.99e-10 | 0 | 1.04894e-11 | 3.29564e-12 |
| chi2 | 1.99e-10 | 5.67276e-14 | 1.28786e-14 | 4.82459e-12 |
| mdp | 1.99e-10 | 5.66938e-14 | 1.69642e-13 | 4.91318e-12 |
qMRLab parity (optional)
Requires Octave and a qMRLab checkout. The script compares qMRLab-generated signals against qmrpy fits.
QMRLAB_PATH=/path/to/qMRLab uv run scripts/verify_parity.py --model inversion_recovery
QMRLAB_PATH=/path/to/qMRLab uv run scripts/verify_qmrlab_mwf.py
QMRLAB_PATH=/path/to/qMRLab uv run scripts/sweep_qmrlab_mwf.py
Inversion Recovery (Barral, rdNLS):
| metric | abs diff |
|---|---|
| T1 (ms) | 0 |
MWF example:
| metric | abs diff |
|---|---|
| MWF (%) | 0.105 |
| T2MW (ms) | 0.127 |
| T2IEW (ms) | 0.045 |
Tests
Run the test suite:
uv run --locked -m pytest
Generate a test matrix table (output under output/, not tracked):
uv run scripts/summarize_tests.py
Development
uv sync --extra viz
uv sync --extra viz --extra dev
Citation
For JOSS submission, see paper.md and paper.bib. A Zenodo archive DOI will be added before release.
License
qmrpycore: MIT (LICENSE)- Third-party notices:
THIRD_PARTY_NOTICES.md
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qmrpy-0.6.1.tar.gz.
File metadata
- Download URL: qmrpy-0.6.1.tar.gz
- Upload date:
- Size: 264.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
39390fe652e1e9f5149ee4bc31f60fa3f46bf245f5c1c46e03ba4563ccb160ef
|
|
| MD5 |
7215ad1ba3397e7d76af491a319dfe80
|
|
| BLAKE2b-256 |
49d66b07774238c966b34a5b24b3bab48fe70ac0bf3e82ab4f9c56fca18eaf03
|
File details
Details for the file qmrpy-0.6.1-py3-none-any.whl.
File metadata
- Download URL: qmrpy-0.6.1-py3-none-any.whl
- Upload date:
- Size: 81.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3589072a0de243a4ecb810173d8125c60a87f6e5cd1df71c9012d7a87d33eb36
|
|
| MD5 |
6bbd353ff70ecadd993986a48a2844ae
|
|
| BLAKE2b-256 |
caf47d3a0c13a6080eeb3b776b5830cd623e0f7c21754966bbdd4434a4543d77
|