The GRE sequence https://github.com/imr-framework/pypulseq/blob/0398b12bc1d86c1997ed5ad34242a22cc95003bd/examples/scripts/write_gre.py has a small TE/TR timing error if the rf.ringdown_time gets longer than the gz.fall_time.
Taking the max() of both fixes the issue which becomes relevant for longer ringdown times or thick slices.

Coverage Report
| File | Stmts | Miss | Cover | Missing |
|---|
| /home/runner/.local/lib/python3.12/site-packages/pypulseq |
| add_gradients.py | 123 | 51 | 59% | 44, 52, 58, 61, 75–86, 92, 120–123, 130–131, 150, 157, 162–241 |
| add_ramps.py | 36 | 36 | 0% | 1–89 |
| align.py | 35 | 4 | 89% | 41, 45, 69, 73 |
| calc_duration.py | 25 | 1 | 96% | 37 |
| calc_ramp.py | 218 | 214 | 2% | 45–353 |
| calc_rf_bandwidth.py | 27 | 20 | 26% | 37–59, 63–67 |
| check_timing.py | 87 | 27 | 69% | 72, 76, 101, 194, 201, 211–255 |
| compress_shape.py | 30 | 1 | 97% | 28 |
| convert.py | 40 | 8 | 80% | 42, 48, 66, 72–73, 82, 88–89 |
| event_lib.py | 96 | 14 | 85% | 6–9, 48–51, 70–71, 205–210 |
| make_adc.py | 92 | 13 | 86% | 63, 72–76, 79, 128, 131, 135, 141, 145, 184, 186, 188, 196 |
| make_adiabatic_pulse.py | 129 | 39 | 70% | 196–200, 217–221, 229–230, 253, 259, 328–347, 451–460, 498–506 |
| make_arbitrary_grad.py | 37 | 7 | 81% | 68, 71, 74, 77, 81, 83, 103 |
| make_arbitrary_rf.py | 66 | 55 | 17% | 83–160 |
| make_block_pulse.py | 46 | 3 | 93% | 112–116, 119 |
| make_delay.py | 9 | 1 | 89% | 27 |
| make_digital_output_pulse.py | 16 | 2 | 88% | 39, 47 |
| make_extended_trapezoid.py | 56 | 12 | 79% | 67, 70, 76, 82, 85, 88, 91, 94, 116, 134, 136, 139 |
| make_extended_trapezoid_area.py | 93 | 3 | 97% | 52, 227, 230 |
| make_gauss_pulse.py | 69 | 20 | 71% | 127–131, 134–158, 165, 168 |
| make_label.py | 19 | 3 | 84% | 36, 41, 43 |
| make_sigpy_pulse.py | 116 | 31 | 73% | 12–13, 112, 115, 119, 154, 157–161, 165, 168–169, 172–173, 188, 195, 200, 212, 215, 240–250, 264, 267, 297–307 |
| make_sinc_pulse.py | 68 | 10 | 85% | 94, 100, 127–131, 135, 138–139, 142–143, 165 |
| make_trapezoid.py | 111 | 7 | 94% | 177, 190, 196, 214, 232, 237, 255 |
| make_trigger.py | 16 | 2 | 88% | 44, 52 |
| opts.py | 66 | 9 | 86% | 78, 83, 102, 142, 166–170 |
| points_to_waveform.py | 9 | 1 | 89% | 27 |
| rotate.py | 69 | 14 | 80% | 15, 55, 66–69, 85–90, 112, 119–120 |
| scale_grad.py | 14 | 4 | 71% | 28–30, 33 |
| sigpy_pulse_opts.py | 26 | 7 | 73% | 34–41 |
| split_gradient.py | 39 | 31 | 21% | 46–103 |
| split_gradient_at.py | 70 | 27 | 61% | 63–90, 110, 114, 118–120, 154–156 |
| traj_to_grad.py | 13 | 9 | 31% | 26–40 |
| /home/runner/.local/lib/python3.12/site-packages/pypulseq/SAR |
| SAR_calc.py | 113 | 98 | 13% | 33–40, 55–62, 89–108, 129–132, 168–212, 242–246, 264–306 |
| /home/runner/.local/lib/python3.12/site-packages/pypulseq/Sequence |
| block.py | 368 | 32 | 91% | 59, 62, 70, 76, 91, 99, 105, 116, 119, 122, 130, 135, 144, 196, 245, 249, 265, 305–308, 337–338, 404, 410, 430, 499, 535, 541, 568, 606, 640 |
| calc_grad_spectrum.py | 81 | 76 | 6% | 68–190 |
| calc_pns.py | 40 | 31 | 22% | 45–96 |
| ext_test_report.py | 140 | 11 | 92% | 23, 58, 61, 135, 227–233 |
| install.py | 75 | 42 | 44% | 31, 52, 69, 71, 112–131, 148, 181–184, 200–212, 254–278 |
| parula.py | 4 | 2 | 50% | 19–86 |
| read_seq.py | 312 | 68 | 78% | 42–43, 90, 93, 105, 110, 116, 123, 132, 141, 146, 149, 157–159, 192, 197, 205–254, 284–287, 302–303, 332–349, 412, 415, 450, 458, 532, 574–578 |
| sequence.py | 723 | 217 | 70% | 11–14, 101–111, 132–145, 183, 248–251, 292, 319, 336, 384, 412, 439–444, 481, 497, 588, 610, 651–654, 708, 740, 751–752, 758, 769, 775, 777, 785, 818–826, 847–869, 912, 914, 917, 943–944, 947–950, 986–996, 1034–1035, 1071–1072, 1098, 1104, 1107, 1144, 1265–1278, 1301, 1329, 1351–1353, 1374, 1405, 1416–1429, 1441–1452, 1498–1499, 1508–1526, 1550, 1580–1588, 1620–1730, 1759, 1773–1783, 1795 |
| write_seq.py | 172 | 8 | 95% | 41, 65, 68–75 |
| /home/runner/.local/lib/python3.12/site-packages/pypulseq/utils |
| cumsum.py | 14 | 1 | 93% | 17 |
| safe_pns_prediction.py | 126 | 113 | 10% | 50–87, 102–189, 197–214, 222, 244–250, 279–286, 310–336, 344–383, 396–411, 415 |
| tracing.py | 16 | 6 | 62% | 33–34, 42, 54–55, 75 |
| /home/runner/.local/lib/python3.12/site-packages/pypulseq/utils/siemens |
| asc_to_hw.py | 58 | 53 | 9% | 21–28, 48–106 |
| readasc.py | 48 | 45 | 6% | 25–100 |
| TOTAL | 4358 | 1489 | 66% | |
| Tests |
Skipped |
Failures |
Errors |
Time |
| 1285 |
18 :zzz: |
0 :x: |
0 :fire: |
2m 51s :stopwatch: |
Going from the GRE sequence I wrote for https://github.com/pulseq/MR-Physics-with-Pulseq/, the correct delay calculation should be:
delay_TE = (
math.ceil(
(
TE
- (pp.calc_duration(gz, rf) - pp.calc_rf_center(rf)[0] - rf.delay)
- pp.calc_duration(gx_pre)
- pp.calc_duration(gx) / 2
- pp.eps
)
/ seq.grad_raster_time
)
* seq.grad_raster_time
)
This should fix your issue, and it does not assume that the center of the RF pulse is in the center of the waveform. seq.test_report() is accurate in reporting TE, so any errors with the nominal TE should show up there.
I had meant to update the example sequences based on the "clean" ones we developed for that course, but I never got around to it. This issue almost certainly exists in other examples.
I adopted your proposed change. It seems that previously a rounding issue led to a delay_TE of 82 ms. Now it is 81 ms. Therefore the reference seq file for testing in '\tests\expected_output' needs to be updated.