Skip to content

Commit 488988b

Browse files
committed
wip
1 parent 88d2fb2 commit 488988b

File tree

1 file changed

+70
-5
lines changed

1 file changed

+70
-5
lines changed

src/mrinufft/io/pulseq.py

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@
55
sequences. Requires the `pypulseq` package to be installed.
66
"""
77

8+
from types import SimpleNamespace
89
import numpy as np
910
import pypulseq as pp
11+
from numpy.typing import NDArray
12+
from ..trajectories.utils import convert_trajectory_to_gradients
1013

1114

12-
def read_pulseq_traj(filename):
15+
def read_pulseq_traj(filename, traj_delay=0.0, grad_offset=0.0):
1316
"""Extract k-space trajectory from a Pulseq sequence file.
1417
1518
The sequence should be a valid Pulseq `.seq` file, with arbitrary gradient
1619
waveforms, which all have the same length.
1720
18-
Unlike `Sequence.calculate_kspace`, this function returns the k-space
19-
trajectory segmented in shots ("blocks" from Pulseq), and works directly
20-
from the gradients waveforms stored in the `.seq` file.
21+
Note
2122
2223
Parameters
2324
----------
@@ -37,5 +38,69 @@ def read_pulseq_traj(filename):
3738
seq = pp.Sequence()
3839
seq.read(filename)
3940

41+
kspace_adc, kspace, t_exc, t_refocus, t_adc = seq.calculate_kspace(
42+
traj_delay, grad_offset
43+
)
4044

41-
gradient_waveforms = seq.waveforms()
45+
46+
def pulseq_grad_blocks(
47+
trajectory: NDArray, system: pp.Opts = pp.Opts.default
48+
) -> list[SimpleNamespace]:
49+
"""Create Pulseq gradient blocks from a k-space trajectory.
50+
51+
Parameters
52+
----------
53+
trajectory : np.ndarray
54+
The k-space trajectory as a numpy array of shape (n_shots, n_samples, 3),
55+
where the last dimension corresponds to the x, y, and z coordinates in k-space.
56+
57+
Returns
58+
-------
59+
list
60+
A list of Pulseq gradient blocks corresponding to the k-space trajectory.
61+
"""
62+
grads = convert_trajectory_to_gradients(trajectory)
63+
64+
# TODO add prewind/postwind stuff from #276
65+
# TODO ensure amplitudes are correct
66+
67+
# TODO deduplicate gradients (reduces the size of the file, speed up the sequence loading).
68+
# TODO Are rotation of trajectories supported in pulseq?
69+
70+
grads = convert_trajectory_to_gradients(trajectory)
71+
for g in grads:
72+
for i, c in enumerate(["x", "y", "z"]):
73+
pp_g = pp.make_arbitrary_grad("x", g[:, i])
74+
75+
76+
return blocks_pp
77+
78+
79+
def pulseq_gre_arb_grad(trajectory, pulse, system: pp.Opts = pp.Opts.default):
80+
"""Create a Pulseq GRE sequence with arbitrary gradient waveform.
81+
82+
Parameters
83+
----------
84+
trajectory : np.ndarray
85+
The k-space trajectory as a numpy array of shape (n_shots, n_samples, 3),
86+
where the last dimension corresponds to the x, y, and z coordinates in k-space.
87+
pulse : pypulseq.Pulse
88+
89+
system : pypulseq.Opts, optional
90+
The system options for the Pulseq sequence. Default is `pp.Opts.default`.
91+
92+
Returns
93+
-------
94+
pp.Sequence
95+
A Pulseq sequence object with the specified arbitrary gradient waveform.
96+
"""
97+
seq = pp.Sequence(system=system)
98+
grad_shot_ids, grad_shots = pulseq_grad_blocks(trajectory, system)
99+
100+
101+
# TODO
102+
for grad_shot_id in grad_shot_ids:
103+
pp.add_block() # RF pulse
104+
pp.add_block() # pause for tuning echo time
105+
pp.add_block() # Gradient block with ADC
106+
return seq

0 commit comments

Comments
 (0)