Skip to content

Fix grad raster time typo. Make system rasters consistent with the defs.#299

Open
btasdelen wants to merge 4 commits intoimr-framework:masterfrom
btasdelen:read_fix_gradraster
Open

Fix grad raster time typo. Make system rasters consistent with the defs.#299
btasdelen wants to merge 4 commits intoimr-framework:masterfrom
btasdelen:read_fix_gradraster

Conversation

@btasdelen
Copy link
Collaborator

Fixes the issue at #254.

@github-actions
Copy link

github-actions bot commented Jul 20, 2025

Coverage

Coverage Report
FileStmtsMissCoverMissing
/home/runner/.local/lib/python3.12/site-packages/pypulseq
   add_gradients.py1376056%44, 52, 58, 61, 75–86, 92, 125–128, 135–136, 155, 162, 167–263
   add_ramps.py36360%1–92
   align.py35489%41, 45, 69, 73
   calc_duration.py25196%37
   calc_ramp.py2202162%48–359
   calc_rf_bandwidth.py372824%45–81, 85–89
   check_timing.py962970%78, 82, 107, 180, 199, 232, 239, 249–293
   compress_shape.py30197%28
   convert.py40880%42, 48, 66, 72–73, 82, 88–89
   event_lib.py961584%6–9, 48–51, 70–71, 205–210, 247
   make_adc.py981486%77, 80, 90–94, 97, 146, 149, 153, 159, 163, 202, 204, 206, 214
   make_adiabatic_pulse.py1323970%204–208, 228–232, 240–241, 264, 270, 339–358, 462–471, 509–517
   make_arbitrary_grad.py531572%71, 74, 77, 80, 96–98, 107, 109, 117–121, 130
   make_arbitrary_rf.py756316%95–179
   make_block_pulse.py48394%121–125, 128
   make_delay.py9189%27
   make_digital_output_pulse.py16288%42, 50
   make_extended_trapezoid.py561279%67, 70, 76, 82, 85, 88, 91, 94, 116, 134, 136, 139
   make_extended_trapezoid_area.py93397%52, 227, 230
   make_gauss_pulse.py732073%139–143, 146–170, 177, 180
   make_label.py22482%64, 66, 68, 75
   make_sigpy_pulse.py1193075%12–13, 121, 124, 128, 165–169, 173, 176–177, 180–181, 196, 203, 208, 220, 223, 248–258, 272, 275, 305–315
   make_sinc_pulse.py701086%102, 108, 136–140, 144, 147–148, 151–152, 174
   make_soft_delay.py26292%107, 125
   make_trapezoid.py111794%177, 190, 196, 214, 232, 237, 255
   make_trigger.py16288%47, 55
   opts.py66986%78, 83, 102, 142, 166–170
   points_to_waveform.py9189%27
   rotate.py691480%15, 55, 66–69, 85–90, 112, 119–120
   scale_grad.py30197%65
   sigpy_pulse_opts.py26773%34–41
   split_gradient.py393121%46–103
   split_gradient_at.py702761%63–90, 110, 114, 118–120, 154–156
   traj_to_grad.py13931%26–40
/home/runner/.local/lib/python3.12/site-packages/pypulseq/SAR
   SAR_calc.py1139813%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.py4698382%63, 66, 74, 80, 95, 103, 109, 120, 123, 126, 134, 139, 148, 159, 167, 207, 209, 213, 225, 274, 278, 294, 319–345, 382–385, 391, 416–418, 421–429, 436, 466–470, 512, 518, 551, 587–594, 611, 621, 647, 685, 703, 706, 724, 738, 765, 844, 881, 905
   calc_grad_spectrum.py81766%68–190
   calc_pns.py403122%45–96
   ext_test_report.py1441292%23, 61, 138, 149–150, 237–243
   install.py754244%31, 52, 69, 71, 112–131, 148, 181–184, 200–212, 254–278
   parula.py4250%19–86
   read_seq.py38012268%43–44, 94, 112, 119, 125, 132–133, 137, 151–158, 163–166, 178, 182–184, 227, 232, 240–297, 304–319, 334–404, 409–426, 489, 492, 527, 535, 577, 601, 641, 683–687, 802, 813
   sequence.py62913479%10–13, 105–115, 136–149, 196, 261–264, 311, 338, 355, 403, 431, 458–463, 500, 516, 607, 635–644, 656, 678, 719–722, 776, 814, 825–826, 832, 843, 849, 851, 859, 892–900, 1030, 1120, 1126, 1129, 1132, 1169, 1294–1307, 1337, 1365, 1387–1389, 1410, 1473, 1481, 1548, 1559–1572, 1584–1595, 1641–1642, 1653–1671, 1695, 1725–1733, 1769, 1783–1793, 1797, 1808
   write_seq.py36218050%45, 69, 72–79, 310–539
/home/runner/.local/lib/python3.12/site-packages/pypulseq/utils
   cumsum.py14193%17
   paper_plot.py63588%47–130
   safe_pns_prediction.py12611310%50–87, 102–189, 197–214, 222, 244–250, 279–286, 310–336, 344–383, 396–411, 415
   seq_plot.py37818052%20, 98, 130–131, 150, 167–169, 174–216, 226–233, 240–305, 309–315, 319–327, 349, 351, 354, 379–401, 446–447, 450–453, 485, 500–510, 519–521, 539–541, 543–544, 546–547, 580–592, 607–608, 624–641, 682–686
   tracing.py16662%33–34, 42, 54–55, 75
/home/runner/.local/lib/python3.12/site-packages/pypulseq/utils/siemens
   asc_to_hw.py58539%21–28, 48–106
   readasc.py48456%25–100
TOTAL5197196062% 

Tests Skipped Failures Errors Time
1369 21 💤 0 ❌ 0 🔥 3m 42s ⏱️

@btasdelen btasdelen mentioned this pull request Jul 31, 2025
11 tasks
@FrankZijlstra
Copy link
Collaborator

FrankZijlstra commented Jul 31, 2025

Question: Why are system parameters read from the sequence file in the first place? While it is useful to know what system parameters were used to write the file, shouldn't the principle of Pulseq be that a .seq file can be shared and run on a different system? That is, system parameters should not be overwritten in the first place?

For example, if I have a hypothetical system with a 1 us gradient raster, I should have no problems reading a sequence with a 10 us gradient raster, but the sequence checks should still be done with with the user-specified system parameters.

It would make more sense to me to give a warning if the specified system parameters do not match with the ones in the file, to hint that the systems may be incompatible.

In addition, I think the system variable in Sequence is a reference, so I think this PR may end up making unexpected modifications, e.g.:

system = pp.Opts();
seq = pp.Sequence(system=system);
seq.read('test.seq')
print(system.grad_raster_time); # <-- May be changed?

@btasdelen
Copy link
Collaborator Author

@FrankZijlstra That is a good question. I think this behavior is consistent with what Matlab Pulseq does. Gradient raster times for extended trapezoids are used in plotting, and incorrect raster time causes weird looking waveforms. See #254.

I also found it confusing that, during object creation, we set self.grad_raster_time = self.system.grad_raster_time (and other system parameter), and use self.grad_raster_time internally when needed, but a couple of places we are inconsistent and use self.system.grad_raster_time instead, so now those two may not be the same if changed halfway. This PR attempted to fix that, but maybe I am misunderstanding the whole deal.

My questions are what do we expect when the user changes the Sequence.system after initialization, and what is the purpose of setting self.grad_raster_time, just a shortcut or to "fix" these definitions in a sense? If the latter, isn't it more confusing that even though the user changes parameters, most of the internal functions use old ones?

These are the functions I see that are using self.system.grad_raster_time, rest are using self.grad_raster_time:

dt = obj.system.grad_raster_time # time raster

raster = seq.system.grad_raster_time

@btasdelen btasdelen requested a review from schuenke October 17, 2025 16:37
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.

3 participants