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
- Create a virtual environment that can use globally installed packages
python -m venv --system-site-packages .venv
- Activate this environment
.venv\Scripts\activate
- 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
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bec8a924bb30c7a99279f16103b6115f9320235b468f46b9e8b50ad8f33eee57
|
|
| MD5 |
c24fd488984ab5286ced4364d1139005
|
|
| BLAKE2b-256 |
c3c202d23ff1e5d66d8307e427864a1def8a5bc42a7e71e8bb473788d531a55e
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac887e36c127419ea9e17ef6a6480af6a6e5997e6b1d28d80bbdc4e7a949061a
|
|
| MD5 |
c526865b9e4920135eac4680c6d51e8e
|
|
| BLAKE2b-256 |
0f80bcd224f645570342632bdc40d4e93caa7c281342570e12af31faf02b3b1a
|