Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

logo

# Requires Python 3.9 or higher
pip install MRzeroCore

MR-zero is a framework for easy MRI sequence optimization and development of self-learning sequence development strategies. The vision is documented in this paper. These goals are backed by a modern Bloch simulation (see this paper). More material can be found in the literature.

Quick start

For a quick introduction, look at the MR-zero Playground!

An ever growing collection of Jupyter Notebook demonstrate core capabilities of MR-zero. These notebooks run on Google Colab - directly in your browser, no installation needed!

Alternatively, install MR-zero Core locally:

# Requires Python 3.9 or higher
pip install MRzeroCore

Simulate any Pulseq sequence in one line

MR-zero makes MRI sequence simulation easy - just one line for simulating .seq files:

import MRzeroCore as mr0

# That's it - automatic phantom download and simulation!
signal, ktraj_adc = mr0.util.simulate('your_sequence.seq')

Even simpler with PyPulseq - no need to worry about writing .seq files:

import pypulseq as pp
# Create sequence with PyPulseq
seq = build_your_sequence()
# ... build sequence ...
signal, ktraj_adc = mr0.util.simulate(seq)
# ... reconstruct, e.g.: with a NUFFT of signal and ktraj_adc

Further documentation

MR-zero uses PyTorch for computation, enabling GPU compute automatic differentiation with backpropagation. This means you can easily develop your own loss functions, sequence building code and more - and then optimize any input parameters efficiently with gradient descent. In the example above, this could mean to simply extend build_your_sequence() by sequence parameters like flip angles and writing an image based loss function for the reconstruction. Then you can lie back and let the computer find the best pulse train.

How this can be done will be explained in the following pages, where this documentation lists the most important ideas and applications of MR-zero. If you think that something is missing or misleading, pleas open an issue on GitHub or directly via the button on the top right on every documentation page.

Playground

Welcome to Playground MR0, a playground to share, vary and simulate MR sequences. MR sequences are written in the Pulseq standard using the pypulseq library. Pulseq files are simulated with the efficient Phase Distribution Graph Bloch simulation. Here we share links to example colabs that contain various MR sequences or let you upload your own seq file for simulation.

Many of the examples are build using PyPulseq and simulate the resulting .seq files with MR0. These .seq files could also be measured on any MRI scanner using a Pulseq interpreter.

Code and simulate PyPulseq

Notebook
Free Induction Decaymr0_FID_seq.ipynb
Spin Echo CPMGmr0_SE_CPMG_seq.ipynb
Stimulated Echo 3 pulses - 5 echoesmr0_STE_3pulses_5echoes_seq.ipynb
FLASH 2D sequencemr0_FLASH_2D_seq.ipynb
GRE EPI 2D sequencemr0_EPI_2D_seq.ipynb
DWI SE EPI 2D sequencemr0_DWI_SE_EPI.ipynb
Diffusion prepared STEAMmr0_diffusion_prep_STEAM_2D_seq.ipynb
RARE 2D sequencemr0_RARE_2D_seq.ipynb
TSE 2D sequencemr0_TSE_2D_multi_shot_seq.ipynb
Interactive GRE to FLASHmr0_GRE_to_FLASH.ipynb
balanced SSFP sequencemr0_bSSFP_2D_seq.ipynb
DREAM STE for B0, B1, TxRx mappingmr0_DREAM_STE_seq.ipynb
DREAM STID for B0, B1, TxRx mappingmr0_DREAM_STID_seq.ipynb
Pulseq with RF shimmingpulseq_rf_shim.ipynb

Plot and simulate predifined .seq files

Notebook
Simulate pypulseq example sequencesmr0_pypulseq_exmpls_seq.ipynb
Simulate own uploaded seq filesmr0_upload_seq.ipynb

MR-zero optimization

Gradient descent optimizations using automatic differentiation by backpropagation. Some notebooks use pulseq-zero for optimizable sequence definitions with PyPulseq.

Notebook
IR FLASH 2D sequence for T1 mapping using a fitmr0_opt_FLASH_2D_IR_Fit_T1.ipynb
IR FLASH 2D sequence for T1 mapping using a NNmr0_opt_FLASH_2D_IR_voxelNN_T1.ipynb
FLASH flip angle opt. for PSF (with pulseq-zero)Pulseq_zero_FLASH_FAopt_PSFtask.ipynb
TSE flip angle opt. for SAR (with pulseq-zero)Pulseq_zero_TSE_FAopt_SARtask.ipynb
DESC with pulseq-zeropulseq_zero_DESC_demo.ipynb

MR-double-zero optimization

Gradient-free optimization with nevergrad

Notebook
Ernst angle optimizationmr00_FLASH_2D_ernstAngle_opt.ipynb

MR plot wall of fame

famous historic plots recreated

MR0 example notebooks

The following sequences are examples of how to realize various tasks in MR-zero rather than demonstrations of specific MRI sequences.

Notebook
Pure MR0 FLASHflash.ipynb
pulseq FLASHpulseq_flash.ipynb
pulseq pTx FLASHpulseq_sim_pTx.ipynb

Integration

MRI simulations are usually not used in isolation. Instead, simulated sequences are written with various tools, optimized flip angle trains are measured, quantified phantoms are viewed in different programs. The following chapters list currently existing integrations with MR-zero and show how to utilize them.

Pulseq Integration

MRzero Core provides seamless integration with the Pulseq standard, making it easy to simulate any Pulseq sequence file in just one line of code.

Get Started Immediately

Simplest possible - one line simulation:

import MRzeroCore as mr0

# That's it - simulate any .seq file with automatic phantom download!
signal, ktraj_adc = mr0.util.simulate(seq)  # Downloads standard phantom if not found

seq.plot(plot_now=False)
mr0.util.insert_signal_plot(seq=seq, signal =signal.numpy())  # show sequence plots with simulated signals inserted in ADC plot.
plt.show()

Full control with prepass-mainpass:

import MRzeroCore as mr0
obj_p = mr0.VoxelGridPhantom.brainweb('subject05.npz') #load a phantom object from file
obj_p = obj_p.interpolate(64, 64, 32).slices([15])
obj_p = obj_p.build()

seq0 = mr0.Sequence.import_file('your_sequence.se')  # Read in the Pulseq seq file

graph = mr0.compute_graph(seq0, obj_p, 2000, 1e-4)  # pre-pass
signal = mr0.execute_graph(graph, seq0, obj_p, print_progress=False) # main-pass

seq.plot(plot_now=False)
mr0.util.insert_signal_plot(seq=seq, signal =signal.numpy())
plt.show()

Try now: mr0_upload_seq.ipynb

Simplified Workflows

Utily functions

MRzero now includes streamlined utility functions for common simulation tasks:

  1. One line - automatic everything
    # Quickest 2D brain phantom simulation 
    signal, ktraj_adc = mr0.util.simulate(seq)  # Downloads standard phantom automatically
    
  2. Two lines - custom phantom parameters
    # Quick 2D brain phantom sim with modifications
    obj = mr0.util.load_phantom([128,128], B0_polynomial=(0,0,-150,1,1,0))  # Custom B0 map
    signal, ktraj_adc = mr0.util.simulate(seq, obj)
    
  3. Three lines - full control
    # Custom phantom from URL/file with arbitrary modifications and high accuracy
    obj = mr0.util.load_phantom([128,128], B0_polynomial=(0,0,-150,1,1,0), url='numerical_brain_cropped.mat')  
    obj.B1 = obj.B1**3     # Very inhomogeneous B1+ field
    signal, ktraj_adc = mr0.util.simulate(seq, obj, accuracy=1e-5)
    

Direct PyPulseq Integration

import pypulseq as pp

# Create sequence with PyPulseq
seq = pp.Sequence()
# ... build sequence ...

# Simulate directly - no need to write/read .seq file!
signal, ktraj_adc = mr0.util.simulate(seq)  # seq can be PyPulseq object

For MATLAB Pulseq Users

See MATLAB integration

Examples - Ready-to-run in Google Colab

NotebookComplexity
Simulate own uploaded seq filesBeginnermr0_upload_seq.ipynb
FLASH 2D sequenceBeginnermr0_FLASH_2D_seq.ipynb
GRE EPI 2D sequenceIntermediatemr0_EPI_2D_seq.ipynb
DWI SE EPI 2D sequenceAdvancedmr0_DWI_SE_EPI.ipynb
TSE 2D sequenceAdvancedmr0_TSE_2D_multi_shot_seq.ipynb

Browse All 20+ Examples →

Further Features

Visualization


# Plot PyPulseq sequence plot with MR-zero signals
seq.plot(plot_now=False)
mr0.util.insert_signal_plot(seq=seq, signal =signal.numpy())
plt.show()

# Plot the detected k-space used by MR-zero
seq.plot_kspace_trajectory()

#Plot the phase distribution graph
graph = mr0.compute_graph(seq0, obj_p, 2000, 1e-4)  # pre-pass
graph.plot()

Simulation

# Simple simulation
signal = mr0.util.simulate(seq)

# With custom phantom
phantom = mr0.util.load_phantom(size=(64, 64))
signal, kspace = mr0.util.simulate(seq, phantom)

Getting Help

Quick help:

MATLAB Pulseq ↔ MR-zero Integration Guide

This guide shows how to seamlessly integrate MATLAB Pulseq with Python MR-zero for powerful sequence development and simulation workflows.

Quick Start for MATLAB Users

Already have MATLAB Pulseq sequences? Get started in 3 steps:

  1. Export your sequence: seq.write('my_sequence.seq') in MATLAB
  2. Upload to Colab: Use our (mr0_upload_seq.ipynb )
  3. Simulate instantly: No Python installation required!

Integration Workflows

Workflow 1: MATLAB seq creation → Python Simulation

Use Case: Leverage MR-zero’s fast simulation while keeping your MATLAB development workflow

% In MATLAB: Create your sequence as usual
seq = mr.Sequence();
% ... build your sequence ...
seq.write('my_flash.seq');

Then switch to python and load the seq file.

# In Python/Colab: Simulate with one line
import MRzeroCore as mr0
seq = mr0.Sequence.import_file('my_flash.seq')
signal = mr0.util.simulate(seq)

You can just upload your seq file in mr0_upload_seq.ipynb

Workflow 2: MATLAB seq creation → Call Python from Matlab using sys command

see Pulseq demo simMR0


Need Help? Try our interactive examples first, or check the GitHub issues for community support.

Pulseq-zero

Frequently asked questions

Common questions and solutions for MRzero Core and Pulseq integration.

What’s the easiest way to simulate a sequence?

A: Code and export your sequence as Pulseq file. One line:

import MRzeroCore as mr0

# Automatic phantom download and simulation
signal, ktraj_adc = mr0.util.simulate('your_sequence.seq')

For complete Pulseq integration features, see: Pulseq Integration Guide →

Can I simulate PyPulseq sequences directly without writing .seq files?

A: Yes! This is new functionality:

import pypulseq as pp
import MRzeroCore as mr0

# Create sequence with PyPulseq
seq = pp.Sequence()
# ... build sequence ...

# Simulate directly - no .seq file needed!
signal, ktraj_adc = mr0.util.simulate(seq)  # seq is PyPulseq object

Note, this is will still generate a temporary seq file. For avoiding seq files completely, check out Pulseq-zero

How do I use custom phantoms with B0 field modifications?

A:

# Load phantom with polynomial B0 augmentation
obj = mr0.util.load_phantom(
    [128, 128], 
    B0_polynomial=(0, 0, -150, 1, 1, 0),  # (const, lin_x, lin_y, quad_x, quad_y, quad_xy)
    url='numerical_brain_cropped.mat'     # Custom phantom URL or local file
)

# Further customize
obj.B1 = obj.B1**3     # Inhomogeneous B1+ field
obj.T2 = 80e-3         # Custom relaxation times

# High-accuracy simulation
signal, ktraj_adc = mr0.util.simulate(seq, obj, accuracy=1e-5)

Does MRzero support ISMRMRD raw data format?

A: Current status: ISMRMRD raw data support is not yet available, but development is underway as a first pull request exists. So it can be expected in upcoming releases. Stay updated:

My .seq file won’t load / import fails

A: Pulseq 1.4.2 is used and tested by us the most. Pulseq 1.3 and 1.5 should work too, but might need some different load and plot functions.

See also in the comments in mr0_upload_seq.ipynb

Getting version compatibility errors

A: Most issues are resolved by:

  • Using matching Pulseq versions between creation and simulation
  • Updating to latest MRzeroCore: pip install --upgrade MRzeroCore
  • Checking GitHub Issues for known compatibility problems

Simulation is too slow / runs out of memory

A: Reduce sequence resolution, go to single slice, reduce phantom resolution, reduce accuracy.

# Reduce phantom size for testing
phantom = mr0.util.load_phantom(size=(32, 32))  # Instead of (128, 128)

# Reduce simulation accuracy for speed
signal = mr0.util.simulate(seq, accuracy=1e-2)  # Default: 1e-3

# Use smaller sequence for testing
# Remove unnecessary repetitions during development

GPU not being used / CUDA errors

A:

import torch
print(f"CUDA available: {torch.cuda.is_available()}")
print(f"CUDA device: {torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'None'}")

# MR-zero uses GPU when seq0 and obj is using cuda
```python
graph = mr0.compute_graph(seq0, obj, 200, 1e-4)
# Minimum emitted and latent signal of 0.01 (compared per repetition to strongest state)
signal = mr0.execute_graph(graph, seq0.cuda(), obj.cuda(), 0.01, 0.01)

How does MRzero handle slice-selective pulses?

A: Current limitation: MRzero uses instantaneous pulses and currently ignores slice selection gradients. This means:

# In PyPulseq - slice selective pulse
rf, gz, gzr = pp.make_sinc_pulse(
    flip_angle=90*np.pi/180, 
    slice_thickness=5e-3,  # This is ignored in MRzero
    duration=1e-3
)

To have correct gradient behavior (spoiling, diffusion), our interpreter puts the instantanoues pulse in the center of the pulse, and correctly plays out the gradients. Thus, if you have assymetric pulses, you have to be careful, and better replace them by block pulses.

Workarounds:

  1. For 2D simulations: Use thin phantom slices to approximate slice selection
  2. For comparison with Scans: Consider this limitation when comparing to real measurements, apparent flip angles might be smaller due to slice profile effects.

How do I choose the right accuracy parameter?

A: The accuracy parameter controls simulation precision vs speed. When in doubt rerun with higher accuracy.

# High accuracy (slow, precise)
signal = mr0.util.simulate(seq, accuracy=1e-8)  # Research-quality

# Fast accuracy (quick testing)
signal = mr0.util.simulate(seq, accuracy=1e-2)  # Development/testing

# Very fast (rough estimates)
signal = mr0.util.simulate(seq, accuracy=1e-1)  # Initial debugging only

What does the accuracy parameter actually control?

A: It sets the min_emitted_signal and min_latent_signal thresholds in the PDG simulation:

  • Lower values = more computation but higher precision
  • Higher values = faster simulation but potential artifacts
  • For sequences with small signals (like multi-echo), use lower values

Does MRzero support magnetization transfer effects?

A: Current status: MRzero currently does not model MT effects. The simulation assumes:

  • Single pool (free water) only
  • No bound pool interactions
  • No MT saturation effects

How accurate is diffusion simulation in MRzero?

A: MRzero handles currently only isotropic diffusion, using the EPG equations from Weigel et al.:

How are relaxation times handled?

A:

# Set realistic values in phantom
phantom.T1 = 1.0    # seconds
phantom.T2 = 80e-3  # seconds  
phantom.T2dash = 50e-3  # T2' dephasing effects with 1/T2* = 1/T2 + 1/T2'

# All relaxation effects are included in simulation
# including T2* decay during readout

Tips:

  • Use literature values for tissue types
  • T2’ does NOT include intravoxel B0 inhomogeneity effects, this can be achieved by high enough B0 map resolution.

Sequence created in MATLAB doesn’t work in Python

A: Check Pulseq version compatibility

# Try different import approaches
seq = mr0.Sequence.import_file('file.seq')  # Standard since Pulseq 1.4, shoudl work for 1.5
seq = mr0.Sequence.from_seq_file('file.seq')  # Alternative for Pulseq 1.3 

Resources:

Still stuck? Try the interactive examples first - they solve most common issues!

Caution

This document might be outdated. We definitely should include NIfTI Phantoms here

Generating Phantoms

Phantoms are built from BrainWeb data. This data is not included directly. Instead, a BrainWeb downloader is part of mr0, that can be run once to download all segmentation data provided by BrainWeb, which is then filled to produce files that can be loaded as mentioned here.

Phantoms can be generated with different configurations, depending on the use-case, like 3T or 7T data, high-res, or whether to include fat are options. A fixed set of configuartions facilitates reproducibility. To execute generation, just use mr0.generate_brainweb_phantoms:

import MRzeroCore as mr0

mr0.generate_brainweb_phantoms("output/brainweb", "3T")

Loading predefined 2D or 3D phantoms

We have some phantoms predefined.

A simple 2D brain phantom as .mat file, 3T (PD,T1,T2, dB0, rB1, no T2’, no Diffusion)

!wget https://github.com/MRsources/MRzero-Core/raw/main/documentation/playground_mr0/numerical_brain_cropped.mat &> /dev/null

This can be loaded and modified via mr0.VoxelGridPhantom.load_mat():

obj_p = mr0.VoxelGridPhantom.load_mat('numerical_brain_cropped.mat')
brain_phantom_res = 64 #@param {type:"slider", min:16, max:128, step:16}
obj_p = obj_p.interpolate(brain_phantom_res, brain_phantom_res, 1)
obj_p.B0[:] = 0
# obj_p.D[:] = 0
obj_p = obj_p.build()

A filled brainweb phantom 3T (PD,T1,T2, dB0, rB1, T2’, Diffusion)

!wget https://github.com/MRsources/MRzero-Core/raw/main/documentation/playground_mr0/subject05.npz &> /dev/null

This can be loaded and modified via mr0.VoxelGridPhantom.brainweb():

sz = [64, 64]
# (i) load a phantom object from file
obj_p = mr0.VoxelGridPhantom.brainweb('subject05.npz')
obj_p = obj_p.interpolate(sz[0], sz[1], 32).slices([15])
obj_p.size[2]=0.08

if 1: # insert rectangular "Tumor" in the diffusion map
# typical brain tumor ADC values are around ~1.5 * 10^-3 mm^2/s,
# which lies between GM/WM and CSF (https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3000221)
# mr0 uses D in units of 10^-3 * mm ^2/s  this is the same as µm^2/ms
    # construct tumor border region
    for ii in range(15, 25):
        for jj in range(15, 25):
            obj_p.D[ii, jj] = torch.tensor(0.75)

    # construct tumor filling
    for ii in range(16, 24):
        for jj in range(16, 24):
            obj_p.D[ii, jj] = torch.tensor(1.5)

# Store PD and B0 for comparison
D = obj_p.D
B0 = obj_p.B0
D=obj_p.D
obj_p.plot()
# Convert Phantom into simulation data, this is sparse, and cannot be plotted directly, see obj_p.recover()
obj_p = obj_p.build()

A simple voxel phantom via mr0.CustomVoxelPhantom():

For a single voxel:

obj_p = mr0.CustomVoxelPhantom(
    pos=[[-0.25, -0.25, 0]],
    PD=[1.0],
    T1=[3.0],
    T2=[0.5],
    T2dash=[30e-3],
    D=[0.0],
    B0=0,
    voxel_size=0.1,
    voxel_shape="box"
)

For a more complex structure, her an L-shape:

obj_p = mr0.CustomVoxelPhantom(
    pos=[[-0.4, -0.4, 0], [-0.4, -0.2, 0],
         [-0.3, -0.2, 0], [-0.2, -0.2, 0], [-0.1, -0.2, 0]],
    PD=[1.0, 1.0, 0.5, 0.5, 0.5],
    T1=[1.0, 0.5, 0.5, 0.5, 2],
    T2=0.1,
    T2dash=0.1,
    D=0.0,
    B0=0,
    voxel_size=0.1,
    voxel_shape="box"
)
.. autofunction:: MRzeroCore.phantom.brainweb.generate_brainweb_phantoms

State selection

Documentation on PDG State Parameters and Configuration

Overview

The Phase Distribution Graph (PDG) states are frequently initialized with default parameters. This document outlines the essential considerations and configurations required for optimal performance, especially when dealing with exotic sequences.

Standard PDG Configuration

Typically, PDG states are invoked using the following standard parameters:

graph = mr0.compute_graph(seq0, obj_ph)
signal = mr0.execute_graph(graph, seq0, obj_ph)

The standard values used then are here written explicitly:

graph = mr0.compute_graph(seq0, obj_ph, max_state_count=200, min_state_mag=0.0001)
signal = mr0.execute_graph(graph, seq0, obj_ph, min_emitted_signal=0.01, min_latent_signal=0.01)

Importance of State Selection Thresholds

For arbitrary sequences, careful examination of state selection is crucial. This process remains important for all users employing PDG for scientific purposes.

As outlined in the main paper, there are four main parameters to adjust:

  1. Threshold Number of States (max_state_count)
  2. Threshold Magnetization (min_state_mag)
  3. Threshold Emitted Signal (min_emitted_signal)
  4. Threshold Latent Signal (min_latent_signal)

To resolve issues of inaccurate simulations one can adjust the parameters as follows to get a more accurate simulation:

graph = mr0.compute_graph(seq0, obj_ph, max_state_count=5000, min_state_mag=1e-12)
signal = mr0.execute_graph(graph, seq0, obj_ph, min_emitted_signal=0.001, min_latent_signal=0.001)

This adjustment will result in a longer simulation duration, but more accurate results

We recommend periodically validating results with more precise simulations.

Each sequence may require unique adjustments to balance simulation speed and accuracy. It’s often beneficial to start with a higher state count for a more accurate baseline.

For sequences with poor timing or spoiling, state explosion can occur (Hennig 1991). The state selection thresholds will filter out these states, potentially leading to inaccurate simulation results.

API overview

All available functions (snake_case naming) / classes (CamelCase) are listed here. In the following pages, more information is listed. For detailed descriptions of each items, look at their Python docstrings (as written in the source code or shown by your Python IDE) as well.


import MRzeroCore as mr0

MRI Sequence definitions

The MRzeroCore Sequence is a Python list of Repetitions, each of which is starting with an instantaneous Pulse. To construct sequences, you can

import MRzeroCore as mr0
import numpy as np

seq = mr0.Sequence()

# Iterate over the repetitions
for i in range(64):
    rep = seq.new_rep(2 + 64 + 2)
    
    # Set the pulse
    rep.pulse.usage = mr0.PulseUsage.EXCIT
    rep.pulse.angle = 5 * np.pi/180
    rep.pulse.phase = i**2 * 117*np.pi/180

    # Set encoding
    rep.gradm[:, :] = ...

    # Set timing
    rep.event_time[:] = ...

    # Set ADC
    rep.adc_usage[2:-2] = 1
    rep.adc_phase[2:-2] = np.pi - rep.pulse.phase

Sequence

Defines an MRI sequence. Derived from a Python list.

Sequence(repetitions, normlized_grads=True)
ParameterDescription
repetitionIterable over Repetitions to initialize the list
normalize_gradsIf set, simulation will scale gradients to match the phantom size. Simplifies writing sequences by assuming a FOV of 1.
  • Sequence.cpu(): move sequence data to CPU
  • Sequence.cuda(device=None): move sequence data to selected or default CUDA device
  • Sequence.device (property): the device of the repetition data
  • Sequence.clone(): make a copy of the repetition with cloned
  • Sequence.new_rep(event_count): appends a Repetition.zero(event_count) to the sequence
  • Sequence.get_kspace(): Returns the kspace trajectory of the measured signal as a single tensor (ADC events only, concatenated repetitions)
  • Sequence.get_full_kspace(): Returns the full kspace trajectory as a list of per-repetition tensors (containing all events)
  • Sequence.plot_kspace_trajectory(): Plot the result of get_full_kspace()
  • Sequence.get_contrast_mask(contrast): Returns a bool mask for the selected contrast which can be applied to the simulated signal or kspace
  • Sequence.get_contrasts(): Returns a list of all used contrast IDs (apply for all repetitions)
  • Sequence.shift_contrasts(offset): Shift all contrast IDs by offset (apply for all repetitions)
  • get_duration(): Return the total duration of the sequence in seconds

Sequences can be imported from Pulseq .seq files or Siemens .dsv files:

Sequence.import_file(file_name, exact_trajectories, print_stats, default_shim, ref_voltage, resolution)
ParameterDescription
file_namePath to .seq file or .dsv folder + file stem
exact_trajectoriesIf true generates more events for accurate diffusion calculation
print_statsPrint more information during import
default_shimshim_array for pulses that don’t specify it themselves
ref_voltage.dsv only: used to convert volts to RF amplitudes
resolution.dsv only: defines samples per ADC block. If not set, this is determined by the .dsv time step + ADC duration.

chain

Helper function to combine multiple sequences into a multi-contrast sequence.

chain(*sequences, oneshot=False)

Returns a new sequence object. If oneshot is set to:

  • True, sequences are simply concatenated.
  • False, the adc_usages are shifted so that every sub-sequence has their own set of IDs.

Repetition

Part of a Sequence, containing an RF pulse and a list of event_count events.

Repetition(pulse: Pulse, event_time, gradm, adc_phase, adc_usage)
ParameterDescription
pulseThe pulse at the start of the repetition
event_timeShape [event_time]: Durations in seconds
gradmShape [event_time, 3]: Gradient moments in 1/m
adc_phaseShape [event_time]: ADC phases in radians
adc_usageShape [event_time]: 0/1 = ADC off/on, other values can be used to distinguish images in multi-contrast sequences
  • Repetition.event_count (property): number of events in this repetition
  • Repetition.cpu(): move repetition data to CPU
  • Repetition.cuda(device=None): move repetition data to selected or default CUDA device
  • Repetition.device (property): the device of the repetition data
  • Repetition.zero(event_count): create a zero’d repetition with the given number of events
  • Repetition.clone(): make a copy of the repetition with cloned
  • Repetition.get_contrasts(): return a list of all used adc_usage values (except zero)
  • Repetition.shift_contrasts(offset): add offset to all adc_usage values (except zero)

Pulse

Contains the definition of an instantaneous RF Pulse.

Pulse(usage: PulseUsage, angle, phase, shim_array, selective)
ParameterDescription
usagePulseUsage - not used in simulation
angle, phaseValues in radians
shim_arrayChannel amplitudes and phases for pTx - use [[1, 0]] for 1Tx
selectiveUsed by legacy exporters to emit slice-selective pulses
  • Pulse.cpu(): move pulse data to CPU
  • Pulse.cuda(device=None): move pulse data to selected or default CUDA device
  • Pulse.device (property): the device of the pulse data
  • Pulse.zero(): alternative constructor which zero-initializes everything
  • Pulse.clone(): make a copy of the pulse with cloned

PulseUsage

Used for computing the k-space trajectory or to select the pulse type in legacy exporters.

AttributeValueDescription
UNDEF"undefined"No specified use case.
EXCIT"excitation"Will set the kspace position back to zero or the position stored by the last STORE pulse.
REFOC"refocussing"Mirrors the kspace position.
STORE"storing"Stores the current kspace position. Can be used for DREAM-like sequences.
FATSAT"fatsaturation"Not handled differently by get_kspace(), but can be used by Pulseq exporters to emit a fat-saturation pulse.

Simulation Phantoms

Phantoms based on BrainWeb data can be downloaded and generated easily, as explained in Generating Phantoms. The data required by the simulation defined by SimData. It should not be created directly, but rather by defining or loading a VoxelGridPhantom or CustomVoxelPhantom.

Example for loading a BrainWeb phantom, scaling it and using it as SimData on the GPU:

phantom = mr0.VoxelGridPhantom.load("subject05.npz")
phantom = phantom.interpolate(128, 128, 32).slices([16])
data = phantom.build().cuda()

Tip

A new type of phantoms is coming! These are based on NIfTIs and allow partial volume effects, segmented phantoms and easy phantom reconfiguration without code changes. They should be documented here as soon as they are merged with MR-zero Core.

Voxel Shape

Simulation data (and therefore all Phantoms) define a shape for their voxels. The following options are available:

ShapeDescription
"exact_sinc"Sinc shape = rect function as k-space drop off
"sinc"Sigmoid (rounded rect) in k-space for differentiability
"box"A box shaped voxel, with a sinc shaped k-space responce
"gauss"Normal distribution voxel shape, available for CustomVoxelPhantom

Most cases should use "sinc":
Input maps, signals, and reconstructed images are all sampled as points. Extending this bandwidth-limited data to continuous functions means that sinc-shaped voxels are the correct form in basically all cases. Using box-shaped voxels means that a round trip of putting maps into the simulation and then quantifying them from the reconstructed images will inevitably blur them. Box shaped voxels do not have flat signal response like sinc shaped voxels have (up to the nyquist frequency). Point shaped voxels would be a good fit too, except that they would prohibit gradient spoiling (and are a bad description of actual tissue).

SimData

Contains the data used for simulation (together with the Sequence). The values are flattened tensors, which only contain voxels with a non-zero proton density.

# Usually not constructed directly but via the `.build()` function on a phantom
SimData(PD, T1, T2, T2dash, D, B0, B1, coil_sens, size, voxel_pos, nyquist, dephasing_func, recover_func=None, phantom_motion=None, voxel_motion=None, tissue_masks=None)
ParameterDescription
PDproton density
T1\(T_1\) relaxation time (seconds)
T2\(T_2\) relaxation time (seconds)
T2dash\(T_2’\) dephasing time (seconds)
Disometric diffusion coefficient (10^-3 mm^2/s)
B0\(B_0\) off-resonance (Hz)
B1per-coil \(B_1\) inhomogeneity (normalized)
coil_sensper-coil sensitivity (normalized)
sizephysical phantom size (meters)
voxel_posvoxel position tensor
nyquistNyquist frequency, given by phantom size and resolution
dephasing_funck-space response of voxel shape
recover_funcoptional - provided by phantoms to revert .build() function
phantom_motionoptional rigid phantom motion trajectory
voxel_motionoptional per-voxel motion trajectory
tissue_masksoptional dictionary of masks, useful for learning tasks
  • SimData.cpu(): move data to the CPU
  • SimData.cuda(): move data to the GPU
  • SimData.device (property): the device of the repetition data
  • SimData.recover(): reconstruct the VoxelGridPhantom or CustomVoxelPhantom that was used to build this SimData

VoxelGridPhantom

Phantom format where tissue parameters are cartesian grids of voxels. The data is stored in 3D or 4D tensors with indices [(channel), x, y, z].

VoxelGridPhantom(PD, T1, T2, T2dash, D, B0, B1, coil_sens, size, phantom_motion=None, voxel_motion=None, tissue_masks=None)

Parameters of this function are identical to those of SimData, except that they are stored in 3D or 4D tensors. They are indexed [(channel), x, y, z].

  • VoxelGridPhantom.load(file_name): Loading phantom from a .npz file
  • VoxelGridPhantom.load_mat(file_name, ...): Loading phantom from a .mat file
  • VoxelGridPhantom.slices(slices): Removing all but the specified list of slices (in z direction)
  • VoxelGridPhantom.scale_fft(): Resizing the phantom by doing FFT -> truncate -> FFt
  • VoxelGridPhantom.interpolate(): Resizing the phantom by using torch.nn.functional.interpolate(..., mode='trilinear')
  • VoxelGridPhantom.plot(): Plotting all maps of the phantom (center slice)
  • VoxelGridPhantom.build(PD_threshold): Convert this phantom into SimData, sparsifying the arrays (flattening and masking where pd < PD_threshold)

CustomVoxelPhantom

Phantom format where tissue parameters are 1D lists of voxels with arbitrary positions.

CustomVoxelPhantom(pos, PD=1.0, T1=1.5, T2=0.1, T2dash=0.05, D=1.0, B0=0.0, B1=1.0, voxel_size=0.1, voxel_shape="sinc")

The size of this phantom is computed from the extends of the voxel positions.
Useful for testing reconstruction, sub-voxel positioning, teaching and more.

Parameters of this function are identical to those of SimData, except that they can also be python lists (and are converted to tensors internally). In addition, it contains a convenience method for plotting the phantom by rendering the voxels (and their selected shape) at any resolution.

  • CustomVoxelPhantom.generate_PD_map(): Voxels can be sinc- box- or gauss-shaped and at arbitrary positions. This function renders them into a fixed-resolution proton density map.
  • CustomVoxelPhantom.plot(): Render and plot all maps of this phantom
  • CustomVoxelPhantom.build(): Convert into SimData instance for simulation

Simulation

MR-zero provides two simulations:

  • a purposefully simple isochromat based simulation to check for correctness
  • a state-of-the-art PDG simulation, built for speed and accuracy.

Both simulations are differentiable and capable to run on any device supported by PyTorch (all CPUs and NVIDIA GPUs). While the isochromat simulation is rather slow and only there for confirmation purposes, PDG is one of the fastest currently available simulations. You can find more information about it in the Paper.

It is strongly adviced to use the PDG simulation - isochromat_sim only exists for testing purposes.

Phase Distribution Graph (PDG) simulation

Phase Distribution Graphs split the magnetization into multiple states, forming a Graph over the duration of the sequence. More details can be found in the PDG Paper, once published.

The simulation runs in two passes:

  • The pre-pass (compute_graph) simulates a large number of states, but only roughly estimates the signal. This information is used to assess which states are important for the signal, and which can be skipped because they don’t contribute anything.
  • The main-pass (execute_graph) uses the exact signal equation and takes all voxels into account, but simulates as few states as possible. It does so by using the information generated by the pre-pass.

The precision / speed tradeoff for both passes can be chosen as follows:

# Default parameters: max 200 states per repetition
# with at leat 0.0001 of maximum possible magnetization
graph = mr0.compute_graph(seq, data, 200, 1e-4)
# Minimum emitted and latent signal of 0.01 (normalized)
signal = mr0.execute_graph(graph, seq, data, 0.01, 0.01)

The pre-pass limits the state count by both the maximum number (higher = more states / slower + more precise simulaiton) of states and the minimum magnetization (lower = more states). In practice, it turns out that the second parameter is less surprising in how it influences the quality of the simulation, which means that the first parameter should be set to a high number and the second parameter should be increased if the pre-pass is too slow (usually the main-pass is more likely to be the bottleneck).

The main-pass has two parameters which are used as threshold to determine which states are used in the signal equation and which states are simulated. Usually they are both set to the same number. Lower numbers mean that more states are above the thresold and will be simulated. It is not useful to set min_emitted_signal to a value lower than min_latent_signal, as this is trying to include to states into the signal equation that are not simulated.

Examples:

# Very precise simulation
graph = mr0.compute_graph(seq, data, 10000, 1e-7)
signal = mr0.execute_graph(graph, seq, data, 1e-7, 1e-7)

# Average precision
graph = mr0.compute_graph(seq, data, 10000, 1e-4)
signal = mr0.execute_graph(graph, seq, data, 1e-3, 1e-4)

# FID only
graph = mr0.compute_graph(seq, data, 10000, 1e-3)
signal = mr0.execute_graph(graph, seq, data, 1, 0.1)

Optimal settings can always depend on the sequence itself. Some sequences are more demanding and require a very precise simulation, some are already decently described by only a few states.

compute_graph

This utility function computes the parameters for compute_graph_ext from the passed data. Returns the computed Graph.

ParameterDescription
seqthe Sequence to compute the graph for
datathe SimData to compute the graph for
max_state_countnumber of states per repetition above which states will be dropped
min_state_magminimum magnetization below which states will be dropped

compute_graph_ext

Compute the Phase Distribution Graph for the given sequence and settings. Runs a simulation of seq for a single voxel with the given properties. Discards states with magnetization below min_state_mag and the states with the lowest magnetization if surpassing max_state_count. Returns the computed Graph.

ParameterDescription
seqthe Sequence to compute the graph for
T1\(T_1\) relaxation time (seconds)
T2\(T_2\) relaxation time (seconds)
T2dash\(T_2’\) dephasing time (seconds)
Disometric diffusion coefficient (10^-3 mm^2/s)
max_state_countnumber of states per repetition above which states will be dropped
min_state_magminimum magnetization below which states will be dropped
nyquistsignal is zero above the Nyquist frequency of the phantom
sizeused to scale gradients to phantom FOV if the Sequence sets normalize_grads=True

execute_graph

Takes the Sequence, the SimData and the Graph and calculates the measured ADC signal. Because of the work done by the pre-pass, only the minimal work needed in order to achieve the desired precision is executed. This precision can be tuned by the min_emitted_signal and min_latent_signal thresholds. Higher values lead to less states being simulated, which improves speed and reduces accuracy. A value of 1 will mean that 2 states will be simulated (z0 and one +), resulting in the FID signal. A value of 0 means that everything will be simulated that somehow contributes to the signal, even if vanishingly small.

ParameterDescription
graphthe Graph used for state selection
seqthe Sequence to compute the graph for
datathe SimData to compute the graph for
min_emitted_signalminimal signal of a state to be included in signal computation
min_latent_signalminimal overal contribution to the signal for a state to be simulated
print_progressprint the currently simulated repetition
return_mag_adcreturn the measured magnetization next to the signal
clear_state_magclears the magnetization tensors - reduces memory consumption if no gradients are calculated
intitial_magz0 starting magnetization separately simulated preparations

Graph

A wrapper for the retuned graph, which provides two additional methods:

Graph.plot

Creates a matplotlib scatter plot of all PDG states. Does not create or show the figure, which allows to modify it, for example:

graph = compute_graph(seq, data)

plt.figure()
graph.plot(dephasing="k_x")
plt.grid()
plt.show()
ParameterDescription
transversal_magif True plot +, otherwise z states
dephasingwhat to use for the y-axis, can be one of 'k_x', 'k_y', 'k_z', or 'tau'
colorwhat to use for the color of the data points, can be one of 'abs(mag)', 'phase(mag)', 'latent signal', 'signal', 'latent signal unormalized', or 'emitted signal'
log_colorif true, use the logarithm of the chosen property for coloring

Graph.plot_data

Returns the data used in Graph.plot.

ParameterDescription
transversal_magif True plot +, otherwise z states
dephasingwhat to use for the y-axis, can be one of 'k_x', 'k_y', 'k_z', or 'tau'
colorwhat to use for the color of the data points, can be one of 'abs(mag)', 'phase(mag)', 'latent signal', 'signal', 'latent signal unormalized', or 'emitted signal'

isochromat_sim

Isochromat based Bloch simulation. The code is implemented for readability, not speed. This allows to verify its correctness, bugs are not expected.

Warning

This simulation

  • is slow
  • does not support diffusion
  • always uses "box" - voxels, which is usually a bad choice and will introduce slight blurring. See Voxel Shape for more information. This choice was made for simplicity.
ParameterDescription
seqthe Sequence to simulate
datathe SimData to simulate
spin_countnumber of spins per voxel
perfect_spoiling=Falseset transversal magnetization to zero before excitation pulses
print_progress=Trueprint the currently simulated repetition
spin_dist="rand""rand": random spin distribution; "r2": blue noise quasirandom sequence - link
r2_seed=Noneseed for "r2" distribution (for reproducibility); random if None

Reconstruction methods

NUFFT

Note

Currently, only one single reconstruction method exists here - despite more (like NUFFT or GRAPPA) being used in many scripts since a long time. We could integrate them here with MR-zero.

Nufft reconstruction is not integrated into mr0 directly, but can be realized with torchkbnufft and code similar to the following:

import torchkbnufft as tkbn

# Construct a sequence "seq" and simulate it, resulting in "signal"

kdata = signal.view(1, 1, -1)
ktraj = seq.get_kspace()[:, :2].T / (2 * np.pi)
im_size = (64, 64)

adjnufft_ob = tkbn.KbNufftAdjoint(im_size)
dcomp = tkbn.calc_density_compensation_function(ktraj, im_size=im_size)
reco = adjnufft_ob(kdata * dcomp, ktraj).view(im_size)

reco_adjoint

Adjoint reconstruction builds a very simple backwards version of the encoding / measurement operation. It essentially resembles a DFT and is thus slower and consumes more memory than an FFT, but can handle any readout trajectory.

ParameterDescription
signal[sample_count, coil_count] complex tensor
kspace[sample_count, 4] tensor (xyz encoding + dephasing time)
resolution=Noneeither (int, int, int) or None for automatic detection
FOV=Noneeither (float, float, float) or None for automatic detection
return_multicoil=Falseif False, returns quadratic combine of coils

util module

Additional helper functions.

import MRzeroCore as mr0
mr0.util.<function>()

get_signal_from_real_system

Wait for scanner TWIX files on the given path, and return if ready. Useful if a shared network folder between scanner and research PC is available.

Note

This is developed for internal use and might not be useful for others.

ParameterDescription
pathpath to TWIX file
NRepnumber of repetitions
NReadnumber of ADC samples per repetition
ncoilsnumber of recieve channels
heuristic_shiftneeded to remove garbage data from the file

insert_signal_plot

Insert a measured signal into a currently open pypulseq plot. This is only supported by newer pulseq versions, which do not show (and close) the figure immediately if plot_now=False.

seq.plot(plot_now=False)  # option doesn't exist for older pulseq versions
mr0.util.insert_signal_plot(seq, signal)
plt.show()
ParameterDescription
seqpulseq sequence, needed to align the signal with the ADC samples
signalsignal to insert into the ADC plot

pulseq_plot

Wrapper around insert_signal_plot, pulseq_plot_142 and pulseq_plot_pre14 which selects the appropriate plotting function based on the installed pulseq version.

ParameterDescription
seqsequence object
typeignored
time_rangesame as for pulseq plot()
time_dispsame as for pulseq plot()
show_blockssame as for pulseq plot()
clearignored
signalinsert simulated signal into the ADC plot
figidignored

pulseq_plot_142

Use only with pypulseq versions 1.4.x / tested with 1.4.2

Identical to pulseq plot(), but returns the generated axes! This is needed to insert the signal into the ADC plot. Modified from pypulseq 1.4.2 sequence.py - plot() - see pulseq documentation for details.

ParameterDescription
seqsequence object
labelsame as for pulseq plot()
show_blockssame as for pulseq plot()
savesame as for pulseq plot()
time_rangesame as for pulseq plot()
time_dispsame as for pulseq plot()
grad_dispsame as for pulseq plot()
plot_nowsame as for pulseq plot()

pulseq_plot_pre14

Use only with pypulseq versions before 1.4

Pulseq sequence plot with some aesthetical changes. Most important, it can insert the simulated signal into the ADC plot. Modified from pypulseq 1.2.0post1 sequence.py - plot() - see pulseq documentation for details.

ParameterDescription
seqsequence object
typesame as for pulseq plot()
time_rangesame as for pulseq plot()
time_dispsame as for pulseq plot()
clearclear matplotlib figures before plotting
signalinsert simulated signal into the ADC plot
figiduse specific figure IDs (to reuse previously created figures)

imshow

Modified version of matplotlib imshow(), tailored for showing MR reconstructions. reco is expected to be an array with dimensions [x, y], [x, y, z] or [coil, x, y, z]

  • plots images in RAS+
    • x is left-to-right
    • y is bottom-to-top
  • plots 3d data (z) as a side-by-side grid of its slices
  • applies quadratic coil-combination for multi-coil data
# Replace
import matplotlib.pyplot as plt
plt.imshow(reco, *args, **kwargs)

# with
import MRzeroCore as mr0
mr0.util.imshow(reco, *args, **kwargs)

load_phantom

Download a phantom from the MR-zero repository (or a custom URL) for getting started quickly.

DEFAULT_PHANTOM_URL = "https://github.com/MRsources/MRzero-Core/raw/main/documentation/playground_mr0/numerical_brain_cropped.mat"
ParameterDescription
sizescale phantom if desired
urlwhere to load the phantom from, defaults to DEFAULT_PHANTOM_URL
dB0_fB0(offset, scaling) floats to modify the \(B_0\) map
dB1_fB1(offset, scaling) floats to modify the \(B_1\) map
B0_polynomialoptional 2d, 2nd degree polinomial to modify the \(B_0\) map

simulate

Helper function to simulate using PDG.

ParameterDescription
seqMR-zero sequence, pulseq sequence or file name
phantomVoxelGridPhantom, CustomVoxelPhantom or .npz / .mat file name
sim_sizescales phantom if set
accuracysets both min_emitted_signal and min_latent_signal for the PDG sim
noise_leveladd normal distributed noise with the given std to the signal

simulate_2d

Caution

Deprecated - use load_phantom + simulate instead. For parameter descriptions, look at these functions.

Other methods

Miscellaneous methods provided by MR-zero. These are currently exported directly, but might be sorted into sub-modules if the list grows.

generate_brainweb_phantoms

Builds MR-zero phantoms with the data provided by BrainWeb. These phantoms are not stored in the repository; call this function once to generate them locally.

The configuration files with the used tissue parameters can be found here: brainweb_data.json

ParameterDescription
outpub_dirpath to the folder where the generated phantoms (and a cache folder for downloaded data) are written to
configone of "3T", "7T-noise", or "3T-highres-fat"

sig_to_mrd

Write the simulation output to an ISMRMD file; supported by many reconstruction tools.

ParameterDescription
mrd_pathpath where the file will be written to
mr0_signalsignal to write, shape [samples, channels]
seqpulseq sequence object (for kspace trajectory, labels, definitions)
verboselogging verbosity (0 to 5)

pulseq_write_cartesian

Warning

Outdated - we suggest writing sequences with Pulseq(-zero) instead. Exporters might be removed in the future.

Export an MR-zero sequence to Pulseq. Since MR-zero sequences have no limitations in timing, slew rates, amplitudes and more, this exporter has to try to convert this into a sequence that can actually be measured. The exporter only supports cartesian trajectories due to its use of trapezoidal gradients. There is no guarantee that it produces the expected results.

ParameterDescription
seq_paramthe mr0 sequence object to export
pathpath to write the .seq file to
FOVfield of view, used for slice selection to scale gradients and
plot_seqwether to plot the generated pulseq sequence
num_slicesused in combination with FOV to determine slice thickness
write_dataignored

Literature

This is a list of all papers and conference abstracts (known to us) which reference MR-zero. If you think something is missing, please open an issue or pull request to extend the list.

Papers

Phase distribution graphs for fast, differentiable, and spatially encoded Bloch simulations of arbitrary MRI sequences.
Endres J, Weinmüller S, Dang HN, Zaiss M.
Magn Reson Med. 2024; https://doi.org/10.1002/mrm.30055

MR-zero meets FLASH – Controlling the transient signal decay in gradient- and rf-spoiled gradient echo sequences.
Weinmüller S, Endres J, Dang HN, Stollberger R, Zaiss M.
Magn Reson Med. 2024; https://doi.org/10.1002/mrm.30318

MRzero - Automated discovery of MRI sequences using supervised learning.
Loktyushin A, Herz K, Dang HN.
Magn Reson Med. 2021; https://doi.org/10.1002/mrm.28727

MR-zero meets RARE MRI: Joint optimization of refocusing flip angles and neural networks to minimize T2-induced blurring in spin echo sequences.
Dang, H, Endres, J, Weinmüller S et al.
Magn Reson Med. 2023; https://doi.org/10.1002/mrm.29710

Conference abstracts

Weinmüller S, Dang HN, Endres J, Glang F, Loktyushin A, Zaiss M.
A blurring-free 3D snapshot readout for fast CEST- or relaxation-prepared MRI.
In: 24. Jahrestagung Der Deutschen Sektion Der ISMRM. ; 2022:6-7.

ISMRM

Advances in MRzero: supervised learning of parallel imaging sequences including joint non-Cartesian trajectory and flip angle optimization.
Glang F, Loktyushin A, Herz K, Dang HN, Deshmane A, Weinmüller S, Zaiss M et al.
ISMRM 2021, abstract 4200; https://archive.ismrm.org/2021/4200.html

MRzero sequence generation using analytic signal equations as forward model and neural network reconstruction for efficient auto-encoding.
Weinmüller S, Dang HN, Loktyushin A, Glang F, Doerfler A, Maier A, Schölkopf B, Scheffler K, Zaiss M.
ISMRM 2021, abstract 1761; https://archive.ismrm.org/2021/1761.html

Overcoming System Imperfections Using End-to-End MR Sequence Design.
West D, Glang F, Endres J, Zaiss M, Hajnal J, Malik S.
ISMRM 2023, abstract 1242; https://archive.ismrm.org/2023/1242.html

Non-idealized system (NIS) optimization of EPI sequences at ultra-high field.
West D, Glang F, Endres J, Leitão D, McElroy S, Zaiss M, Hajnal J, Malik S.
ISMRM 2024, abstract 0528; https://archive.ismrm.org/2024/0528.html

ESMRMB 2025

Book of Abstracts ESMRMB 2025 Online 41st Annual Scientific Meeting 8–11 October 2025. https://doi.org/10.1007/s10334-025-01278-8

Breast tissue segmentation at 7T using Chemical Exchange Saturation Transfer (CEST)
Magda Duarte, Katharina Breininger, Katharina Tkotz4, Sebastian Bickelhaupt, Moritz Zaiss
abstract 041

Agentic MR sequence development - Leveraging LLMs with MR tools and tests for physics-informed sequence development
Moritz Zaiss, Jonathan Endres, Simon Weinmüller
abstract 046

Breast Digital Twin: simulating with MR-zero
Magda Duarte, Felix Dietz, Tobias Dornstetter, Jonathan Endres, Simon Weinmüller, Sebastian Bickelhaupt, Moritz Zaiss
abstract 055

End-to-End Optimization of Variable Flip Angle Schemes for Enhanced Apparent Resolution in 7T 3D Fast Spin Echo MRI
Peter Dawood, Martin Blaimer, Angelika Mennecke, Fraticelli Laura, Simon Weinmüller, Jonathan Endres, Peter Jakob, Moritz Zaiss
abstract 066

Highly accelerated snapshot readout for high-resolution CEST imaging
Martin Freudensprung, Patrick Liebig, Simon Weinmüller1, Magda Durate, Moritz Zaiss
abstract 076

Simulation of dynamic B0 with Phase Distribution Graphs
Jonathan Endres, Simon Weinmüller, Moritz Zaiss
abstract 119

Phase graph-based MRI simulation including off-resonant pulse response
Felix Dietz, Simon Weinmüller, Jonathan Endres, Moritz Zaiss
abstract 130

Towards B0 and B1 Robust Spiral Turbo Spin Echo Sequence at 7T
Simon Weinmüller, Jürgen Hennig, Felix Dietz, Peter Dawood, Jonathan Endres, Moritz Zaiss
abstract 233

Patient specific quantitative MR twins for synthetic previews and protocol planning
Deepak Charles, Simon Weinmüller, Fabian Wagner, Rainer Schneider, Jonathan Endres, Moritz Zaiss
abstract 359

Exact motion simulation vs. Retrospective application on static data
Jonathan Endres, Simon Weinmüller, Moritz Zaiss
abstract 445

Optimal control pulses and MIMOSA for CEST preparation at 7 T
Martin Freudensprung, Clemens Stilianu, Simon Weinmüller, Rudolf Stollberger, Moritz Zaiss
abstract 504

ESMRMB 2024

Book of Abstracts ESMRMB 2024 Online 40th Annual Scientific Meeting 2–5 October 2024. https://doi.org/10.1007/s10334-024-01191-6

Quantalizer: a quantitative digital twin to create and run tailored sequences.
Simon Weinmüller1, Jonathan Endres, Hoai Nam Dang, Junaid Rajput, Felix Glang, Andreas Maier, Moritz Zaiss
abstract 011

MR-zero-tailored dummy refocusing pulses in TSE sequences reduce artifacts.
Jacob Malich, Simon Weinmüller, Jonathan Endres, Peter Dawood, Moritz Zaiss
abstract 112

kT-points optimization using Pulseq and MR-zero at 7T.
Martin Freudensprung, Simon Weinmüller1, Jonathan Endres,,Armin Nagel, Moritz Zaiss
abstract 422

Joint reconstruction of EPI and FLASH using Phase Distribution Graphs as a general MRI reconstruction model.
Magda Duarte, Jonathan Endres, Junaid Rajput, Simon Weinmüller1, Moritz Zaiss
abstract 456

ESMRMB 2023

Book of Abstracts ESMRMB 2023 Online 39th Annual Scientific Meeting 4–7 October 2023. https://doi.org/10.1007/s10334-023-01108-9

Dynamic DREAM MRI: B0, B1 and Tx/Rx-phase mapping for assisting motion tracking systems.
Tim Baum, Simon Weinmüller, Armin Nagel, Martin Vossiek, Moritz Zaiss
LT52

A simple pTx Pulseq extension for pulse-specific B1 shimming.
Martin Freudensprung, Simon Weinmüller1, Jonathan Endres, Armin Nagel, Moritz Zaiss
LT53

A magnetization-prepared DREAM sequence for CEST imaging with an intrinsic dynamic B0 and B1 reference (CEST-MP-DREAM).
Tim Baum, Simon Weinmüller, Jonathan Endres, Patrick Liebig, Moritz Zaiss
LT68

DREAM-zero – Optimized variable flip angles for decreased image blurring in magnetization-prepared DREAM sequences.
Simon Weinmüller, Tim Baum, Hoai Nam Dang, Jonathan Endres, Moritz Zaiss
P198