Skip to main content

Use PyPulseq for MRI sequence definitions in MR-zero

Project description

Pulseq-zero

This project aims to join pulseq with MR-zero: Use pypulseq for sequence programming and insert the sequence definition directly in MR-zero for simulations, optimization and more!

Built for pypulseq 1.4.2

Development

  1. Create a virtual environment that can use globally installed packages
python -m venv --system-site-packages .venv
  1. Activate this environment
.venv\Scripts\activate
  1. Install pulseq-zero in the virtual enviornment in editable mode
pip install --editable .

Usage

Example scripts are provided in 'pulseqzero/seq_examples'. They are modified versions of the pypulseq 1.4.2 examples. The changes that are typically necessary to convert from a pypulseq sequence script to Pulseq-zero are as follows:

Import pulseq

Change the python imports to access all functions via the Pulseq-zero facade: A wrapper that can switch between the pulseq - MR-zero interface and the real pypulseq.

Before:

import pypulseq as pp

# Build a sequence...
seq = pp.Sequence()
seq.add_block(pp.make_delay(10e-3))

After:

import pulseqzero
pp = pulseqzero.pp_impl
  
# Use exactly as before...
seq = pp.Sequence()
seq.add_block(pp.make_delay(10e-3))

Define the sequence

Wrap the sequence code in a function. This is not a necessity but a best practice for better code organization and done in newer pypulseq examples as well. Namely, it allows to:

  • switch executing the sequence script with pypulseq and write a .seq file and simulation with MR-zero
  • define sequence parameter as function arguments for re-creating the sequence with different settings
  • easily use the sequence definition in an optimization loop.

The result is something like the following example:

def my_gre_seq(TR, TE):
  seq = pp.Sequence()

  # ... create your sequence ...
  seq.add_block(pp.make_delay(TR - 3e-3)) # use the parameters in any way
  # ... more sequence creation ...

  return seq

Application

The sequence definition can now be used in many ways!

  • Using with pulseq for plotting and exporting:
    seq = my_gre_seq(14e-3, 5e-3)
    seq.plot()
    seq.write("tse.seq")
    
  • Using with MR-zero for simulation:
    import MRzeroCore as mr0
    # Data loading and other imports
    
    with pulseqzero.mr0_mode():
      seq = my_gre_seq()
    
    graph = mr0.compute_graph(seq, sim_data)
    signal = mr0.execute_graph(graph, seq, sim_data)
    reco = mr0.reco_adjoint(signal, seq.get_kspace())
    
  • Using pulseq-zero helpers to simplify common tasks even more!
    # Define some target_image which we try to achieve
    
    TR = torch.tensor(14e-3)
    TE = torch.tensor(5e-3)
    for iter in range(100):
      pulseqzero.optimize(my_gre_seq, target_image, TR, TE)
    
    # Back to using plain old pypulseq for export again!
    # The pulseq-zero magic is disabled outside of all special calls but theparameters remain optimized
    seq = my_gre_seq(TR, TE)
    seq.write("tse_optim.seq")
    

API

The following pypulseq methods and classes currently exist in Pulseq-zero. If your sequence scripts rely methods that are not listed here, Pulseq-zero might not yet be usable. Please create an issue with the request for the missing functionality.

Pypulseq 1.4.2 has the following re-exports that are expected to be used frequently. They fall into different categories as specified below, which also are the roadmap for pulseq-zero development.

from pypulseq.SAR.SAR_calc import calc_SAR
from pypulseq.Sequence.sequence import Sequence
from pypulseq.add_gradients import add_gradients
from pypulseq.align import align
from pypulseq.calc_duration import calc_duration
from pypulseq.calc_ramp import calc_ramp
from pypulseq.calc_rf_bandwidth import calc_rf_bandwidth
from pypulseq.calc_rf_center import calc_rf_center
from pypulseq.make_adc import make_adc
from pypulseq.make_adiabatic_pulse import make_adiabatic_pulse
from pypulseq.make_arbitrary_grad import make_arbitrary_grad
from pypulseq.make_arbitrary_rf import make_arbitrary_rf
from pypulseq.make_block_pulse import make_block_pulse
from pypulseq.make_sigpy_pulse import *
from pypulseq.make_delay import make_delay
from pypulseq.make_digital_output_pulse import make_digital_output_pulse
from pypulseq.make_extended_trapezoid import make_extended_trapezoid
from pypulseq.make_extended_trapezoid_area import make_extended_trapezoid_area
from pypulseq.make_gauss_pulse import make_gauss_pulse
from pypulseq.make_label import make_label
from pypulseq.make_sinc_pulse import make_sinc_pulse
from pypulseq.make_trapezoid import make_trapezoid
from pypulseq.sigpy_pulse_opts import SigpyPulseOpts
from pypulseq.make_trigger import make_trigger
from pypulseq.opts import Opts
from pypulseq.points_to_waveform import points_to_waveform
from pypulseq.rotate import rotate
from pypulseq.scale_grad import scale_grad
from pypulseq.split_gradient import split_gradient
from pypulseq.split_gradient_at import split_gradient_at
from pypulseq.supported_labels_rf_use import get_supported_labels
from pypulseq.traj_to_grad import traj_to_grad

TODO

  • calc_SAR
  • Sequence
    • __init__
    • __str__
    • adc_times
    • add_block
    • calculate_gradient_spectrum
    • calculate_kspace
    • calculate_kspacePP
    • calculate_pns
    • check_timing
    • duration
    • evaluate_labels
    • flip_grad_axis
    • get_block
    • get_definition
    • get_extension_type_ID
    • get_extension_type_string
    • get_gradients
    • mod_grad_axis
    • plot
    • read
    • register_adc_event
    • register_grad_event
    • register_label_event
    • register_rf_event
    • remove_duplicates
    • rf_from_lib_data
    • rf_times
    • set_block
    • set_definition
    • set_extension_string_ID
    • test_report
    • waveforms
    • waveforms_and_times
    • waveforms_export
    • write
  • add_gradients
  • align
  • calc_duration
  • calc_ramp
  • calc_rf_bandwidth
  • calc_rf_center
  • make_adc
  • make_adiabatic_pulse
  • make_arbitrary_grad
  • make_arbitrary_rf
  • make_block_pulse
  • make_delay
  • make_digital_output_pulse
  • make_extended_trapezoid
  • make_extended_trapezoid_area
  • make_gauss_pulse
  • make_label
  • make_sinc_pulse
  • make_trapezoid
  • sigpy
    • SigpyPulseOpts
    • sigpy_n_seq
    • make_slr
    • make_sms
  • make_trigger
  • Opts
    • __init__
    • set_as_default
    • reset_default
    • __str__
  • points_to_waveform
  • rotate
  • scale_grad
  • split_gradient
  • split_gradient_at
  • get_supported_labels
  • traj_to_grad

Disabled in mr0 mode

These will in mr0 mode either return the specified value or don't exist so using them raises an error. The reason for disabling is either that a differentiable re-implementation if out of scope of pulseq-zero (e.g.: pulse optimization) or not sensible (like sequence loding).

function return value
calc_SAR (True, [])
Sequence.calculate_pns error
Sequence.check_timing None
Sequence.evaluate_labels error
Sequence.plot None
Sequence.read error
Sequence.write None or "" depending on create_signature
Sequence.register_*_event error - is only used internally
sigpy error
make_adiabatic_pulse error
make_label None
make_extended_trapezoid_area error
calc_rf_bandwidth returns zeroes as mr0 mode doesn't store pulse shapes
calc_rf_center returns zeroes as mr0 mode doesn't store pulse shapes
points_to_waveform error

Altered behaviour

Some functions are only partially supported in mr0 mode and / or some aspects are missing in simulation. In general, pulseq-zero tries not to include every single attribute that exists in pypulseq to reduce bloat; if scripts rely on them existing (even if they are ignored even in pypulseq) they can be added to the objects created in the make_ functions even if they don't affect anything. Some pypulseq functions round to raster times, which is not done in mr0 mode for differentiability. Pypulseq does many more checks on timing or other parameters that are not checked by pulseq-zero. These are not listed here, but note that some scripts that don't run otherwise might run in mr0 mode. Pulses have no shape, center_pos will influence the returned gzr but nothing else - TODO should be considered when converting timing to mr0

function remarks
make_trigger, make_digital_output_pulse returns Delay, ignores rest
make_adc has no dead_time property
make_arbitrary_rf, make_block_pulse, make_gauss_pulse, make_sinc_pulse returned object has no signal or t attribute (waveform is not computed) but has an added flip_angle
make_trapezoid area, flat_area are calculated properties, no attributes first, last or use, signal or t
make_sinc_pulse has no dead_time, ringdown_time or use properties
make_gauss_pulse has no dead_time, ringdown_time, use, signal or t
make_arbitrary_rf has no dead_time, ringdown_time, use, signal or t
calc_duration adc doesn't include dead_time (pypulseq bug), only includes trigger delay (see make_trigger)
make_arbitrary_grad no first or last
make_extended_trapezoid skipping some checks and ignoring convert_to_arbitrary; area is a computed property, no first or last
Sequence way less internal bookkeeping, most variables are missing, reports etc. are not calculated

Additional API

This API does not exist in pulseq and is provided for simulation, optimization and other tasks.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pulseqzero-0.1.0.tar.gz (27.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pulseqzero-0.1.0-py3-none-any.whl (26.1 kB view details)

Uploaded Python 3

File details

Details for the file pulseqzero-0.1.0.tar.gz.

File metadata

  • Download URL: pulseqzero-0.1.0.tar.gz
  • Upload date:
  • Size: 27.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for pulseqzero-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bec8a924bb30c7a99279f16103b6115f9320235b468f46b9e8b50ad8f33eee57
MD5 c24fd488984ab5286ced4364d1139005
BLAKE2b-256 c3c202d23ff1e5d66d8307e427864a1def8a5bc42a7e71e8bb473788d531a55e

See more details on using hashes here.

File details

Details for the file pulseqzero-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pulseqzero-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 26.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for pulseqzero-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ac887e36c127419ea9e17ef6a6480af6a6e5997e6b1d28d80bbdc4e7a949061a
MD5 c526865b9e4920135eac4680c6d51e8e
BLAKE2b-256 0f80bcd224f645570342632bdc40d4e93caa7c281342570e12af31faf02b3b1a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page