Skip to content

Add (multi) 2D EPI kernel and scripts#70

Draft
schuenke wants to merge 29 commits intomainfrom
epi2d
Draft

Add (multi) 2D EPI kernel and scripts#70
schuenke wants to merge 29 commits intomainfrom
epi2d

Conversation

@schuenke
Copy link
Copy Markdown
Contributor

@schuenke schuenke commented Feb 25, 2026

To do:

  • verify mrd trajectory information for multi-2D acquisitions with and without noise and/or navigator acquisitions
  • add tests
  • add example scripts
  • (optional) replace pulseq-based traj calculation with analytical definition (including ramp sampling and oversampling)
  • add frequency offset for ADC in EPI readout

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 25, 2026

Coverage

Coverage Report
FileStmtsMissCoverMissing
/home/runner/.local/lib/python3.12/site-packages/mrseq
   _version.py770%2–9
/home/runner/.local/lib/python3.12/site-packages/mrseq/preparations
   t2_prep.py51198%195
/home/runner/.local/lib/python3.12/site-packages/mrseq/scripts
   epi2d_fid.py155994%308, 411, 468–473, 485, 491
   epi2d_se.py1731492%205–207, 330, 358, 366, 469, 526–531, 543, 549
   grpe_flash_dixon.py2051891%121, 124, 189, 206–208, 330, 349, 400, 410, 503, 571–576, 596, 602
   radial_flash.py1401192%101, 104, 259, 345, 403–408, 428, 434
   spiral_flash.py1201092%95, 231, 313, 363–368, 387, 393
   t1_inv_rec_gre_single_line.py93990%162, 255, 298–303, 330, 336
   t1_inv_rec_se_single_line.py106992%219, 316, 375–380, 407, 413
   t1_molli_bssfp.py1411391%216, 282–284, 299, 374, 428–433, 454, 460
   t1_t2_spiral_cmrf.py1491292%89, 95, 114, 168, 385, 432–437, 463, 469
   t1rho_se_single_line.py102892%310, 367–372, 399, 405
   t2_multi_echo_se_single_line.py96991%162, 261, 314–319, 344, 350
   t2_t2prep_flash.py1431590%103, 226, 243, 277–279, 291, 367, 429–434, 454, 460
   t2star_multi_echo_flash.py1451490%114, 233, 280–282, 294, 390, 452–457, 477, 483
/home/runner/.local/lib/python3.12/site-packages/mrseq/utils
   EpiReadout.py3069071%52, 61, 193, 197, 244, 318, 322–333, 455, 508–592, 658–664, 684–729
   ismrmrd.py93298%173, 179
   sequence_helper.py59493%105, 133–134, 162
   trajectory.py148398%45, 87, 358
TOTAL256425890% 

Tests Skipped Failures Errors Time
1253 0 💤 4 ❌ 0 🔥 2m 22s ⏱️

@schuenke
Copy link
Copy Markdown
Contributor Author

schuenke commented Mar 4, 2026

This is how the current version of plot_trajectory() looks like:

symmetric:
image

flyback:
image

@ckolbPTB
Copy link
Copy Markdown
Contributor

In dc500da I changed how the amplitude of the readout gradient is modified for the symmetric EPI readout. In the previous version the EPI-object was modified. This meant that for an odd number of phase encoding steps, the readout gradient of the EPI-object was flipped at the end of add_to_seq. The EPI-object could then not be used anymore to obtain e.g. another repetition. Now the EPI-object is not modified.

I removed the rev-label here:

seq.add_block(self.gx, self.adc, lin_label)

I think this should be fine but maybe @schuenke could double check

epi2d.adc,
pp.make_label(label='REV', type='SET', value=gx.amplitude < 0),
pp.make_label(label='SEG', type='SET', value=gx.amplitude < 0),
pp.make_label(label='AVG', type='SET', value=(n + 1) == 3),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pp.make_label(label='AVG', type='SET', value=(n + 1) == 3),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove this, because it leads to 1 readout having avg = 0 and two readouts with avg = 0,1 which then leads to problems for the MRpro sorting routines. They are not really averages anyway because there is T2* decay.

epi2d.adc,
pp.make_label(label='REV', type='SET', value=gx_sign < 0),
pp.make_label(label='SEG', type='SET', value=gx_sign < 0),
pp.make_label(label='AVG', type='SET', value=(n + 1) == 3),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pp.make_label(label='AVG', type='SET', value=(n + 1) == 3),

same as for epi2d_fid

)

# Navigator kx offset: starts from -gx_pre.area (reversed pre-winder)
nav_kx_offset = -epi2d.gx_pre.area
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
nav_kx_offset = -epi2d.gx_pre.area
nav_kx_offset = epi2d.gx_pre.area

I had to make these changes to get the correct navigator trajectory


# Navigator kx offset: starts from -gx_pre.area (reversed pre-winder)
nav_kx_offset = -epi2d.gx_pre.area
nav_gx_sign = -1.0 # first navigator uses reversed gx
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
nav_gx_sign = -1.0 # first navigator uses reversed gx

I had to make these changes to get the correct navigator trajectory

assert prot is not None
n_samples = epi2d.adc.num_samples
traj = np.zeros((n_samples, 2), dtype=np.float32)
if nav_gx_sign > 0:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if nav_gx_sign > 0:

traj = np.zeros((n_samples, 2), dtype=np.float32)
if nav_gx_sign > 0:
nav_kx = nav_kx_offset + nav_kx_forward
else:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
else:

if nav_gx_sign > 0:
nav_kx = nav_kx_offset + nav_kx_forward
else:
nav_kx = nav_kx_offset - nav_kx_forward
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
nav_kx = nav_kx_offset - nav_kx_forward

n_samples = epi2d.adc.num_samples
traj = np.zeros((n_samples, 2), dtype=np.float32)
if nav_gx_sign > 0:
nav_kx = nav_kx_offset + nav_kx_forward
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
nav_kx = nav_kx_offset + nav_kx_forward
nav_kx = nav_kx_offset + gx_sign * nav_kx_forward

@ckolbPTB
Copy link
Copy Markdown
Contributor

The above changes were necessary to get the correct trajectory for the navigators. Probably similary changes are needed for the epi2d_fid.

We could add the part on reading out the navigators to the example notebook. What do you think @schuenke ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants