Skip to content

Test sequence runnable script - #370

Open
fsantini wants to merge 4 commits into
pulseq:masterfrom
fsantini:master
Open

Test sequence runnable script#370
fsantini wants to merge 4 commits into
pulseq:masterfrom
fsantini:master

Conversation

@fsantini

Copy link
Copy Markdown

This PR adds a runnable script "ppseqtest" that can be used to plot an existing .seq file. It is useful to visualize a third-party file, or generated with another framework.

A section "command-line utilities" was added to the README

Minor change:

  • Links in the README were fixed and reorganized.

@mzaiss

mzaiss commented Feb 21, 2026

Copy link
Copy Markdown
Contributor

This is a helpful thing, we use similar scripts.

We realized that this is actually a "pulseq interpreter"

as it mimicks the interpreter on a real scanner.
just an idea to maybe actually call such a script like that.

you could also make it similar to the new example sequences, regarding input, output (seq object) and a check for fov definition, which would turn this into a test very colse to a scanner interpreter.

returning seq also allows then to run similar functions as for other write_seq files afterwards.

like seq.plot or seq.calulate_kspace

@github-actions

Copy link
Copy Markdown

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.py961485%6–9, 48–51, 70–71, 205–210
   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.py5180%9
/home/runner/.local/lib/python3.12/site-packages/pypulseq/Sequence
   block.py4697983%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, 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.py1441192%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.py4003990%44–45, 110, 117, 130, 133–134, 138, 184, 228, 401, 422–439, 502, 505, 590, 614, 654, 685, 701–705, 712, 823, 834
   sequence.py63112880%10–13, 105–115, 136–149, 196, 261–264, 311, 355, 431, 458–463, 500, 528–531, 622, 650–659, 671, 693, 734–737, 791, 829, 840–841, 847, 858, 864, 866, 874, 907–915, 1045, 1135, 1141, 1144, 1147, 1184, 1309–1322, 1380, 1402–1404, 1425, 1488, 1496, 1563, 1574–1587, 1656–1657, 1668–1686, 1710, 1740–1748, 1784, 1798–1808
   write_seq.py362798%45, 77–79, 313, 347–349, 499
/home/runner/.local/lib/python3.12/site-packages/pypulseq/scripts
   test_sequence.py30300%1–58
/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
TOTAL5141162568% 

Tests Skipped Failures Errors Time
1441 24 💤 0 ❌ 0 🔥 4m 48s ⏱️

@fsantini

Copy link
Copy Markdown
Author

Hi Moritz, thanks for the comment. I'm not sure I understand it though, as the script does very little except loading an existing sequence file, so what's the use of returning a seq object? It would be basically equivalent to do read().

@schuenke

Copy link
Copy Markdown
Collaborator

I don't really get why I would need this to be honest.

I would still need to install Python and PyPulseq and the only advantage would be to be able to run a plot/check without starting my IDE and manually call seq.read() and seq.plot(), right?

However, I am not able to specify my system limits which makes timing checks and the test report a bit meaningless, no?

Maybe you can explain again when/where/why you would use this and maybe @mzaiss can also quickly explain why this should be seen as kind of a "virtual interpreter" !?

@fsantini

Copy link
Copy Markdown
Author

Hi Patrick, it is useful if you just want to use pypulseq as a utlity to look at existing seq files. In my specific case, I would generate seq files with nimpulseq, which doesn't have plotting capabilities, so I would then use this utility to look at the result. However, I understand that this might not be the majority use case for pypulseq users, so I'm happy to keep this (and other future command-line utilities) in a separate package that simply depends on pypulseq.

@mzaiss

mzaiss commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

for us its nice to have something generic that returns seq objects.

then i can use e.g. mrseq seqs and files
analogously.

in that sense mrseq is a built-in sequence, and such a function would be a pulseq interpreter for files.

but this does not need kspqce and other plotting.
and it must return seq objects

@fsantini

Copy link
Copy Markdown
Author

for us its nice to have something generic that returns seq objects.
but this does not need kspqce and other plotting. and it must return seq objects

Isn't this what Sequence.read() does?

@mzaiss

mzaiss commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

yes, but you need to define a seq first. so its a nice mini helper function, that coukd be extended to limit tests that also run on a real scanner. that's what i thought you had in mind. but i take all my comments from this thread now back as i think im confusing everybody. please decide not based on my comments.

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