Skip to content

Update safety PNS code and add chronaxie/rheobase Python port#385

Open
LeoMcBills wants to merge 14 commits into
masterfrom
safety
Open

Update safety PNS code and add chronaxie/rheobase Python port#385
LeoMcBills wants to merge 14 commits into
masterfrom
safety

Conversation

@LeoMcBills

Copy link
Copy Markdown
Collaborator
  • Updates safe_pns.py with the latest safety branch changes.
  • Adds src/pypulseq/safety/pns/chronaxie_rheobase.py.
  • Keeps PNS safety tooling in Python and ready for integration/testing in the main code path.

@github-actions

github-actions Bot commented Apr 27, 2026

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/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.py685716%63–162
   ext_test_report.py1661193%78, 155, 166–167, 336–342
   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.py63312880%10–13, 105–115, 136–149, 196, 261–264, 311, 355, 431, 458–463, 510, 546–549, 640, 668–677, 689, 711, 752–755, 809, 847, 858–859, 865, 876, 882, 884, 892, 925–933, 1063, 1153, 1159, 1162, 1165, 1202, 1327–1340, 1398, 1420–1422, 1443, 1506, 1514, 1612, 1623–1636, 1705–1706, 1717–1735, 1759, 1789–1797, 1833, 1847–1857
   write_seq.py362798%45, 77–79, 313, 347–349, 499
/home/runner/.local/lib/python3.12/site-packages/pypulseq/safety/pns
   chronaxie_rheobase.py1731655%14, 40–232, 237–244, 249–270, 274
   safe_pns.py12711410%50–87, 102–189, 197–214, 222, 244–250, 279–286, 310–336, 344–383, 396–412, 416
/home/runner/.local/lib/python3.12/site-packages/pypulseq/safety/sar4seq
   q_mat_gen.py21210%1–34
   sar4seq.py1091017%42–103, 109–126, 143–155, 161–216, 221–232
   vop_qmatrices_v3.py73730%1–107
/home/runner/.local/lib/python3.12/site-packages/pypulseq/utils
   cumsum.py14193%17
   paper_plot.py63588%47–130
   seq_plot.py38919051%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, 476–485, 497, 512–522, 531–533, 551–553, 555–556, 558–559, 592–604, 619–620, 636–653, 694–698
   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
TOTAL5555199164% 

Tests Skipped Failures Errors Time
1465 24 💤 0 ❌ 0 🔥 3m 41s ⏱️

@schuenke

schuenke commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Wouldn't it make more sense to keep this as a separate package, which we add as an additional dependency so that we can call the functions in Sequence.calc_pns() etc

@btasdelen

Copy link
Copy Markdown
Collaborator

I agree with @schuenke, this can be an optional dependency.

@sairamgeethanath

sairamgeethanath commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Hi @schuenke, @btasdelen, @LeoMcBills — thank you all for pushing this forward. I think improving the structure of calc_pns and making it easier to connect to external PNS tools is a good direction.

One point I would like us to be careful about is vendor neutrality, especially because this is safety-related code. My understanding is that the current calc_pns implementation includes a Siemens-native implementation of the SAFE model. That is useful, but it is not directly applicable to GE, where the behavior is not filter-dependent in the same way, and it is only partly extensible to Philips, which would require a two-filter implementation.

So if we restructure calc_pns to call external packages or vendor-specific implementations, I think we should try to do this consistently for all major vendors rather than solving it only for one pathway. I would be comfortable with either approach: adding an explicit argument to calc_pns to specify the vendor/model, or allowing optional imported dependencies for vendor-specific PNS calculations. My main request is that whatever structure we adopt should make the vendor-specific assumptions explicit and should be extensible across Siemens, GE, and Philips.

I just want to make sure that, because this touches safety, PyPulseq remains transparent and vendor-neutral.

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.

4 participants