dmipy
Towards a physics-complete MRI representation of the brain
dmipy — Diffusion Microstructure Imaging in Python — is the revived and expanded successor to the 2019 toolbox: now a pulse-sequence designer, a forward Monte-Carlo simulator, and an analytical fitter — one shared physics running the whole loop from the scanner to the tissue and back.
MRI scanners don't measure tissue directly — they measure a signal that a physics model turns into the numbers people read (axon density, myelin content, microstructure). But today's models — including dmipy 1.x — are each incomplete: each captures some physical effects (diffusion) while ignoring others present in the same signal (relaxation, susceptibility, surface interactions), so the numbers come out subtly and predictably biased, and most tools can't tell you when, or by how much.
dmipy is built to leave nothing out: one shared physical description of the tissue, used to explain every signal a scanner can produce — so the numbers mean what people already assume they mean.

How it works: design → run → simulate → fit, one shared physics
dmipy describes the acquisition once — a gradient waveform G(t) — and the tissue once — a
substrate of geometric compartments. Everything else is a different view of those same two objects,
so the whole measurement loop stays consistent from the scanner to the tissue and back:
- dmipy-design — the acquisition front-end: design a diffusion pulse sequence
that is deliverable under a real scanner's limits (slew, PNS, timing), and export it to a
scanner-runnable Pulseq
.seq. This is the bridge to the hardware — the exact sequence you optimise here is the one the scanner plays. - dmipy-sim — the forward truth: given that waveform and a substrate, simulate the signal from first principles by random-walking spins through the geometry — a physics-complete Monte-Carlo ground truth, no analytical shortcuts.
- dmipy-fit — the analytical inverse: from the signal, recover the tissue — multi-compartment models with T2 and surface relaxivity as composable factors, CSD and myelin-water estimation, fit on the GPU.
Because all three read the same G(t) and the same substrate, the loop is literal: you
design a deliverable sequence, run it on the scanner, simulate what it should produce on a known
substrate, and fit the acquired data with a model that is validated — effect by effect — against
that simulator. The sequence you scanned, the one you simulated, and the one you fit are one object.
Agreement is how we earn trust in the numbers.
Try it
import numpy as np
from dmipy_fit.core.acquisition_scheme import acquisition_scheme_from_bvalues
from dmipy_fit.signal_models.gaussian_models import G1Ball
from dmipy_fit.signal_models.cylinder_models import C1Stick
from dmipy_fit.core.modeling_framework import MultiCompartmentModel
# a small two-shell scheme (b-values in s/m^2 — multiply s/mm^2 by 1e6)
rng = np.random.default_rng(0)
bvals = np.r_[0.0, np.full(32, 1e9), np.full(32, 2e9)]
bvecs = np.zeros((65, 3)); v = rng.standard_normal((64, 3))
bvecs[1:] = v / np.linalg.norm(v, axis=1, keepdims=True)
scheme = acquisition_scheme_from_bvalues(bvals, bvecs, delta=0.01, Delta=0.03)
data = rng.uniform(0.1, 1.0, size=(10, 65)) # <- swap in your DWI voxels
ball_stick = MultiCompartmentModel([G1Ball(), C1Stick()])
fit = ball_stick.fit(scheme, data, solver="jax") # vmap over voxels, GPU if available
print(fit.fitted_parameters.keys())
Start here: Install → the inverse or forward quickstart → designing a deliverable sequence → the worked surface-relaxivity / myelin-water walkthrough. Coming from the 2019 toolbox? See Migrating from dmipy 1.x.
Physics is the specification
Physical laws, invariants, and known analytical results are the correctness criteria — not "the code runs". Every analytical model is validated effect-by-effect against Monte Carlo. More on the philosophy at dmrai-lab.org.