- Config name
model: inversion_recoveryBIDS suffixIRT1Method family- T1 Relaxometry Acquired volumes
- 9 Fit granularity
- voxelwise
Fits the longitudinal relaxation time T1 from a series of inversion-recovery images acquired at different inversion times. The magnitude signal is modelled as an exponential recovery with a free amplitude and offset, which together absorb imperfect inversion efficiency, so no assumption about a perfect 180° pulse is needed. T1 is recovered by a grid search over the configured range followed by a local zoom refinement.
Signal model¶
| Symbol | Quantity | Unit |
|---|---|---|
T1 | Longitudinal relaxation time | s |
a | Recovery amplitude (absorbs inversion efficiency) | — |
b | Signal offset | — |
What the model reads¶
A series of 9 volumes indexed by InversionTime. Volumes are matched to these identities by value, so reordering the acquisition yields an identical fit.
| # | InversionTime |
|---|---|
| 1 | 0.35 |
| 2 | 0.5 |
| 3 | 0.65 |
| 4 | 0.8 |
| 5 | 0.95 |
| 6 | 1.1 |
| 7 | 1.25 |
| 8 | 1.4 |
| 9 | 1.7 |
Where the protocol comes from¶
In a BIDS dataset these values are resolved for you:
| Protocol parameter | Source | Key | Resolved |
|---|---|---|---|
InversionTime | sidecar field | InversionTime | per volume |
RepetitionTime | sidecar field | RepetitionTime | whole collection |
Inputs¶

Figure 1:The 9 acquired volumes, each labeled with the identity the model reads it by.

Figure 2:Auxiliary maps and the mask applied to this fit.
Outputs¶
| Map | BIDS suffix | Unit | Fit bounds | Fitted |
|---|---|---|---|---|
T1 | T1map | s | unbounded … unbounded | free |
Diagnostic outputs
Reported by the fit but not written as BIDS derivatives: they describe the fit rather than the tissue, and have no BIDS suffix to be written under.
| Output |
|---|
b |
a |
res |
idx |

Figure 3:Fitted maps for one example subject.
Usage¶
The acquisition comes from the sidecars, so recipes/bids/irt1_config.yaml carries only algorithm options:
model: inversion_recovery
# BIDS input: InversionTime is read from the JSON sidecars via the model's
# protocol_schema(), so the inversion-time list is NOT declared here.
# Algorithm options (always used; not BIDS metadata).
method: magnitude
t1_range:
start: 0.001
stop: 5.0
step: 0.001
zoom:
iterations: 2
points: 21
# BIDS mask selection — disambiguates which mask in the dataset to apply.
mask:
desc: brainqmrust fit --bids-dir ds-mydata \
--config recipes/bids/irt1_config.yaml --output-dir outFitted maps are written as BIDS derivatives:
out/derivatives/qmrust/sub-01/anat/
sub-01_T1map.nii.gz
sub-01_T1map.jsonNo sidecars, so recipes/non-bids/irt1_config.yaml declares the acquisition itself:
model: inversion_recovery
# non-BIDS: protocol from this file; mask via --mask
# All times are in seconds (BIDS/SI).
inversion_times:
- 0.350
- 0.500
- 0.650
- 0.800
- 0.950
- 1.100
- 1.250
- 1.400
- 1.700
repetition_time: 2.5
# Algorithm options (always used; not BIDS metadata).
method: magnitude
t1_range:
start: 0.001
stop: 5.0
step: 0.001
zoom:
iterations: 2
points: 21qmrust fit --data data.nii.gz --mask mask.nii.gz \
--config recipes/non-bids/irt1_config.yaml \
--output-dir outSee Fitting without BIDS.
model: inversion_recovery
# Simulation: the acquisition comes from this file, as for every non-BIDS
# recipe. All times are in seconds (BIDS/SI).
inversion_times:
- 0.350
- 0.500
- 0.650
- 0.800
- 0.950
- 1.100
- 1.250
- 1.400
- 1.700
repetition_time: 2.5
method: magnitude
t1_range:
start: 0.001
stop: 5.0
step: 0.001
zoom:
iterations: 2
points: 21
# Ground truth: white matter at 3 T. The IR signal is a + b*exp(-TI/T1), so a
# is the recovered magnetization and b is close to -2a for a full inversion.
sim:
params: { T1: 0.9, a: 500.0, b: -1000.0 }
noise: { type: rician, snr: 100.0 }
seed: 0
trials: 100
sweep: { param: T1, start: 0.3, stop: 2.5, steps: 10 }
distributions:
T1: { mean: 0.9, std: 0.15 }qmrust sim signal --config recipes/sim/irt1_sim.yaml --output signal.json
qmrust sim single-voxel --config recipes/sim/irt1_sim.yaml --output sv.json
qmrust sim sensitivity --config recipes/sim/irt1_sim.yaml --output sens.json
qmrust sim montecarlo --config recipes/sim/irt1_sim.yaml --output mc.jsonSee Simulation.
The same core, compiled to WebAssembly:
import init, { fit_volume } from './pkg/qmrust_wasm.js';
await init();
const maps = fit_volume(configYaml, data, [nx, ny, nz, nt],
JSON.stringify(volumeIds), mask, '{}');Try it on real data in the playground, or read Browser & wasm.

Figure 4:One voxel’s measured data with the model’s forward signal at the fitted parameters. The curve is computed by the same Rust code that does the fitting.
Implementation¶
model.rs— theModelimplementation: measurement contract, protocol schema, BIDS outputs.fit.rs— the numerical fit.config.rs— configuration and validation.
Fully-resolved configuration
Every default materialized, as qmrust dump-config prints it.
model: inversion_recovery
inversion_times:
- 0.35
- 0.5
- 0.65
- 0.8
- 0.95
- 1.1
- 1.25
- 1.4
- 1.7
method: magnitude
t1_range:
start: 0.001
stop: 5.0
step: 0.001
zoom:
iterations: 2
points: 21
repetition_time: 2.5References¶
Barral et al. (2010)
- Barral, J. K., Gudmundson, E., Stikov, N., Etezadi-Amoli, M., Stoica, P., & Nishimura, D. G. (2010). A robust methodology for in vivo T1 mapping. Magnetic Resonance in Medicine, 64(4), 1057–1067.