pypulseqpp 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pypulseqpp-0.0.1/.gitattributes +11 -0
- pypulseqpp-0.0.1/.github/ISSUE_TEMPLATE/bug_report.yml +42 -0
- pypulseqpp-0.0.1/.github/ISSUE_TEMPLATE/config.yml +8 -0
- pypulseqpp-0.0.1/.github/ISSUE_TEMPLATE/feature_request.yml +31 -0
- pypulseqpp-0.0.1/.github/PULL_REQUEST_TEMPLATE.md +24 -0
- pypulseqpp-0.0.1/.github/dependabot.yml +36 -0
- pypulseqpp-0.0.1/.github/workflows/codeql.yml +33 -0
- pypulseqpp-0.0.1/.github/workflows/docs.yml +131 -0
- pypulseqpp-0.0.1/.github/workflows/style.yml +42 -0
- pypulseqpp-0.0.1/.github/workflows/tags-release.yml +58 -0
- pypulseqpp-0.0.1/.github/workflows/test-ci.yml +74 -0
- pypulseqpp-0.0.1/.github/workflows/viewer-release.yml +30 -0
- pypulseqpp-0.0.1/.github/workflows/viewer-wheels.yml +104 -0
- pypulseqpp-0.0.1/.github/workflows/wheels.yml +70 -0
- pypulseqpp-0.0.1/.gitignore +31 -0
- pypulseqpp-0.0.1/.gitmodules +6 -0
- pypulseqpp-0.0.1/.pre-commit-config.yaml +32 -0
- pypulseqpp-0.0.1/AGENTS.md +301 -0
- pypulseqpp-0.0.1/CLAUDE.md +302 -0
- pypulseqpp-0.0.1/CMakeLists.txt +78 -0
- pypulseqpp-0.0.1/CODE_OF_CONDUCT.md +42 -0
- pypulseqpp-0.0.1/CONTRIBUTING.md +101 -0
- pypulseqpp-0.0.1/GEMINI.md +302 -0
- pypulseqpp-0.0.1/LICENSE +21 -0
- pypulseqpp-0.0.1/LICENSES/SigPy-BSD-3-Clause.txt +13 -0
- pypulseqpp-0.0.1/LICENSES/pocketfft-BSD-3-Clause.txt +41 -0
- pypulseqpp-0.0.1/LICENSES/safe_pns_prediction-BSD-3-Clause.txt +29 -0
- pypulseqpp-0.0.1/NEXT.md +89 -0
- pypulseqpp-0.0.1/PKG-INFO +128 -0
- pypulseqpp-0.0.1/README.md +79 -0
- pypulseqpp-0.0.1/SECURITY.md +33 -0
- pypulseqpp-0.0.1/benchmarks/throughput.py +76 -0
- pypulseqpp-0.0.1/codecov.yml +24 -0
- pypulseqpp-0.0.1/docs/Makefile +14 -0
- pypulseqpp-0.0.1/docs/_templates/autosummary/base.rst +5 -0
- pypulseqpp-0.0.1/docs/_templates/autosummary/class.rst +20 -0
- pypulseqpp-0.0.1/docs/_templates/autosummary/function.rst +5 -0
- pypulseqpp-0.0.1/docs/_templates/autosummary/module.rst +41 -0
- pypulseqpp-0.0.1/docs/api/cli.md +19 -0
- pypulseqpp-0.0.1/docs/api/events.md +52 -0
- pypulseqpp-0.0.1/docs/api/gradients.md +43 -0
- pypulseqpp-0.0.1/docs/api/index.md +65 -0
- pypulseqpp-0.0.1/docs/api/modules.md +119 -0
- pypulseqpp-0.0.1/docs/api/plotting.md +28 -0
- pypulseqpp-0.0.1/docs/api/rf.md +52 -0
- pypulseqpp-0.0.1/docs/api/safety.md +58 -0
- pypulseqpp-0.0.1/docs/api/sampling.md +53 -0
- pypulseqpp-0.0.1/docs/api/sequence.md +59 -0
- pypulseqpp-0.0.1/docs/api/timing.md +21 -0
- pypulseqpp-0.0.1/docs/api/trajectories.md +23 -0
- pypulseqpp-0.0.1/docs/conf.py +61 -0
- pypulseqpp-0.0.1/docs/developer_guide.md +1 -0
- pypulseqpp-0.0.1/docs/examples/index.md +1 -0
- pypulseqpp-0.0.1/docs/index.md +36 -0
- pypulseqpp-0.0.1/docs/misc/code_of_conduct.md +1 -0
- pypulseqpp-0.0.1/docs/misc/contributors.md +1 -0
- pypulseqpp-0.0.1/docs/misc/license.md +1 -0
- pypulseqpp-0.0.1/docs/misc/related.md +1 -0
- pypulseqpp-0.0.1/docs/user_guide.md +1 -0
- pypulseqpp-0.0.1/examples/sequence/__init__.py +20 -0
- pypulseqpp-0.0.1/examples/sequence/gre2D_sequence.py +466 -0
- pypulseqpp-0.0.1/external/MRArbGrad/.gitignore +13 -0
- pypulseqpp-0.0.1/external/MRArbGrad/CHANGELOG +44 -0
- pypulseqpp-0.0.1/external/MRArbGrad/LICENSE +7 -0
- pypulseqpp-0.0.1/external/MRArbGrad/MANIFEST.in +1 -0
- pypulseqpp-0.0.1/external/MRArbGrad/README.md +34 -0
- pypulseqpp-0.0.1/external/MRArbGrad/copy.bash +16 -0
- pypulseqpp-0.0.1/external/MRArbGrad/example/example_BuiltInTraj.py +105 -0
- pypulseqpp-0.0.1/external/MRArbGrad/example/example_ExternalFunction2D.py +80 -0
- pypulseqpp-0.0.1/external/MRArbGrad/example/example_ExternalSamples2D.py +84 -0
- pypulseqpp-0.0.1/external/MRArbGrad/example/example_ExternalSamples3D.py +72 -0
- pypulseqpp-0.0.1/external/MRArbGrad/example/requirements.txt +1 -0
- pypulseqpp-0.0.1/external/MRArbGrad/install.bash +9 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/Function.py +570 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/Utility.py +330 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/__init__.py +6 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/mag/Mag.cpp +446 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/mag/Mag.h +197 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/main.cpp +871 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/traj/Cones.h +141 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/traj/MrTraj.h +414 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/traj/MrTraj_2D.h +63 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/traj/Rosette.h +105 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/traj/Seiffert.h +198 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/traj/Shell3d.h +107 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/traj/Spiral.h +60 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/traj/TrajFunc.h +90 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/traj/VDSpiral.h +113 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/traj/Yarnball.h +146 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/utility/Intp.h +90 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/utility/LinIntp.h +71 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/utility/SplineIntp.h +134 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/utility/global.cpp +1 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/utility/global.h +68 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/utility/v3.cpp +450 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/ext/utility/v3.h +72 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/trajfunc/__init__.py +1 -0
- pypulseqpp-0.0.1/external/MRArbGrad/mrarbgrad_src/trajfunc/main.py +38 -0
- pypulseqpp-0.0.1/external/MRArbGrad/push.bash +3 -0
- pypulseqpp-0.0.1/external/MRArbGrad/pyproject.toml +20 -0
- pypulseqpp-0.0.1/external/MRArbGrad/requirements.txt +3 -0
- pypulseqpp-0.0.1/external/MRArbGrad/setup.py +62 -0
- pypulseqpp-0.0.1/external/MRArbGrad/upload.bash +3 -0
- pypulseqpp-0.0.1/external/MRArbGrad/upload_twine.bash +3 -0
- pypulseqpp-0.0.1/external/NOTICE.md +44 -0
- pypulseqpp-0.0.1/pyproject.toml +171 -0
- pypulseqpp-0.0.1/scripts/build_docs.sh +56 -0
- pypulseqpp-0.0.1/scripts/format_and_lint.sh +21 -0
- pypulseqpp-0.0.1/scripts/sync_agent_docs.sh +29 -0
- pypulseqpp-0.0.1/setup.py +5 -0
- pypulseqpp-0.0.1/src/cpp/bindings/arbgrad.cpp +232 -0
- pypulseqpp-0.0.1/src/cpp/bindings/arbgrad.h +10 -0
- pypulseqpp-0.0.1/src/cpp/bindings/module.cpp +1826 -0
- pypulseqpp-0.0.1/src/cpp/bindings/ptx.cpp +792 -0
- pypulseqpp-0.0.1/src/cpp/bindings/ptx.h +10 -0
- pypulseqpp-0.0.1/src/cpp/bindings/pulseqpp_decode.h +357 -0
- pypulseqpp-0.0.1/src/cpp/bindings/pulseqpp_events.h +1178 -0
- pypulseqpp-0.0.1/src/cpp/bindings/pulseqpp_eventtypes.cpp +1392 -0
- pypulseqpp-0.0.1/src/cpp/bindings/pulseqpp_eventtypes.h +349 -0
- pypulseqpp-0.0.1/src/cpp/bindings/sampling.cpp +427 -0
- pypulseqpp-0.0.1/src/cpp/bindings/sampling.h +10 -0
- pypulseqpp-0.0.1/src/cpp/bindings/sim.cpp +194 -0
- pypulseqpp-0.0.1/src/cpp/bindings/sim.h +10 -0
- pypulseqpp-0.0.1/src/cpp/bindings/slr.cpp +375 -0
- pypulseqpp-0.0.1/src/cpp/bindings/slr.h +10 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/analysis.cpp +377 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/analysis.hpp +97 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/binary.hpp +87 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/channels.hpp +41 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/corners.cpp +232 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/corners.hpp +85 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/dedup.cpp +798 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/events.hpp +262 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/fov.cpp +1031 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/fov.hpp +124 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/kspace.cpp +612 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/kspace.hpp +84 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/md5.cpp +138 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/md5.hpp +26 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/parsed.hpp +87 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/pns.cpp +175 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/pns.hpp +92 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/raster.cpp +132 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/raster.hpp +94 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/read.cpp +1058 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/read.hpp +32 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/read_binary.cpp +455 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/resonance.cpp +225 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/resonance.hpp +90 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/rf_safety.cpp +394 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/rf_safety.hpp +102 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/rfft.cpp +195 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/rfft.hpp +59 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/safety.cpp +603 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/safety.hpp +126 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/sequence.cpp +1107 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/sequence.hpp +1722 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/shape.cpp +349 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/shape.hpp +48 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/timing.cpp +685 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/timing.hpp +105 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/types.hpp +133 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/waveforms.cpp +482 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/waveforms.hpp +105 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/write.hpp +74 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/write_binary.cpp +510 -0
- pypulseqpp-0.0.1/src/cpp/pulseq/write_text.cpp +1262 -0
- pypulseqpp-0.0.1/src/cpp/third_party/pocketfft_hdronly.h +3853 -0
- pypulseqpp-0.0.1/src/pypulseqpp/__init__.py +298 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_accelerators.py +67 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_adiabatic.py +328 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_angles.py +316 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_arbgrad/__init__.py +224 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_b1_pulses.py +397 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_band_phases.py +103 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_block_to_events.py +74 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_calc_rf_bandwidth.py +167 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_calc_rf_power.py +68 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_check_timing.py +220 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_epi.py +170 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_events.py +431 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_gradients.py +441 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_kspace.py +164 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_make_hexagon_gradient_area.py +408 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_make_label.py +57 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_make_rf_shim.py +41 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_make_rotation.py +165 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_masks.py +875 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_opts.py +202 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_ordering.py +121 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_ptx.py +477 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_report.py +349 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_results.py +147 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_rf_pulses.py +1006 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_rotate_3d.py +163 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_sampling.py +85 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_schedules.py +158 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_sequence.py +1454 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_sim_rf.py +230 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_slice_encoding.py +364 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_slr.py +700 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_timing.py +170 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_traj_to_grad.py +121 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_trajectories.py +279 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_transform_fov.py +264 -0
- pypulseqpp-0.0.1/src/pypulseqpp/_waveforms.py +346 -0
- pypulseqpp-0.0.1/src/pypulseqpp/cli/__init__.py +237 -0
- pypulseqpp-0.0.1/src/pypulseqpp/plot/__init__.py +23 -0
- pypulseqpp-0.0.1/src/pypulseqpp/plot/_kspace.py +206 -0
- pypulseqpp-0.0.1/src/pypulseqpp/plot/_paper.py +211 -0
- pypulseqpp-0.0.1/src/pypulseqpp/plot/_rf.py +386 -0
- pypulseqpp-0.0.1/src/pypulseqpp/plot/_seqeyes.py +433 -0
- pypulseqpp-0.0.1/src/pypulseqpp/plot/_style.py +68 -0
- pypulseqpp-0.0.1/src/pypulseqpp/safety/__init__.py +172 -0
- pypulseqpp-0.0.1/src/pypulseqpp/safety/_physical.py +22 -0
- pypulseqpp-0.0.1/src/pypulseqpp/safety/_pns.py +142 -0
- pypulseqpp-0.0.1/src/pypulseqpp/safety/_resonance.py +296 -0
- pypulseqpp-0.0.1/src/pypulseqpp/safety/_sar.py +382 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/__init__.py +162 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/_module.py +290 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/excitation/__init__.py +24 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/excitation/_base.py +55 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/excitation/multiband.py +304 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/excitation/nonselective.py +226 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/excitation/selective.py +273 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/excitation/spatial2d.py +115 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/excitation/spectral.py +233 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/preparation/__init__.py +26 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/preparation/_common.py +19 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/preparation/diffusion.py +245 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/preparation/fatsat.py +229 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/preparation/inversion.py +106 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/preparation/saturation.py +382 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/preparation/t2prep.py +222 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/__init__.py +48 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/_common.py +183 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/_trajectories.py +841 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/bssfp.py +358 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/epi.py +684 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/fse.py +519 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/line.py +510 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/navigator.py +226 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/noncartesian.py +1067 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/propeller.py +208 -0
- pypulseqpp-0.0.1/src/pypulseqpp/sequences/readout/zte.py +361 -0
- pypulseqpp-0.0.1/tests/conftest.py +42 -0
- pypulseqpp-0.0.1/tests/convert.py +142 -0
- pypulseqpp-0.0.1/tests/cpp/sanitize.cpp +265 -0
- pypulseqpp-0.0.1/tests/extended.py +127 -0
- pypulseqpp-0.0.1/tests/reference.py +430 -0
- pypulseqpp-0.0.1/tests/requirements.txt +12 -0
- pypulseqpp-0.0.1/tests/seq/NOTICE.md +16 -0
- pypulseqpp-0.0.1/tests/seq/seq1.seq +68 -0
- pypulseqpp-0.0.1/tests/seq/seq1_m.seq +70 -0
- pypulseqpp-0.0.1/tests/seq/seq2.seq +73 -0
- pypulseqpp-0.0.1/tests/seq/seq2_m.seq +75 -0
- pypulseqpp-0.0.1/tests/seq/seq3.seq +136 -0
- pypulseqpp-0.0.1/tests/seq/seq3_m.seq +138 -0
- pypulseqpp-0.0.1/tests/seq/seq4.seq +154 -0
- pypulseqpp-0.0.1/tests/seq/seq4_m.seq +156 -0
- pypulseqpp-0.0.1/tests/seq/seq5.seq +1315 -0
- pypulseqpp-0.0.1/tests/seq/seq6.seq +147 -0
- pypulseqpp-0.0.1/tests/seq/seq_adc_only.seq +33 -0
- pypulseqpp-0.0.1/tests/seq/seq_ext_only.seq +45 -0
- pypulseqpp-0.0.1/tests/seq/seq_make_block_pulses.seq +79 -0
- pypulseqpp-0.0.1/tests/seq/seq_make_block_pulses_m.seq +75 -0
- pypulseqpp-0.0.1/tests/seq/seq_make_gauss_pulses.seq +9055 -0
- pypulseqpp-0.0.1/tests/seq/seq_make_gauss_pulses_m.seq +5083 -0
- pypulseqpp-0.0.1/tests/seq/seq_make_radial.seq +92 -0
- pypulseqpp-0.0.1/tests/seq/seq_make_sinc_pulses.seq +9124 -0
- pypulseqpp-0.0.1/tests/seq/seq_make_sinc_pulses_m.seq +10107 -0
- pypulseqpp-0.0.1/tests/seq/seq_trap_only.seq +33 -0
- pypulseqpp-0.0.1/tests/seq/simple_mprage120.seq +3666 -0
- pypulseqpp-0.0.1/tests/seq/simple_mprage130.seq +3706 -0
- pypulseqpp-0.0.1/tests/seq/simple_mprage131.seq +3706 -0
- pypulseqpp-0.0.1/tests/seq/simple_mprage140.seq +3687 -0
- pypulseqpp-0.0.1/tests/seq/simple_mprage141.seq +3687 -0
- pypulseqpp-0.0.1/tests/seq/simple_mprage142.seq +3687 -0
- pypulseqpp-0.0.1/tests/seq/simple_mprage150.seq +3688 -0
- pypulseqpp-0.0.1/tests/seq/write_epi.seq +3466 -0
- pypulseqpp-0.0.1/tests/seq/write_epi_label.seq +8768 -0
- pypulseqpp-0.0.1/tests/seq/write_epi_se.seq +3227 -0
- pypulseqpp-0.0.1/tests/seq/write_epi_se_rs.seq +10341 -0
- pypulseqpp-0.0.1/tests/seq/write_gre.seq +3504 -0
- pypulseqpp-0.0.1/tests/seq/write_gre_label.seq +3527 -0
- pypulseqpp-0.0.1/tests/seq/write_gre_label_softdelay.seq +3666 -0
- pypulseqpp-0.0.1/tests/seq/write_haste.seq +4911 -0
- pypulseqpp-0.0.1/tests/seq/write_mprage.seq +8268 -0
- pypulseqpp-0.0.1/tests/seq/write_radial_gre.seq +4698 -0
- pypulseqpp-0.0.1/tests/seq/write_tse.seq +5096 -0
- pypulseqpp-0.0.1/tests/seq/write_ute.seq +1429 -0
- pypulseqpp-0.0.1/tests/test_absolute_trajectory.py +129 -0
- pypulseqpp-0.0.1/tests/test_adiabatic.py +137 -0
- pypulseqpp-0.0.1/tests/test_arbgrad_spiral.py +111 -0
- pypulseqpp-0.0.1/tests/test_b1_and_recursive_pulses.py +160 -0
- pypulseqpp-0.0.1/tests/test_binary.py +214 -0
- pypulseqpp-0.0.1/tests/test_binary_signature.py +110 -0
- pypulseqpp-0.0.1/tests/test_block.py +167 -0
- pypulseqpp-0.0.1/tests/test_block_k_origins.py +190 -0
- pypulseqpp-0.0.1/tests/test_block_to_events.py +68 -0
- pypulseqpp-0.0.1/tests/test_calc_rf_bandwidth.py +133 -0
- pypulseqpp-0.0.1/tests/test_check_timing.py +610 -0
- pypulseqpp-0.0.1/tests/test_corpus.py +291 -0
- pypulseqpp-0.0.1/tests/test_design_excitation.py +273 -0
- pypulseqpp-0.0.1/tests/test_design_excitation_selective_pulses.py +422 -0
- pypulseqpp-0.0.1/tests/test_design_fatsat.py +308 -0
- pypulseqpp-0.0.1/tests/test_design_module.py +270 -0
- pypulseqpp-0.0.1/tests/test_design_preparation.py +427 -0
- pypulseqpp-0.0.1/tests/test_design_promoted.py +188 -0
- pypulseqpp-0.0.1/tests/test_design_readout_bssfp.py +438 -0
- pypulseqpp-0.0.1/tests/test_design_readout_epi.py +501 -0
- pypulseqpp-0.0.1/tests/test_design_readout_fse.py +552 -0
- pypulseqpp-0.0.1/tests/test_design_readout_line.py +408 -0
- pypulseqpp-0.0.1/tests/test_design_readout_navigator.py +133 -0
- pypulseqpp-0.0.1/tests/test_design_readout_noncartesian.py +650 -0
- pypulseqpp-0.0.1/tests/test_design_readout_propeller.py +233 -0
- pypulseqpp-0.0.1/tests/test_design_readout_wave.py +232 -0
- pypulseqpp-0.0.1/tests/test_design_readout_zte.py +420 -0
- pypulseqpp-0.0.1/tests/test_design_refocusing.py +211 -0
- pypulseqpp-0.0.1/tests/test_design_slice_rephasing.py +282 -0
- pypulseqpp-0.0.1/tests/test_docstrings.py +49 -0
- pypulseqpp-0.0.1/tests/test_evaluate_labels.py +162 -0
- pypulseqpp-0.0.1/tests/test_examples.py +227 -0
- pypulseqpp-0.0.1/tests/test_facade.py +983 -0
- pypulseqpp-0.0.1/tests/test_fov_shift.py +274 -0
- pypulseqpp-0.0.1/tests/test_get_block.py +192 -0
- pypulseqpp-0.0.1/tests/test_gradient_axes.py +245 -0
- pypulseqpp-0.0.1/tests/test_interoperability.py +85 -0
- pypulseqpp-0.0.1/tests/test_kspace.py +455 -0
- pypulseqpp-0.0.1/tests/test_labels.py +84 -0
- pypulseqpp-0.0.1/tests/test_make_rotation.py +108 -0
- pypulseqpp-0.0.1/tests/test_matlab_parity.py +289 -0
- pypulseqpp-0.0.1/tests/test_mech_resonance.py +422 -0
- pypulseqpp-0.0.1/tests/test_opts.py +161 -0
- pypulseqpp-0.0.1/tests/test_opts_cap_system.py +79 -0
- pypulseqpp-0.0.1/tests/test_paper_plot.py +190 -0
- pypulseqpp-0.0.1/tests/test_parity.py +80 -0
- pypulseqpp-0.0.1/tests/test_plot.py +357 -0
- pypulseqpp-0.0.1/tests/test_plotting.py +311 -0
- pypulseqpp-0.0.1/tests/test_pns.py +292 -0
- pypulseqpp-0.0.1/tests/test_promoted_columns.py +107 -0
- pypulseqpp-0.0.1/tests/test_ptx.py +136 -0
- pypulseqpp-0.0.1/tests/test_ptx_design.py +258 -0
- pypulseqpp-0.0.1/tests/test_ptx_kernels.py +184 -0
- pypulseqpp-0.0.1/tests/test_pypulseq_base_factories.py +365 -0
- pypulseqpp-0.0.1/tests/test_pypulseq_epi_order.py +221 -0
- pypulseqpp-0.0.1/tests/test_pypulseq_simulate.py +146 -0
- pypulseqpp-0.0.1/tests/test_read.py +201 -0
- pypulseqpp-0.0.1/tests/test_repetition.py +352 -0
- pypulseqpp-0.0.1/tests/test_report.py +334 -0
- pypulseqpp-0.0.1/tests/test_rf_power.py +145 -0
- pypulseqpp-0.0.1/tests/test_rf_shim.py +87 -0
- pypulseqpp-0.0.1/tests/test_rotation_convention.py +103 -0
- pypulseqpp-0.0.1/tests/test_rotation_extension.py +133 -0
- pypulseqpp-0.0.1/tests/test_safety.py +546 -0
- pypulseqpp-0.0.1/tests/test_sampling_angles.py +36 -0
- pypulseqpp-0.0.1/tests/test_sampling_cartesian.py +125 -0
- pypulseqpp-0.0.1/tests/test_sampling_orderings.py +98 -0
- pypulseqpp-0.0.1/tests/test_sampling_poisson.py +106 -0
- pypulseqpp-0.0.1/tests/test_sar.py +350 -0
- pypulseqpp-0.0.1/tests/test_sequence.py +209 -0
- pypulseqpp-0.0.1/tests/test_shape.py +149 -0
- pypulseqpp-0.0.1/tests/test_sim_bloch.py +166 -0
- pypulseqpp-0.0.1/tests/test_slice_encoding.py +144 -0
- pypulseqpp-0.0.1/tests/test_slr_design.py +256 -0
- pypulseqpp-0.0.1/tests/test_smoke.py +8 -0
- pypulseqpp-0.0.1/tests/test_soft_delays.py +203 -0
- pypulseqpp-0.0.1/tests/test_structure.py +480 -0
- pypulseqpp-0.0.1/tests/test_transform_fov.py +925 -0
- pypulseqpp-0.0.1/tests/test_v141.py +129 -0
- pypulseqpp-0.0.1/tests/test_version.py +58 -0
- pypulseqpp-0.0.1/tests/test_waveforms.py +315 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something behaves differently from what it says it does.
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: what-happened
|
|
7
|
+
attributes:
|
|
8
|
+
label: What happened
|
|
9
|
+
description: What did you expect, and what did you get instead?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: reproduce
|
|
15
|
+
attributes:
|
|
16
|
+
label: Smallest reproduction
|
|
17
|
+
description: >
|
|
18
|
+
Code we can run. Prefer synthetic arrays over a data file; if the shape
|
|
19
|
+
of real data matters, give the shapes and dtypes.
|
|
20
|
+
render: python
|
|
21
|
+
validations:
|
|
22
|
+
required: true
|
|
23
|
+
|
|
24
|
+
- type: textarea
|
|
25
|
+
id: environment
|
|
26
|
+
attributes:
|
|
27
|
+
label: Environment
|
|
28
|
+
description: >
|
|
29
|
+
Output of `python -c "import pypulseqpp, sys, torch;
|
|
30
|
+
print(pypulseqpp.__version__, sys.version, torch.__version__,
|
|
31
|
+
torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'cpu')"`
|
|
32
|
+
render: shell
|
|
33
|
+
validations:
|
|
34
|
+
required: true
|
|
35
|
+
|
|
36
|
+
- type: dropdown
|
|
37
|
+
id: device
|
|
38
|
+
attributes:
|
|
39
|
+
label: Where it happens
|
|
40
|
+
options: ["CPU only", "CUDA only", "Both"]
|
|
41
|
+
validations:
|
|
42
|
+
required: true
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Question or idea
|
|
4
|
+
url: https://github.com/pulserver/pypulseqpp/discussions
|
|
5
|
+
about: Ask about usage, or propose something before it is a bug report.
|
|
6
|
+
- name: Security vulnerability
|
|
7
|
+
url: https://github.com/pulserver/pypulseqpp/security/advisories/new
|
|
8
|
+
about: Report privately. Please do not open a public issue.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Something this package should be able to do and cannot.
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: The problem
|
|
9
|
+
description: What are you trying to do, and where does it stop?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: proposal
|
|
15
|
+
attributes:
|
|
16
|
+
label: What you have in mind
|
|
17
|
+
description: >
|
|
18
|
+
A sketch of the API, if you have one. If there is a paper or another
|
|
19
|
+
implementation that does this, name it — that is usually the fastest
|
|
20
|
+
way to agree on what is wanted.
|
|
21
|
+
validations:
|
|
22
|
+
required: true
|
|
23
|
+
|
|
24
|
+
- type: textarea
|
|
25
|
+
id: layer
|
|
26
|
+
attributes:
|
|
27
|
+
label: Which layer this belongs to
|
|
28
|
+
description: >
|
|
29
|
+
This package is one of a family with a strict layering (`mrutils` at the
|
|
30
|
+
base, `deepmr` at the top). If the feature needs something from a
|
|
31
|
+
sibling package, say which — that usually means it belongs elsewhere.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
## What this changes
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences. What behaviour is different afterwards? -->
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
<!-- The problem this solves. Link the issue if there is one. -->
|
|
8
|
+
|
|
9
|
+
## How it was verified
|
|
10
|
+
|
|
11
|
+
<!-- The commands you ran and what they said. Paste the output, don't
|
|
12
|
+
summarise it. "Tests pass" is not verification. -->
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Checklist
|
|
18
|
+
|
|
19
|
+
- [ ] `bash scripts/format_and_lint.sh` is clean
|
|
20
|
+
- [ ] `pytest -q` passes, and new behaviour has a test whose name states the
|
|
21
|
+
invariant it protects
|
|
22
|
+
- [ ] Anything numerical is exercised on CPU and CUDA, or the CUDA leg is
|
|
23
|
+
marked `@pytest.mark.cuda` and skips cleanly
|
|
24
|
+
- [ ] No comment or docstring describes the code's history
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# The Actions in .github/workflows pin third-party code that runs with
|
|
4
|
+
# repository credentials, so these are the updates worth having weekly.
|
|
5
|
+
- package-ecosystem: github-actions
|
|
6
|
+
directory: "/"
|
|
7
|
+
schedule:
|
|
8
|
+
interval: weekly
|
|
9
|
+
day: monday
|
|
10
|
+
labels: ["dependencies", "ci"]
|
|
11
|
+
commit-message:
|
|
12
|
+
prefix: "ci"
|
|
13
|
+
groups:
|
|
14
|
+
actions:
|
|
15
|
+
patterns: ["*"]
|
|
16
|
+
|
|
17
|
+
- package-ecosystem: pip
|
|
18
|
+
directory: "/"
|
|
19
|
+
schedule:
|
|
20
|
+
interval: weekly
|
|
21
|
+
day: monday
|
|
22
|
+
open-pull-requests-limit: 5
|
|
23
|
+
labels: ["dependencies", "python"]
|
|
24
|
+
commit-message:
|
|
25
|
+
prefix: "deps"
|
|
26
|
+
groups:
|
|
27
|
+
# The reference implementation moves the parity fixtures with it, so its
|
|
28
|
+
# bumps arrive alone and get a full run of their own.
|
|
29
|
+
reference:
|
|
30
|
+
patterns: ["pypulseq"]
|
|
31
|
+
numerical:
|
|
32
|
+
patterns: ["numpy"]
|
|
33
|
+
build:
|
|
34
|
+
patterns: ["scikit-build-core", "pybind11", "setuptools_scm"]
|
|
35
|
+
dev-tooling:
|
|
36
|
+
patterns: ["pytest*", "coverage", "ruff", "pre-commit", "build"]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
analyze:
|
|
11
|
+
name: Analyze Python
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
# Code scanning on a private repository needs GitHub Advanced Security,
|
|
14
|
+
# and uploading results without it is a hard error rather than a warning.
|
|
15
|
+
# The job stands down while the repository is private and starts working
|
|
16
|
+
# on its own once it is made public.
|
|
17
|
+
if: github.event.repository.visibility == 'public'
|
|
18
|
+
permissions:
|
|
19
|
+
security-events: write
|
|
20
|
+
packages: read
|
|
21
|
+
actions: read
|
|
22
|
+
contents: read
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v7
|
|
25
|
+
with:
|
|
26
|
+
submodules: recursive # the solver in external/ is compiled in
|
|
27
|
+
- uses: github/codeql-action/init@v4
|
|
28
|
+
with:
|
|
29
|
+
languages: python
|
|
30
|
+
build-mode: none
|
|
31
|
+
- uses: github/codeql-action/analyze@v4
|
|
32
|
+
with:
|
|
33
|
+
category: "/language:python"
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
# Builds the documentation and publishes it to GitHub Pages, which serves the
|
|
4
|
+
# gh-pages branch. The site holds one directory per version: main publishes
|
|
5
|
+
# `latest`, a release tag publishes `vX.Y.Z` and copies it to `stable`, and the
|
|
6
|
+
# root redirects to whichever of the two a reader should see. Pull requests
|
|
7
|
+
# build without publishing, so a documentation warning fails review rather than
|
|
8
|
+
# the site.
|
|
9
|
+
#
|
|
10
|
+
# The branch is the site's archive. GitHub Pages can be deployed from an
|
|
11
|
+
# artifact instead, but a deployment replaces the whole site, so publishing one
|
|
12
|
+
# version would drop the others.
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: [main]
|
|
17
|
+
tags: ["v[0-9]+.[0-9]+.[0-9]+"]
|
|
18
|
+
pull_request:
|
|
19
|
+
workflow_dispatch:
|
|
20
|
+
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
|
|
24
|
+
# Every publish commits to the same branch, so main, the tags and a manual run
|
|
25
|
+
# share one group and wait for each other rather than racing to push. A pull
|
|
26
|
+
# request publishes nothing and gets a group of its own.
|
|
27
|
+
concurrency:
|
|
28
|
+
group: docs-${{ github.event.pull_request.number || 'publish' }}
|
|
29
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
30
|
+
|
|
31
|
+
jobs:
|
|
32
|
+
docs:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
permissions:
|
|
35
|
+
contents: write # the publish step pushes the built site to gh-pages
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v7
|
|
38
|
+
with:
|
|
39
|
+
submodules: recursive # the solver in external/ is compiled in
|
|
40
|
+
fetch-depth: 0 # setuptools_scm reads the tags
|
|
41
|
+
|
|
42
|
+
- uses: actions/setup-python@v7
|
|
43
|
+
with:
|
|
44
|
+
python-version: "3.12"
|
|
45
|
+
cache: pip
|
|
46
|
+
|
|
47
|
+
- name: Name this version
|
|
48
|
+
id: version
|
|
49
|
+
# A release is built as `stable`, the URL a reader should land on, and
|
|
50
|
+
# archived under its tag as well; the canonical link in both copies
|
|
51
|
+
# points at `stable`, so a search result leads to the current release
|
|
52
|
+
# rather than to whichever version was indexed first.
|
|
53
|
+
run: |
|
|
54
|
+
if [ "$GITHUB_REF_TYPE" = tag ]; then
|
|
55
|
+
echo "dir=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
|
|
56
|
+
echo "canonical=stable" >> "$GITHUB_OUTPUT"
|
|
57
|
+
else
|
|
58
|
+
echo "dir=latest" >> "$GITHUB_OUTPUT"
|
|
59
|
+
echo "canonical=latest" >> "$GITHUB_OUTPUT"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
- name: Install
|
|
63
|
+
# Into the CMake build directory build_docs.sh uses, so the build it
|
|
64
|
+
# makes for Sphinx reuses these objects rather than compiling twice.
|
|
65
|
+
run: |
|
|
66
|
+
python -m pip install --upgrade pip
|
|
67
|
+
python -m pip install -Cbuild-dir="$PWD/docs/build/cmake" '.[doc]'
|
|
68
|
+
|
|
69
|
+
- name: Build
|
|
70
|
+
env:
|
|
71
|
+
PYPULSEQPP_DOCS_VERSION: ${{ steps.version.outputs.canonical }}
|
|
72
|
+
run: bash scripts/build_docs.sh
|
|
73
|
+
|
|
74
|
+
- name: Check that the site is only the site
|
|
75
|
+
# Sphinx caches parsed documents in the output directory unless given
|
|
76
|
+
# `-d`, and the cache is far larger than the pages. Publishing commits
|
|
77
|
+
# whatever is there to a branch that is never pruned, so a build that
|
|
78
|
+
# leaves it behind has to fail here rather than on main.
|
|
79
|
+
run: |
|
|
80
|
+
if [ -e docs/build/html/.doctrees ]; then
|
|
81
|
+
echo "::error::The doctree cache is inside the built site and would be published." >&2
|
|
82
|
+
exit 1
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
- name: Publish
|
|
86
|
+
if: github.event_name != 'pull_request'
|
|
87
|
+
env:
|
|
88
|
+
DIR: ${{ steps.version.outputs.dir }}
|
|
89
|
+
GH_TOKEN: ${{ github.token }}
|
|
90
|
+
run: |
|
|
91
|
+
site="$RUNNER_TEMP/pages"
|
|
92
|
+
remote="https://x-access-token:$GH_TOKEN@github.com/$GITHUB_REPOSITORY"
|
|
93
|
+
# The branch does not exist before the first publish.
|
|
94
|
+
if ! git clone --depth 1 --branch gh-pages "$remote" "$site"; then
|
|
95
|
+
git init -b gh-pages "$site"
|
|
96
|
+
git -C "$site" remote add origin "$remote"
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# Only this version's directory is replaced; the others stay as the
|
|
100
|
+
# release that built them left them.
|
|
101
|
+
rm -rf "${site:?}/$DIR"
|
|
102
|
+
cp -r docs/build/html "$site/$DIR"
|
|
103
|
+
|
|
104
|
+
# `stable` is the newest release, so a patch tagged after a later
|
|
105
|
+
# release archives itself without taking `stable` backwards.
|
|
106
|
+
if [ "$GITHUB_REF_TYPE" = tag ]; then
|
|
107
|
+
newest=$(ls "$site" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1)
|
|
108
|
+
if [ "$newest" = "$DIR" ]; then
|
|
109
|
+
rm -rf "$site/stable"
|
|
110
|
+
cp -r "$site/$DIR" "$site/stable"
|
|
111
|
+
else
|
|
112
|
+
echo "$newest is newer than $DIR; leaving stable alone."
|
|
113
|
+
fi
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# The root goes to the current release, or to main's pages until
|
|
117
|
+
# there is one.
|
|
118
|
+
target=latest
|
|
119
|
+
[ -d "$site/stable" ] && target=stable
|
|
120
|
+
printf '<!doctype html>\n<meta http-equiv="refresh" content="0; url=%s/">\n' \
|
|
121
|
+
"$target" > "$site/index.html"
|
|
122
|
+
# Pages runs the branch through Jekyll unless told not to, and Jekyll
|
|
123
|
+
# drops the _static and _sources directories Sphinx writes.
|
|
124
|
+
touch "$site/.nojekyll"
|
|
125
|
+
|
|
126
|
+
git -C "$site" add -A
|
|
127
|
+
git -C "$site" -c user.name='github-actions[bot]' \
|
|
128
|
+
-c user.email='41898282+github-actions[bot]@users.noreply.github.com' \
|
|
129
|
+
commit -m "Documentation for $DIR from $GITHUB_SHA" \
|
|
130
|
+
|| { echo "No documentation change to publish."; exit 0; }
|
|
131
|
+
git -C "$site" push origin gh-pages
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Style
|
|
2
|
+
|
|
3
|
+
# Runs the same script pre-commit runs, in --check mode: nothing is rewritten
|
|
4
|
+
# and any file that would change fails the job.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
pull_request:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
format-and-lint:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
with:
|
|
21
|
+
submodules: recursive # the solver in external/ is compiled in
|
|
22
|
+
- uses: actions/setup-python@v7
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.11"
|
|
25
|
+
|
|
26
|
+
# The linter only, taken from the same `dev` extra a contributor's
|
|
27
|
+
# pre-commit installs, so both apply one ruff. Installing the extra whole
|
|
28
|
+
# would download the runtime for a job that never imports it.
|
|
29
|
+
- name: Install ruff
|
|
30
|
+
run: |
|
|
31
|
+
python -m pip install --upgrade pip
|
|
32
|
+
python - <<'PY' > "$RUNNER_TEMP/lint-requirements.txt"
|
|
33
|
+
import tomllib
|
|
34
|
+
|
|
35
|
+
with open("pyproject.toml", "rb") as pyproject:
|
|
36
|
+
dev = tomllib.load(pyproject)["project"]["optional-dependencies"]["dev"]
|
|
37
|
+
print("\n".join(line for line in dev if line.startswith("ruff")))
|
|
38
|
+
PY
|
|
39
|
+
python -m pip install -r "$RUNNER_TEMP/lint-requirements.txt"
|
|
40
|
+
|
|
41
|
+
- name: Format and lint (check only)
|
|
42
|
+
run: bash scripts/format_and_lint.sh --check
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publishes a tagged version: the wheels and sdist from the reusable Wheels
|
|
4
|
+
# workflow, then PyPI and a signed GitHub release. The version comes from the
|
|
5
|
+
# tag via setuptools_scm.
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
tags:
|
|
10
|
+
- "v[0-9]+.[0-9]+.[0-9]+"
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
uses: ./.github/workflows/wheels.yml
|
|
15
|
+
with:
|
|
16
|
+
cibw-build: "cp310-* cp311-* cp312-* cp313-*"
|
|
17
|
+
|
|
18
|
+
publish-to-pypi:
|
|
19
|
+
needs: [build]
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
environment:
|
|
22
|
+
name: pypi
|
|
23
|
+
url: https://pypi.org/p/pypulseqpp
|
|
24
|
+
permissions:
|
|
25
|
+
id-token: write # trusted publishing (OIDC)
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/download-artifact@v8
|
|
28
|
+
with:
|
|
29
|
+
pattern: "{wheels-*,sdist}"
|
|
30
|
+
path: dist
|
|
31
|
+
merge-multiple: true
|
|
32
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
33
|
+
|
|
34
|
+
github-release:
|
|
35
|
+
needs: [publish-to-pypi]
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
permissions:
|
|
38
|
+
contents: write # create the release
|
|
39
|
+
id-token: write # sigstore
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/download-artifact@v8
|
|
42
|
+
with:
|
|
43
|
+
pattern: "{wheels-*,sdist}"
|
|
44
|
+
path: dist
|
|
45
|
+
merge-multiple: true
|
|
46
|
+
- uses: sigstore/gh-action-sigstore-python@v3.5.0
|
|
47
|
+
with:
|
|
48
|
+
inputs: |
|
|
49
|
+
./dist/*.tar.gz
|
|
50
|
+
./dist/*.whl
|
|
51
|
+
- env:
|
|
52
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
53
|
+
run: |
|
|
54
|
+
gh release create '${{ github.ref_name }}' \
|
|
55
|
+
--repo '${{ github.repository }}' \
|
|
56
|
+
--title '${{ github.ref_name }}' \
|
|
57
|
+
--generate-notes
|
|
58
|
+
gh release upload '${{ github.ref_name }}' dist/** --repo '${{ github.repository }}'
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: ${{ matrix.os }} / Python ${{ matrix.python-version }}
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
# Every platform a wheel ships for: the compiled core is the package,
|
|
20
|
+
# so a platform that is not tested is not supported.
|
|
21
|
+
os: [ubuntu-latest, macos-14, windows-latest]
|
|
22
|
+
# The floor and the ceiling of the supported band: an intermediate
|
|
23
|
+
# release that fails on neither is not a plausible failure.
|
|
24
|
+
python-version: ["3.10", "3.13"]
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v7
|
|
27
|
+
with:
|
|
28
|
+
submodules: recursive # the solver in external/ is compiled in
|
|
29
|
+
fetch-depth: 0 # setuptools_scm reads the tags
|
|
30
|
+
|
|
31
|
+
- uses: actions/setup-python@v7
|
|
32
|
+
with:
|
|
33
|
+
python-version: ${{ matrix.python-version }}
|
|
34
|
+
cache: pip
|
|
35
|
+
|
|
36
|
+
- name: Install
|
|
37
|
+
run: |
|
|
38
|
+
python -m pip install --upgrade pip
|
|
39
|
+
python -m pip install .[dev] -r tests/requirements.txt
|
|
40
|
+
|
|
41
|
+
- name: Run the tests
|
|
42
|
+
run: pytest -q --cov --cov-report=xml
|
|
43
|
+
|
|
44
|
+
- uses: codecov/codecov-action@v7
|
|
45
|
+
if: matrix.os == 'ubuntu-latest'
|
|
46
|
+
with:
|
|
47
|
+
fail_ci_if_error: false
|
|
48
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
49
|
+
slug: pulserver/pypulseqpp
|
|
50
|
+
|
|
51
|
+
sanitize:
|
|
52
|
+
name: sanitizers
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v7
|
|
56
|
+
with:
|
|
57
|
+
submodules: recursive # the solver in external/ is compiled in
|
|
58
|
+
|
|
59
|
+
# A read past the end of an array is not a wrong answer, it is whatever
|
|
60
|
+
# was there -- so the tests above catch it only when the memory it lands
|
|
61
|
+
# on differs enough to change a number. One such bug reported the same
|
|
62
|
+
# waveform on five of those six jobs and a different one on the sixth,
|
|
63
|
+
# and gave two different answers within a single process. This is the
|
|
64
|
+
# job that would have named it on the first run.
|
|
65
|
+
- name: Build the core with the sanitizers on
|
|
66
|
+
run: |
|
|
67
|
+
g++ -std=c++17 -g -O1 \
|
|
68
|
+
-fsanitize=address,undefined -fno-sanitize-recover=all \
|
|
69
|
+
-fno-omit-frame-pointer \
|
|
70
|
+
-I src/cpp -o sanitize \
|
|
71
|
+
tests/cpp/sanitize.cpp src/cpp/pulseq/*.cpp
|
|
72
|
+
|
|
73
|
+
- name: Read, write and expand every sequence in the corpus
|
|
74
|
+
run: ./sanitize tests/seq/*.seq
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Viewer release
|
|
2
|
+
|
|
3
|
+
# Publishes pypulseqpp-seqeyes, the GPL viewer package in viewer/, from a tag
|
|
4
|
+
# of its own: it is versioned after the SeqEyes release it builds, not after
|
|
5
|
+
# pypulseqpp.
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
tags:
|
|
10
|
+
- "viewer-v[0-9]+.[0-9]+.[0-9]+*"
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
uses: ./.github/workflows/viewer-wheels.yml
|
|
15
|
+
|
|
16
|
+
publish-to-pypi:
|
|
17
|
+
needs: [build]
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
environment:
|
|
20
|
+
name: pypi-viewer
|
|
21
|
+
url: https://pypi.org/p/pypulseqpp-seqeyes
|
|
22
|
+
permissions:
|
|
23
|
+
id-token: write # trusted publishing (OIDC)
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/download-artifact@v8
|
|
26
|
+
with:
|
|
27
|
+
pattern: "{viewer-wheels-*,viewer-sdist}"
|
|
28
|
+
path: dist
|
|
29
|
+
merge-multiple: true
|
|
30
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
name: Viewer wheels
|
|
2
|
+
|
|
3
|
+
# SeqEyes, built from viewer/ as the pypulseqpp-seqeyes wheels that
|
|
4
|
+
# `pip install 'pypulseqpp[plot]'` installs. Reusable: the viewer release
|
|
5
|
+
# publishes what this builds, and any change under viewer/ runs it.
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
workflow_call:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
pull_request:
|
|
11
|
+
paths: ["viewer/**", ".gitmodules", ".github/workflows/viewer-*.yml"]
|
|
12
|
+
push:
|
|
13
|
+
branches: [main]
|
|
14
|
+
paths: ["viewer/**", ".gitmodules", ".github/workflows/viewer-*.yml"]
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
wheels:
|
|
18
|
+
name: ${{ matrix.os }}
|
|
19
|
+
runs-on: ${{ matrix.os }}
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
# The platforms pypulseqpp ships for. Each build job also installs the
|
|
24
|
+
# wheel beside PySide6 and draws a sequence with it: see
|
|
25
|
+
# viewer/tests/smoke.py and [tool.cibuildwheel] in viewer/pyproject.toml.
|
|
26
|
+
os: [ubuntu-latest, macos-14, windows-latest]
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v7
|
|
29
|
+
with:
|
|
30
|
+
submodules: recursive # SeqEyes is the submodule in viewer/seqeyes
|
|
31
|
+
|
|
32
|
+
- uses: pypa/cibuildwheel@v4.2.0
|
|
33
|
+
with:
|
|
34
|
+
package-dir: viewer
|
|
35
|
+
|
|
36
|
+
- uses: actions/upload-artifact@v7
|
|
37
|
+
with:
|
|
38
|
+
name: viewer-wheels-${{ matrix.os }}
|
|
39
|
+
path: wheelhouse/*.whl
|
|
40
|
+
if-no-files-found: error
|
|
41
|
+
|
|
42
|
+
plot:
|
|
43
|
+
# pypulseqpp's own plot tests, against the wheel just built: the test that
|
|
44
|
+
# opens SeqEyes skips when there is none, so here it is made to run.
|
|
45
|
+
name: plot / ${{ matrix.os }}
|
|
46
|
+
needs: wheels
|
|
47
|
+
runs-on: ${{ matrix.os }}
|
|
48
|
+
strategy:
|
|
49
|
+
fail-fast: false
|
|
50
|
+
matrix:
|
|
51
|
+
os: [ubuntu-latest, macos-14, windows-latest]
|
|
52
|
+
env:
|
|
53
|
+
QT_QPA_PLATFORM: offscreen
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v7
|
|
56
|
+
with:
|
|
57
|
+
submodules: recursive
|
|
58
|
+
fetch-depth: 0 # setuptools_scm reads the tags
|
|
59
|
+
|
|
60
|
+
- uses: actions/setup-python@v7
|
|
61
|
+
with:
|
|
62
|
+
python-version: "3.12"
|
|
63
|
+
|
|
64
|
+
- uses: actions/download-artifact@v8
|
|
65
|
+
with:
|
|
66
|
+
name: viewer-wheels-${{ matrix.os }}
|
|
67
|
+
path: viewer-wheel
|
|
68
|
+
|
|
69
|
+
# PySide6's Qt draws with the system's display libraries, which every
|
|
70
|
+
# desktop has and the runner image does not all of. These are what
|
|
71
|
+
# drawing offscreen needs; viewer/README.md lists them too.
|
|
72
|
+
- name: System libraries
|
|
73
|
+
if: runner.os == 'Linux'
|
|
74
|
+
run: |
|
|
75
|
+
sudo apt-get update
|
|
76
|
+
sudo apt-get install -y libegl1 libgl1 libx11-6 libdbus-1-3 \
|
|
77
|
+
libfontconfig1 libfreetype6 libglib2.0-0 libxkbcommon0
|
|
78
|
+
|
|
79
|
+
- name: Install
|
|
80
|
+
shell: bash
|
|
81
|
+
run: |
|
|
82
|
+
python -m pip install --upgrade pip
|
|
83
|
+
python -m pip install ".[dev]" -r tests/requirements.txt viewer-wheel/*.whl
|
|
84
|
+
|
|
85
|
+
- name: Test
|
|
86
|
+
run: python -m pytest tests/test_plot.py -ra
|
|
87
|
+
|
|
88
|
+
sdist:
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
steps:
|
|
91
|
+
- uses: actions/checkout@v7
|
|
92
|
+
with:
|
|
93
|
+
submodules: recursive
|
|
94
|
+
- uses: actions/setup-python@v7
|
|
95
|
+
with:
|
|
96
|
+
python-version: "3.12"
|
|
97
|
+
- run: |
|
|
98
|
+
python -m pip install --upgrade pip build
|
|
99
|
+
python -m build --sdist viewer --outdir dist
|
|
100
|
+
- uses: actions/upload-artifact@v7
|
|
101
|
+
with:
|
|
102
|
+
name: viewer-sdist
|
|
103
|
+
path: dist/*.tar.gz
|
|
104
|
+
if-no-files-found: error
|