blochsim 0.0.9__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.
- blochsim-0.0.9/.gitattributes +42 -0
- blochsim-0.0.9/.github/DISCUSSION_TEMPLATE/ideas.yml +19 -0
- blochsim-0.0.9/.github/DISCUSSION_TEMPLATE/q-a.yml +24 -0
- blochsim-0.0.9/.github/ISSUE_TEMPLATE/bug_report.yml +69 -0
- blochsim-0.0.9/.github/ISSUE_TEMPLATE/config.yml +8 -0
- blochsim-0.0.9/.github/ISSUE_TEMPLATE/feature_request.yml +41 -0
- blochsim-0.0.9/.github/PULL_REQUEST_TEMPLATE.md +28 -0
- blochsim-0.0.9/.github/SECURITY.md +39 -0
- blochsim-0.0.9/.github/copilot-instructions.md +1 -0
- blochsim-0.0.9/.github/dependabot.yml +27 -0
- blochsim-0.0.9/.github/skills/add-a-sequence/SKILL.md +79 -0
- blochsim-0.0.9/.github/skills/build-and-test/SKILL.md +95 -0
- blochsim-0.0.9/.github/skills/build-the-docs/SKILL.md +125 -0
- blochsim-0.0.9/.github/skills/cut-a-release/SKILL.md +53 -0
- blochsim-0.0.9/.github/workflows/codeql.yml +54 -0
- blochsim-0.0.9/.github/workflows/docs.yml +148 -0
- blochsim-0.0.9/.github/workflows/lint.yml +31 -0
- blochsim-0.0.9/.github/workflows/test.yml +89 -0
- blochsim-0.0.9/.github/workflows/wheels.yml +109 -0
- blochsim-0.0.9/.gitignore +63 -0
- blochsim-0.0.9/.pre-commit-config.yaml +40 -0
- blochsim-0.0.9/AGENTS.md +1 -0
- blochsim-0.0.9/CHANGELOG.md +1294 -0
- blochsim-0.0.9/CLAUDE.md +219 -0
- blochsim-0.0.9/CMakeLists.txt +58 -0
- blochsim-0.0.9/LICENSE.txt +21 -0
- blochsim-0.0.9/PKG-INFO +168 -0
- blochsim-0.0.9/README.md +106 -0
- blochsim-0.0.9/benchmarks/README.md +281 -0
- blochsim-0.0.9/benchmarks/_common.py +181 -0
- blochsim-0.0.9/benchmarks/anatomy.py +318 -0
- blochsim-0.0.9/benchmarks/bench_blochsim.py +116 -0
- blochsim-0.0.9/benchmarks/bench_epgpy.py +95 -0
- blochsim-0.0.9/benchmarks/bench_sycomore.py +115 -0
- blochsim-0.0.9/benchmarks/figures/convergence.png +0 -0
- blochsim-0.0.9/benchmarks/figures/derivatives.png +0 -0
- blochsim-0.0.9/benchmarks/figures/memory.png +0 -0
- blochsim-0.0.9/benchmarks/figures/throughput.png +0 -0
- blochsim-0.0.9/benchmarks/julia/Manifest.toml +1206 -0
- blochsim-0.0.9/benchmarks/julia/Project.toml +28 -0
- blochsim-0.0.9/benchmarks/julia/bench_blochsimulators.jl +173 -0
- blochsim-0.0.9/benchmarks/julia/bench_koma.jl +169 -0
- blochsim-0.0.9/benchmarks/julia/common.jl +139 -0
- blochsim-0.0.9/benchmarks/make_figures.py +392 -0
- blochsim-0.0.9/benchmarks/results/anatomy.txt +89 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-1-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-1-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-10-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-10-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-100-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-100-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-1000-cpu-t1.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-1000-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-1000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-10000-cpu-t1.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-10000-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-10000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-100000-cpu-t1.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-100000-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-forward-100000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-1-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-1-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-10-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-10-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-100-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-100-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-1000-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-1000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-10000-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-10000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-100000-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian-100000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-1-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-1-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-10-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-10-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-100-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-100-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-1000-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-1000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-10000-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-10000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-100000-cpu-t4.json +36 -0
- blochsim-0.0.9/benchmarks/results/blochsim-jacobian1-100000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-complex-1000-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-complex-1000-cuda.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-complex-10000-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-complex-10000-cuda.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-complex-100000-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-complex-100000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-1-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-1-cuda.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-10-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-10-cuda.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-100-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-100-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-1000-cpu-t1.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-1000-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-1000-cuda.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-10000-cpu-t1.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-10000-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-10000-cuda.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-100000-cpu-t1.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-100000-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-forward-100000-cuda.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-jacobian-1000-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-jacobian-1000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-jacobian-10000-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-jacobian-10000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-jacobian-100000-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/blochsimulators-jacobian-100000-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/epgpy-forward-1.json +36 -0
- blochsim-0.0.9/benchmarks/results/epgpy-forward-10.json +36 -0
- blochsim-0.0.9/benchmarks/results/epgpy-forward-100.json +36 -0
- blochsim-0.0.9/benchmarks/results/epgpy-forward-1000.json +36 -0
- blochsim-0.0.9/benchmarks/results/epgpy-forward-10000.json +36 -0
- blochsim-0.0.9/benchmarks/results/epgpy-jacobian-1.json +36 -0
- blochsim-0.0.9/benchmarks/results/epgpy-jacobian-10.json +36 -0
- blochsim-0.0.9/benchmarks/results/epgpy-jacobian-100.json +36 -0
- blochsim-0.0.9/benchmarks/results/epgpy-jacobian-1000.json +36 -0
- blochsim-0.0.9/benchmarks/results/epgpy-jacobian-10000.json +36 -0
- blochsim-0.0.9/benchmarks/results/koma-forward-1-s64-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/koma-forward-1-s64-cuda.json +23 -0
- blochsim-0.0.9/benchmarks/results/koma-forward-10-s64-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/koma-forward-10-s64-cuda.json +23 -0
- blochsim-0.0.9/benchmarks/results/koma-forward-100-s64-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/koma-forward-100-s64-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/koma-forward-1000-s64-cpu-t4.json +23 -0
- blochsim-0.0.9/benchmarks/results/koma-forward-1000-s64-cuda.json +48 -0
- blochsim-0.0.9/benchmarks/results/sycomore-forward-1.json +35 -0
- blochsim-0.0.9/benchmarks/results/sycomore-forward-10.json +35 -0
- blochsim-0.0.9/benchmarks/results/sycomore-forward-100.json +35 -0
- blochsim-0.0.9/benchmarks/results/sycomore-forward-1000.json +35 -0
- blochsim-0.0.9/benchmarks/results/sycomore-forward-10000.json +35 -0
- blochsim-0.0.9/benchmarks/results/table.md +142 -0
- blochsim-0.0.9/benchmarks/results/validation.json +208 -0
- blochsim-0.0.9/benchmarks/results/validation.txt +193 -0
- blochsim-0.0.9/benchmarks/run_all.py +319 -0
- blochsim-0.0.9/benchmarks/setup.sh +154 -0
- blochsim-0.0.9/benchmarks/summarize.py +58 -0
- blochsim-0.0.9/benchmarks/validate.py +277 -0
- blochsim-0.0.9/docs/Makefile +20 -0
- blochsim-0.0.9/docs/_static/blochsim-logo-dark.svg +19 -0
- blochsim-0.0.9/docs/_static/blochsim-logo.svg +19 -0
- blochsim-0.0.9/docs/_static/blochsim-mark-dark.svg +18 -0
- blochsim-0.0.9/docs/_static/blochsim-mark.svg +18 -0
- blochsim-0.0.9/docs/_static/custom.css +33 -0
- blochsim-0.0.9/docs/_templates/autosummary/base.rst +5 -0
- blochsim-0.0.9/docs/_templates/autosummary/class.rst +21 -0
- blochsim-0.0.9/docs/_templates/autosummary/function.rst +10 -0
- blochsim-0.0.9/docs/_templates/autosummary/module.rst +64 -0
- blochsim-0.0.9/docs/api/estimators.md +121 -0
- blochsim-0.0.9/docs/api/execution.md +63 -0
- blochsim-0.0.9/docs/api/index.md +49 -0
- blochsim-0.0.9/docs/api/model.md +143 -0
- blochsim-0.0.9/docs/api/optim.md +26 -0
- blochsim-0.0.9/docs/api/recon.md +79 -0
- blochsim-0.0.9/docs/api/sequence.md +94 -0
- blochsim-0.0.9/docs/api/simulators.md +92 -0
- blochsim-0.0.9/docs/binder/apt.txt +3 -0
- blochsim-0.0.9/docs/binder/environment.yml +10 -0
- blochsim-0.0.9/docs/conf.py +437 -0
- blochsim-0.0.9/docs/developer_guide.md +335 -0
- blochsim-0.0.9/docs/explanation_figures.py +1406 -0
- blochsim-0.0.9/docs/explanations/description.md +202 -0
- blochsim-0.0.9/docs/explanations/epg.md +364 -0
- blochsim-0.0.9/docs/explanations/implementation.md +326 -0
- blochsim-0.0.9/docs/explanations/index.md +28 -0
- blochsim-0.0.9/docs/figure_style.py +57 -0
- blochsim-0.0.9/docs/index.md +16 -0
- blochsim-0.0.9/docs/misc/code_of_conduct.md +128 -0
- blochsim-0.0.9/docs/misc/contributors.md +9 -0
- blochsim-0.0.9/docs/misc/index.md +13 -0
- blochsim-0.0.9/docs/misc/license.md +4 -0
- blochsim-0.0.9/docs/misc/related.md +125 -0
- blochsim-0.0.9/docs/sphinx_add_colab_link.py +171 -0
- blochsim-0.0.9/docs/user_guide.md +269 -0
- blochsim-0.0.9/examples/01-framework/01-getting-started.py +594 -0
- blochsim-0.0.9/examples/01-framework/02-expanded-physics.py +614 -0
- blochsim-0.0.9/examples/01-framework/03-writing-a-simulator.py +424 -0
- blochsim-0.0.9/examples/01-framework/04-custom-operator.py +384 -0
- blochsim-0.0.9/examples/01-framework/README.rst +16 -0
- blochsim-0.0.9/examples/01-framework/data/slr90.npz +0 -0
- blochsim-0.0.9/examples/01-framework/fse.seq +1252 -0
- blochsim-0.0.9/examples/02-parameter-inference/01-dictionary-matching.py +605 -0
- blochsim-0.0.9/examples/02-parameter-inference/02-lookup-table.py +568 -0
- blochsim-0.0.9/examples/02-parameter-inference/03-nonlinear-least-squares.py +547 -0
- blochsim-0.0.9/examples/02-parameter-inference/04-perk.py +637 -0
- blochsim-0.0.9/examples/02-parameter-inference/README.rst +15 -0
- blochsim-0.0.9/examples/03-sequence-optimization/01-echo-train-design.py +830 -0
- blochsim-0.0.9/examples/03-sequence-optimization/02-joint-relaxometry.py +613 -0
- blochsim-0.0.9/examples/03-sequence-optimization/03-rf-pulse-design.py +170 -0
- blochsim-0.0.9/examples/03-sequence-optimization/README.rst +19 -0
- blochsim-0.0.9/examples/04-model-based-imaging/01-linear-subspace.py +508 -0
- blochsim-0.0.9/examples/04-model-based-imaging/02-nonlinear-inversion.py +545 -0
- blochsim-0.0.9/examples/04-model-based-imaging/README.rst +17 -0
- blochsim-0.0.9/examples/05-misc/01-synthetic-data.py +597 -0
- blochsim-0.0.9/examples/05-misc/README.rst +4 -0
- blochsim-0.0.9/examples/05-misc/data/PD/IXI002-Guys-0828-PD.nii.gz +0 -0
- blochsim-0.0.9/examples/05-misc/data/T1/IXI002-Guys-0828-T1.nii.gz +0 -0
- blochsim-0.0.9/examples/05-misc/data/T2/IXI002-Guys-0828-T2.nii.gz +0 -0
- blochsim-0.0.9/examples/README.rst +2 -0
- blochsim-0.0.9/examples/_gallery_header.md +49 -0
- blochsim-0.0.9/pyproject.toml +239 -0
- blochsim-0.0.9/scripts/build_docs.sh +63 -0
- blochsim-0.0.9/scripts/check_wheel.py +57 -0
- blochsim-0.0.9/scripts/make_artwork.py +161 -0
- blochsim-0.0.9/scripts/prune_triton_cache.py +142 -0
- blochsim-0.0.9/scripts/publish_docs.py +143 -0
- blochsim-0.0.9/setup.py +10 -0
- blochsim-0.0.9/src/blochsim/__init__.py +30 -0
- blochsim-0.0.9/src/blochsim/_bounds.py +207 -0
- blochsim-0.0.9/src/blochsim/_epg_cpu.cpp +11790 -0
- blochsim-0.0.9/src/blochsim/_execution.py +519 -0
- blochsim-0.0.9/src/blochsim/_functional/__init__.py +37 -0
- blochsim-0.0.9/src/blochsim/_functional/_bssfp.py +87 -0
- blochsim-0.0.9/src/blochsim/_functional/_fse.py +99 -0
- blochsim-0.0.9/src/blochsim/_functional/_mp2rage.py +86 -0
- blochsim-0.0.9/src/blochsim/_functional/_mpnrage.py +87 -0
- blochsim-0.0.9/src/blochsim/_functional/_mprage.py +86 -0
- blochsim-0.0.9/src/blochsim/_functional/_mrf.py +96 -0
- blochsim-0.0.9/src/blochsim/_functional/_run.py +49 -0
- blochsim-0.0.9/src/blochsim/_functional/_spgr.py +82 -0
- blochsim-0.0.9/src/blochsim/_ifunc.hpp +39 -0
- blochsim-0.0.9/src/blochsim/_perk_cpu.cpp +401 -0
- blochsim-0.0.9/src/blochsim/_subspace.py +129 -0
- blochsim-0.0.9/src/blochsim/_threads.hpp +169 -0
- blochsim-0.0.9/src/blochsim/_version.py +24 -0
- blochsim-0.0.9/src/blochsim/estimators/__init__.py +37 -0
- blochsim-0.0.9/src/blochsim/estimators/_dictionary.py +460 -0
- blochsim-0.0.9/src/blochsim/estimators/_grouped.py +251 -0
- blochsim-0.0.9/src/blochsim/estimators/_lookup.py +291 -0
- blochsim-0.0.9/src/blochsim/estimators/_mapping.py +648 -0
- blochsim-0.0.9/src/blochsim/estimators/_nlls.py +327 -0
- blochsim-0.0.9/src/blochsim/estimators/_perk.py +915 -0
- blochsim-0.0.9/src/blochsim/estimators/_perk_native.py +87 -0
- blochsim-0.0.9/src/blochsim/estimators/_perk_triton.py +332 -0
- blochsim-0.0.9/src/blochsim/model/__init__.py +30 -0
- blochsim-0.0.9/src/blochsim/model/_binding.py +386 -0
- blochsim-0.0.9/src/blochsim/model/_signal.py +320 -0
- blochsim-0.0.9/src/blochsim/model/_state_machine.py +920 -0
- blochsim-0.0.9/src/blochsim/optim/__init__.py +16 -0
- blochsim-0.0.9/src/blochsim/optim/_design.py +287 -0
- blochsim-0.0.9/src/blochsim/recon/__init__.py +34 -0
- blochsim-0.0.9/src/blochsim/recon/_gauss_newton.py +793 -0
- blochsim-0.0.9/src/blochsim/recon/_operator.py +542 -0
- blochsim-0.0.9/src/blochsim/sequence/__init__.py +86 -0
- blochsim-0.0.9/src/blochsim/sequence/_accelerators.py +4136 -0
- blochsim-0.0.9/src/blochsim/sequence/_array.py +202 -0
- blochsim-0.0.9/src/blochsim/sequence/_builders.py +278 -0
- blochsim-0.0.9/src/blochsim/sequence/_calibration.py +48 -0
- blochsim-0.0.9/src/blochsim/sequence/_description.py +981 -0
- blochsim-0.0.9/src/blochsim/sequence/_epg_triton.py +18718 -0
- blochsim-0.0.9/src/blochsim/sequence/_fixed_point.py +180 -0
- blochsim-0.0.9/src/blochsim/sequence/_lineshape.py +283 -0
- blochsim-0.0.9/src/blochsim/sequence/_mrd.py +173 -0
- blochsim-0.0.9/src/blochsim/sequence/_operators.py +629 -0
- blochsim-0.0.9/src/blochsim/sequence/_parameters.py +559 -0
- blochsim-0.0.9/src/blochsim/sequence/_pools.py +293 -0
- blochsim-0.0.9/src/blochsim/sequence/_pools_triton.py +2226 -0
- blochsim-0.0.9/src/blochsim/sequence/_pulseq.py +430 -0
- blochsim-0.0.9/src/blochsim/sequence/_settling.py +85 -0
- blochsim-0.0.9/src/blochsim/sequence/_simulation.py +819 -0
- blochsim-0.0.9/src/blochsim/sequence/_transition.py +822 -0
- blochsim-0.0.9/src/blochsim/sequence/_transmit.py +203 -0
- blochsim-0.0.9/src/blochsim/simulators/__init__.py +61 -0
- blochsim-0.0.9/src/blochsim/simulators/_contrast.py +39 -0
- blochsim-0.0.9/src/blochsim/simulators/_pulses.py +158 -0
- blochsim-0.0.9/src/blochsim/simulators/asl.py +143 -0
- blochsim-0.0.9/src/blochsim/simulators/bssfp.py +113 -0
- blochsim-0.0.9/src/blochsim/simulators/cest.py +239 -0
- blochsim-0.0.9/src/blochsim/simulators/diffusion.py +103 -0
- blochsim-0.0.9/src/blochsim/simulators/flash.py +187 -0
- blochsim-0.0.9/src/blochsim/simulators/fmssfp.py +141 -0
- blochsim-0.0.9/src/blochsim/simulators/fse.py +213 -0
- blochsim-0.0.9/src/blochsim/simulators/gradient_echo.py +277 -0
- blochsim-0.0.9/src/blochsim/simulators/hsfp.py +106 -0
- blochsim-0.0.9/src/blochsim/simulators/looklocker.py +302 -0
- blochsim-0.0.9/src/blochsim/simulators/mp2rage.py +274 -0
- blochsim-0.0.9/src/blochsim/simulators/mpnrage.py +90 -0
- blochsim-0.0.9/src/blochsim/simulators/mprage.py +130 -0
- blochsim-0.0.9/src/blochsim/simulators/mrf.py +84 -0
- blochsim-0.0.9/src/blochsim/simulators/relaxometry.py +194 -0
- blochsim-0.0.9/src/blochsim/simulators/spgr.py +104 -0
- blochsim-0.0.9/src/blochsim/simulators/spin_echo.py +96 -0
- blochsim-0.0.9/src/blochsim/simulators/stimulated_echo.py +102 -0
- blochsim-0.0.9/src/blochsim/simulators/truefisp.py +169 -0
- blochsim-0.0.9/src/blochsim/utils/__init__.py +8 -0
- blochsim-0.0.9/src/blochsim/utils/_b1rms.py +45 -0
- blochsim-0.0.9/tests/conftest.py +17 -0
- blochsim-0.0.9/tests/epg/test_adc.py +109 -0
- blochsim-0.0.9/tests/epg/test_diffusion.py +89 -0
- blochsim-0.0.9/tests/epg/test_flow.py +137 -0
- blochsim-0.0.9/tests/epg/test_relaxation.py +237 -0
- blochsim-0.0.9/tests/epg/test_rf.py +382 -0
- blochsim-0.0.9/tests/epg/test_shift.py +144 -0
- blochsim-0.0.9/tests/epg/test_spoil.py +79 -0
- blochsim-0.0.9/tests/epg/test_states.py +61 -0
- blochsim-0.0.9/tests/epg/test_three_pool.py +538 -0
- blochsim-0.0.9/tests/epg/test_two_pool.py +379 -0
- blochsim-0.0.9/tests/epg/test_two_pool_transverse.py +437 -0
- blochsim-0.0.9/tests/estimators/test_dictionary.py +99 -0
- blochsim-0.0.9/tests/estimators/test_grouped.py +325 -0
- blochsim-0.0.9/tests/estimators/test_lookup.py +228 -0
- blochsim-0.0.9/tests/estimators/test_mapping.py +209 -0
- blochsim-0.0.9/tests/estimators/test_mapping_comparison.py +47 -0
- blochsim-0.0.9/tests/estimators/test_nlls.py +353 -0
- blochsim-0.0.9/tests/estimators/test_perk.py +294 -0
- blochsim-0.0.9/tests/estimators/test_perk_kernel.py +207 -0
- blochsim-0.0.9/tests/estimators/test_streaming.py +253 -0
- blochsim-0.0.9/tests/estimators/test_subspace.py +98 -0
- blochsim-0.0.9/tests/estimators/test_uncertainty.py +380 -0
- blochsim-0.0.9/tests/functionals/test_bssfp_func.py +57 -0
- blochsim-0.0.9/tests/functionals/test_fse_func.py +61 -0
- blochsim-0.0.9/tests/functionals/test_mp2rage_func.py +54 -0
- blochsim-0.0.9/tests/functionals/test_mp2rage_reference.py +303 -0
- blochsim-0.0.9/tests/functionals/test_mpnrage_func.py +27 -0
- blochsim-0.0.9/tests/functionals/test_mprage_func.py +41 -0
- blochsim-0.0.9/tests/functionals/test_mrf_func.py +62 -0
- blochsim-0.0.9/tests/functionals/test_spgr_func.py +59 -0
- blochsim-0.0.9/tests/model/test_array_backends.py +186 -0
- blochsim-0.0.9/tests/model/test_jacobian_contract.py +104 -0
- blochsim-0.0.9/tests/model/test_model_physics.py +144 -0
- blochsim-0.0.9/tests/model/test_signal_model.py +245 -0
- blochsim-0.0.9/tests/model/test_state_machine.py +300 -0
- blochsim-0.0.9/tests/optim/test_binding.py +469 -0
- blochsim-0.0.9/tests/optim/test_design.py +254 -0
- blochsim-0.0.9/tests/recon/test_constraints.py +232 -0
- blochsim-0.0.9/tests/recon/test_deepinv.py +136 -0
- blochsim-0.0.9/tests/recon/test_gauss_newton.py +429 -0
- blochsim-0.0.9/tests/recon/test_operator.py +308 -0
- blochsim-0.0.9/tests/recon/test_subspace_route.py +141 -0
- blochsim-0.0.9/tests/sequence/test_against_epgpy.py +137 -0
- blochsim-0.0.9/tests/sequence/test_both_pools.py +1696 -0
- blochsim-0.0.9/tests/sequence/test_bound_pool.py +1721 -0
- blochsim-0.0.9/tests/sequence/test_calibration.py +44 -0
- blochsim-0.0.9/tests/sequence/test_cuda_parity.py +628 -0
- blochsim-0.0.9/tests/sequence/test_description.py +204 -0
- blochsim-0.0.9/tests/sequence/test_description_helper.py +109 -0
- blochsim-0.0.9/tests/sequence/test_diffusion_kernels.py +376 -0
- blochsim-0.0.9/tests/sequence/test_distribute.py +240 -0
- blochsim-0.0.9/tests/sequence/test_dynamic_transmit.py +2064 -0
- blochsim-0.0.9/tests/sequence/test_engine_coverage.py +176 -0
- blochsim-0.0.9/tests/sequence/test_exact_profile.py +396 -0
- blochsim-0.0.9/tests/sequence/test_exchange.py +1418 -0
- blochsim-0.0.9/tests/sequence/test_execution.py +301 -0
- blochsim-0.0.9/tests/sequence/test_feature_gates.py +503 -0
- blochsim-0.0.9/tests/sequence/test_features.py +163 -0
- blochsim-0.0.9/tests/sequence/test_first_order_adjoint.py +212 -0
- blochsim-0.0.9/tests/sequence/test_fixed_point.py +155 -0
- blochsim-0.0.9/tests/sequence/test_flow_kernels.py +378 -0
- blochsim-0.0.9/tests/sequence/test_gradient_operators.py +150 -0
- blochsim-0.0.9/tests/sequence/test_host_feature_mask.py +269 -0
- blochsim-0.0.9/tests/sequence/test_interpreted.py +101 -0
- blochsim-0.0.9/tests/sequence/test_lineshape.py +222 -0
- blochsim-0.0.9/tests/sequence/test_many_pools.py +760 -0
- blochsim-0.0.9/tests/sequence/test_many_pools_interpreted.py +79 -0
- blochsim-0.0.9/tests/sequence/test_mrd_reader.py +203 -0
- blochsim-0.0.9/tests/sequence/test_offload.py +823 -0
- blochsim-0.0.9/tests/sequence/test_operators.py +283 -0
- blochsim-0.0.9/tests/sequence/test_parameters.py +211 -0
- blochsim-0.0.9/tests/sequence/test_pulseq_reader.py +234 -0
- blochsim-0.0.9/tests/sequence/test_real_subspace.py +1212 -0
- blochsim-0.0.9/tests/sequence/test_rf_definition.py +188 -0
- blochsim-0.0.9/tests/sequence/test_settling.py +171 -0
- blochsim-0.0.9/tests/sequence/test_simulation.py +275 -0
- blochsim-0.0.9/tests/sequence/test_slice_table.py +619 -0
- blochsim-0.0.9/tests/sequence/test_ssfp_readouts.py +152 -0
- blochsim-0.0.9/tests/sequence/test_static_spread.py +354 -0
- blochsim-0.0.9/tests/sequence/test_steady_state.py +146 -0
- blochsim-0.0.9/tests/sequence/test_subspace_streams.py +149 -0
- blochsim-0.0.9/tests/sequence/test_train_batching.py +405 -0
- blochsim-0.0.9/tests/sequence/test_transition.py +477 -0
- blochsim-0.0.9/tests/sequence/test_transmit_array.py +987 -0
- blochsim-0.0.9/tests/sequence/test_unrefocused_time.py +262 -0
- blochsim-0.0.9/tests/sequence/test_vjp.py +492 -0
- blochsim-0.0.9/tests/sequence/test_washout_kernels.py +498 -0
- blochsim-0.0.9/tests/sequence/test_worker_pool.py +105 -0
- blochsim-0.0.9/tests/simulators/test_closed_forms.py +317 -0
- blochsim-0.0.9/tests/simulators/test_epg_trains.py +251 -0
- blochsim-0.0.9/tests/simulators/test_sampled_pulses.py +359 -0
- blochsim-0.0.9/tests/utils/__init__.py +1 -0
- blochsim-0.0.9/tests/utils/epg/__init__.py +37 -0
- blochsim-0.0.9/tests/utils/epg/_adc.py +81 -0
- blochsim-0.0.9/tests/utils/epg/_adiabatic_inversion.py +31 -0
- blochsim-0.0.9/tests/utils/epg/_diffusion.py +99 -0
- blochsim-0.0.9/tests/utils/epg/_flow.py +188 -0
- blochsim-0.0.9/tests/utils/epg/_longitudinal_relaxation.py +156 -0
- blochsim-0.0.9/tests/utils/epg/_rf_pulse.py +717 -0
- blochsim-0.0.9/tests/utils/epg/_shift.py +40 -0
- blochsim-0.0.9/tests/utils/epg/_spoil.py +25 -0
- blochsim-0.0.9/tests/utils/epg/_states_matrix.py +58 -0
- blochsim-0.0.9/tests/utils/epg/_transverse_relaxation.py +142 -0
- blochsim-0.0.9/tests/utils/epg/_utils.py +24 -0
- blochsim-0.0.9/tests/utils/exchange.py +47 -0
- blochsim-0.0.9/tests/utils/interpreted.py +979 -0
- blochsim-0.0.9/tests/utils/interpreted_pools.py +221 -0
- blochsim-0.0.9/tests/utils/packed_reference.py +812 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Normalise line endings in the repository; check out native on Windows.
|
|
2
|
+
* text=auto
|
|
3
|
+
|
|
4
|
+
# Text, whatever the platform.
|
|
5
|
+
*.py text diff=python
|
|
6
|
+
*.pyi text diff=python
|
|
7
|
+
*.cpp text diff=cpp
|
|
8
|
+
*.hpp text diff=cpp
|
|
9
|
+
*.md text
|
|
10
|
+
*.rst text
|
|
11
|
+
*.txt text
|
|
12
|
+
*.toml text
|
|
13
|
+
*.cfg text
|
|
14
|
+
*.yml text
|
|
15
|
+
*.yaml text
|
|
16
|
+
*.json text
|
|
17
|
+
*.ipynb text
|
|
18
|
+
CMakeLists.txt text
|
|
19
|
+
*.cmake text
|
|
20
|
+
|
|
21
|
+
# Shell scripts must keep LF even when checked out on Windows, so a WSL or
|
|
22
|
+
# Git Bash run of scripts/ does not fail on carriage returns.
|
|
23
|
+
*.sh text eol=lf
|
|
24
|
+
|
|
25
|
+
# Binary, never diffed or line-ending converted.
|
|
26
|
+
*.png binary
|
|
27
|
+
*.jpg binary
|
|
28
|
+
*.jpeg binary
|
|
29
|
+
*.gif binary
|
|
30
|
+
*.svg binary
|
|
31
|
+
*.pdf binary
|
|
32
|
+
*.npy binary
|
|
33
|
+
*.npz binary
|
|
34
|
+
*.so binary
|
|
35
|
+
*.pyd binary
|
|
36
|
+
*.dylib binary
|
|
37
|
+
*.dll binary
|
|
38
|
+
|
|
39
|
+
# What the repository's language bar reports: the package, not the pages that
|
|
40
|
+
# describe it. Affects GitHub's statistics only, nothing that is built.
|
|
41
|
+
docs/** linguist-documentation
|
|
42
|
+
examples/** linguist-documentation
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
labels: ["idea"]
|
|
2
|
+
body:
|
|
3
|
+
- type: textarea
|
|
4
|
+
id: idea
|
|
5
|
+
attributes:
|
|
6
|
+
label: The idea
|
|
7
|
+
description: |
|
|
8
|
+
A model, an interface or a direction you think BlochSim should take,
|
|
9
|
+
before it is concrete enough to be a feature request.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: context
|
|
15
|
+
attributes:
|
|
16
|
+
label: Where it comes from
|
|
17
|
+
description: |
|
|
18
|
+
The experiment that prompted it, and any paper or implementation that
|
|
19
|
+
already does something like it.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
labels: ["question"]
|
|
2
|
+
body:
|
|
3
|
+
- type: textarea
|
|
4
|
+
id: question
|
|
5
|
+
attributes:
|
|
6
|
+
label: What you are trying to do
|
|
7
|
+
description: |
|
|
8
|
+
The sequence or the analysis, and where you got stuck. If a signal
|
|
9
|
+
looks wrong, say what you expected it to look like and why.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: code
|
|
15
|
+
attributes:
|
|
16
|
+
label: What you have so far
|
|
17
|
+
description: The call you are making, if there is one.
|
|
18
|
+
render: python
|
|
19
|
+
|
|
20
|
+
- type: input
|
|
21
|
+
id: version
|
|
22
|
+
attributes:
|
|
23
|
+
label: BlochSim version
|
|
24
|
+
placeholder: "0.4.1, or the commit you are on"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: A simulation that raises, hangs, or returns a signal you can show is wrong.
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Questions about how to use BlochSim, and results you are unsure about,
|
|
9
|
+
belong in [Discussions](https://github.com/pulserver/blochsim/discussions).
|
|
10
|
+
This form is for behaviour you can pin down.
|
|
11
|
+
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: what-happens
|
|
14
|
+
attributes:
|
|
15
|
+
label: What happens
|
|
16
|
+
description: What you ran, and what it did instead of what you expected.
|
|
17
|
+
placeholder: |
|
|
18
|
+
A 48-echo FSE train at 60 degree refocusing returns NaN from the
|
|
19
|
+
second echo on, on CPU, for T2 = 0.
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
|
|
23
|
+
- type: textarea
|
|
24
|
+
id: reproduce
|
|
25
|
+
attributes:
|
|
26
|
+
label: Code that reproduces it
|
|
27
|
+
description: |
|
|
28
|
+
The shortest script that shows the problem, with the tissue and the
|
|
29
|
+
protocol it was run on. Paste it whole rather than describing it -- a
|
|
30
|
+
sequence is enough numbers that a description leaves the run ambiguous.
|
|
31
|
+
render: python
|
|
32
|
+
validations:
|
|
33
|
+
required: true
|
|
34
|
+
|
|
35
|
+
- type: textarea
|
|
36
|
+
id: traceback
|
|
37
|
+
attributes:
|
|
38
|
+
label: Traceback or output
|
|
39
|
+
description: The full traceback, or the numbers that are wrong beside the ones you expected.
|
|
40
|
+
render: shell
|
|
41
|
+
|
|
42
|
+
- type: textarea
|
|
43
|
+
id: environment
|
|
44
|
+
attributes:
|
|
45
|
+
label: Environment
|
|
46
|
+
description: |
|
|
47
|
+
Paste the output of
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
python -c "from importlib.metadata import version; print('blochsim', version('blochsim'))"
|
|
51
|
+
python -c "import torch; print(torch.__version__, torch.version.cuda, torch.cuda.get_device_name() if torch.cuda.is_available() else 'cpu')"
|
|
52
|
+
python -VV
|
|
53
|
+
```
|
|
54
|
+
render: shell
|
|
55
|
+
validations:
|
|
56
|
+
required: true
|
|
57
|
+
|
|
58
|
+
- type: dropdown
|
|
59
|
+
id: where
|
|
60
|
+
attributes:
|
|
61
|
+
label: Where it runs
|
|
62
|
+
description: Which backends you have seen it on.
|
|
63
|
+
multiple: true
|
|
64
|
+
options:
|
|
65
|
+
- CPU
|
|
66
|
+
- CUDA (Triton kernels)
|
|
67
|
+
- Both
|
|
68
|
+
validations:
|
|
69
|
+
required: true
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Question, or a result you are unsure about
|
|
4
|
+
url: https://github.com/pulserver/blochsim/discussions
|
|
5
|
+
about: Ask how to model a sequence, or whether a signal you got is expected.
|
|
6
|
+
- name: Security report
|
|
7
|
+
url: https://github.com/pulserver/blochsim/security/policy
|
|
8
|
+
about: Report a vulnerability privately rather than in a public issue.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: A sequence, a physical effect, an estimator or an interface BlochSim should carry.
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: What you are trying to simulate or fit
|
|
9
|
+
description: |
|
|
10
|
+
The acquisition or the analysis, in the vocabulary of the experiment
|
|
11
|
+
rather than of the API. What the sequence plays, which properties you
|
|
12
|
+
need out, and what stops you today.
|
|
13
|
+
validations:
|
|
14
|
+
required: true
|
|
15
|
+
|
|
16
|
+
- type: textarea
|
|
17
|
+
id: proposal
|
|
18
|
+
attributes:
|
|
19
|
+
label: What you would like BlochSim to do
|
|
20
|
+
description: |
|
|
21
|
+
If you already know the shape of it -- an operator, a tissue property,
|
|
22
|
+
a keyword on an existing simulator -- sketch the call you would like
|
|
23
|
+
to write.
|
|
24
|
+
render: python
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
|
|
28
|
+
- type: textarea
|
|
29
|
+
id: reference
|
|
30
|
+
attributes:
|
|
31
|
+
label: Reference
|
|
32
|
+
description: |
|
|
33
|
+
The paper the model comes from, if there is one, and the figure or
|
|
34
|
+
equation the implementation would have to reproduce.
|
|
35
|
+
|
|
36
|
+
- type: checkboxes
|
|
37
|
+
id: contribution
|
|
38
|
+
attributes:
|
|
39
|
+
label: Contribution
|
|
40
|
+
options:
|
|
41
|
+
- label: I would be willing to open a pull request for this.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
## What this changes
|
|
2
|
+
|
|
3
|
+
<!-- What the code does now that it did not do before, in one or two
|
|
4
|
+
sentences. Link the issue or discussion it comes from, if there is one. -->
|
|
5
|
+
|
|
6
|
+
## How it was checked
|
|
7
|
+
|
|
8
|
+
<!-- The command you ran and what it printed: a test that fails before the
|
|
9
|
+
change and passes after it, an analytic case the new physics reproduces,
|
|
10
|
+
a benchmark. "Tests pass" on its own does not say which ones. -->
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
pytest tests/
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Checklist
|
|
17
|
+
|
|
18
|
+
- [ ] `pytest tests/` passes locally, and a new test covers what changed.
|
|
19
|
+
- [ ] `pre-commit run --all-files` is clean -- the `ruff format` and
|
|
20
|
+
`ruff check` that CI's Lint job runs.
|
|
21
|
+
- [ ] Public functions and classes carry a numpydoc docstring: one line of
|
|
22
|
+
what, then Parameters, Returns, Raises.
|
|
23
|
+
- [ ] Comments and docstrings describe the code as it is now -- no
|
|
24
|
+
"previously", no "this replaces", no naming of a bug that is fixed.
|
|
25
|
+
- [ ] A change to what the kernels compute is in both of them, and arrives
|
|
26
|
+
with a test that pins it against something outside BlochSim.
|
|
27
|
+
- [ ] The documentation is updated where the change is visible to a caller,
|
|
28
|
+
and `bash scripts/build_docs.sh` still builds.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Security fixes are applied to the latest release on PyPI and to `main`.
|
|
6
|
+
Older releases are not patched.
|
|
7
|
+
|
|
8
|
+
## Reporting a vulnerability
|
|
9
|
+
|
|
10
|
+
Report privately, not as a public issue:
|
|
11
|
+
|
|
12
|
+
- open a draft advisory through
|
|
13
|
+
[Security -> Report a vulnerability](https://github.com/pulserver/blochsim/security/advisories/new),
|
|
14
|
+
which is the preferred route; or
|
|
15
|
+
- email **matteo.cencini@gmail.com** if you cannot use GitHub.
|
|
16
|
+
|
|
17
|
+
Please include what an attacker can do, the version and platform you saw it
|
|
18
|
+
on, and a minimal reproduction. You can expect an acknowledgement within a
|
|
19
|
+
week, an assessment within two, and credit in the advisory unless you ask
|
|
20
|
+
otherwise. Please give us a chance to release a fix before disclosing
|
|
21
|
+
publicly.
|
|
22
|
+
|
|
23
|
+
## Scope
|
|
24
|
+
|
|
25
|
+
BlochSim executes the code you give it: a sequence layout, a cost function and
|
|
26
|
+
a signal model are all Python that runs in your process, so a malicious
|
|
27
|
+
*script* is out of scope in the same way it is for NumPy or PyTorch.
|
|
28
|
+
|
|
29
|
+
In scope is anything that turns *data* into execution or into memory
|
|
30
|
+
corruption -- a sequence description, a pulse waveform, a phantom or a
|
|
31
|
+
dictionary read from a file, or values passed to the simulator, reaching the
|
|
32
|
+
C++ and Triton kernels. Those kernels index raw pointers, so an out-of-bounds
|
|
33
|
+
read or write reachable from ordinary arguments is a vulnerability and not
|
|
34
|
+
merely a bug.
|
|
35
|
+
|
|
36
|
+
## Not a vulnerability
|
|
37
|
+
|
|
38
|
+
A simulation that returns wrong physics, diverges, or raises is a
|
|
39
|
+
[bug report](https://github.com/pulserver/blochsim/issues/new/choose).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
../CLAUDE.md
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# The actions the workflows pin. A pinned action that is never updated is a
|
|
4
|
+
# pinned action that stops working.
|
|
5
|
+
- package-ecosystem: github-actions
|
|
6
|
+
directory: /
|
|
7
|
+
schedule:
|
|
8
|
+
interval: weekly
|
|
9
|
+
day: monday
|
|
10
|
+
commit-message:
|
|
11
|
+
prefix: "ci"
|
|
12
|
+
groups:
|
|
13
|
+
actions:
|
|
14
|
+
patterns: ["*"]
|
|
15
|
+
|
|
16
|
+
# The dependency floors in pyproject.toml, and the toolchain the extras pull.
|
|
17
|
+
- package-ecosystem: pip
|
|
18
|
+
directory: /
|
|
19
|
+
schedule:
|
|
20
|
+
interval: weekly
|
|
21
|
+
day: monday
|
|
22
|
+
commit-message:
|
|
23
|
+
prefix: "deps"
|
|
24
|
+
groups:
|
|
25
|
+
python:
|
|
26
|
+
patterns: ["*"]
|
|
27
|
+
update-types: [minor, patch]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-a-sequence
|
|
3
|
+
description: Write a new simulator, signal model, or sequence operator in BlochSim. Use when asked to add a sequence, a readout module, a physical effect, or a tissue property.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Add a sequence to BlochSim
|
|
7
|
+
|
|
8
|
+
**There is one base class, `Simulator`, written in one of two ways.** Nothing
|
|
9
|
+
downstream ever asks which way.
|
|
10
|
+
|
|
11
|
+
## A signal that has to be played
|
|
12
|
+
|
|
13
|
+
Implement `layout()`: a train of pulses whose magnetization state carries from
|
|
14
|
+
one event to the next, which is almost every quantitative sequence.
|
|
15
|
+
|
|
16
|
+
1. Set `model` to a `SpinPhysics` — what a voxel holds, so which tissue
|
|
17
|
+
properties are exposed and which terms the kernels carry, and what each kind
|
|
18
|
+
of event does to it.
|
|
19
|
+
2. Implement `layout()`, returning the operators of one repetition in the order
|
|
20
|
+
they are played.
|
|
21
|
+
|
|
22
|
+
The extended phase-graph engine, the derivative, the device placement and the
|
|
23
|
+
memory policy all follow, and none of them is yours to write. The two pieces
|
|
24
|
+
are separate so either can change without the other: giving an MRF timing a
|
|
25
|
+
selective excitation, or a refocused train a readout that spoils rather than
|
|
26
|
+
winds, is an assignment rather than a new model.
|
|
27
|
+
|
|
28
|
+
`EventOperators` names the operator each kind of event plays. Four are supplied
|
|
29
|
+
and a `SpinPhysics` picks one: `SPOILED` and `UNBALANCED` for gradient-spoiled
|
|
30
|
+
and gradient-echo trains, `BALANCED` for a fully refocused steady state,
|
|
31
|
+
`REFOCUSED` for a spin-echo train.
|
|
32
|
+
|
|
33
|
+
## A signal with a closed form
|
|
34
|
+
|
|
35
|
+
Implement `evaluate()` instead — a mono-exponential decay, an
|
|
36
|
+
inversion-recovery curve, an Ernst steady state. There is nothing to play and
|
|
37
|
+
no state to carry, so there is no `layout` and the `SpinPhysics` carries only
|
|
38
|
+
the property declaration. `SPGRSimulator` is written this way; `MP2RAGESimulator`
|
|
39
|
+
carries both, the closed form a lookup table is built from and the layout a
|
|
40
|
+
description arriving from a scanner is compared against.
|
|
41
|
+
|
|
42
|
+
## An operator of your own
|
|
43
|
+
|
|
44
|
+
An operator is a Python function that returns events. `Excitation`,
|
|
45
|
+
`Refocusing`, `Readout`, `Dephase`, `Spoil`, `Delay` and the readout modules
|
|
46
|
+
built from them speak exactly the vocabulary the kernels implement, so a module
|
|
47
|
+
you write — a T2 preparation, an MT saturation, a shaped pulse — reaches the
|
|
48
|
+
fused kernels with no change to them.
|
|
49
|
+
|
|
50
|
+
An event is a wait, an RF pulse, or an ADC. **Gradients are not events**: each
|
|
51
|
+
event declares its own role (`CRUSH_BEFORE`, `CRUSH_AFTER`, `SHIFT_AFTER`,
|
|
52
|
+
`SPOIL_AFTER`), because a Pulseq file has no gradient *use* field and a crusher
|
|
53
|
+
cannot be told from a phase encode by looking at waveforms. What an operator
|
|
54
|
+
cannot say is how much a gradient dephases: a description carries one crusher
|
|
55
|
+
moment for the whole sequence, and dephasing is quantized to whole
|
|
56
|
+
configuration orders.
|
|
57
|
+
|
|
58
|
+
## Adding a physical effect
|
|
59
|
+
|
|
60
|
+
A tissue property has an **identity** — the value at which it has no effect —
|
|
61
|
+
and a run reads which properties were passed to decide which terms the kernel
|
|
62
|
+
evaluates. Adding an effect is one line in a model's property declaration, plus
|
|
63
|
+
the term itself in **both** kernels.
|
|
64
|
+
|
|
65
|
+
The shared parameter ABI is `src/blochsim/sequence/_parameters.py`, read by the
|
|
66
|
+
Python dispatch, the C++ extension and the Triton kernels. A parameter added
|
|
67
|
+
there is added in all three or in none.
|
|
68
|
+
|
|
69
|
+
## What the change has to arrive with
|
|
70
|
+
|
|
71
|
+
A test that pins the new physics against something **outside** BlochSim: a
|
|
72
|
+
closed form, a published figure, or an isochromat summation written out in the
|
|
73
|
+
test itself. Comparing BlochSim to BlochSim proves the two agree, which was
|
|
74
|
+
never in doubt. Put it in `tests/epg/` and state the invariant in the module
|
|
75
|
+
docstring.
|
|
76
|
+
|
|
77
|
+
Units are public at the edges and internal underneath: a caller writes
|
|
78
|
+
milliseconds, degrees and Hz; a description timestamps in microseconds and
|
|
79
|
+
carries radians. Convert at the boundary and name the unit in the identifier.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-and-test
|
|
3
|
+
description: Compile the C++ kernels and run the BlochSim suite, including the Triton paths on a machine with no GPU. Use when asked to build, install, test, or reproduce a failure in blochsim.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build and test BlochSim
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
pip install -e ".[dev]" ; echo "exit: $?"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`dev` is `test` + `doc` + `examples` plus ruff, mypy and pre-commit. For a test
|
|
15
|
+
run alone, `pip install -e ".[test]"` is enough and much smaller.
|
|
16
|
+
|
|
17
|
+
An editable install puts the Python sources on the path, so an edit under
|
|
18
|
+
`src/blochsim` takes effect on the next import. The two C++ extensions are
|
|
19
|
+
compiled artifacts and do not: re-run the install after editing any `.cpp`.
|
|
20
|
+
|
|
21
|
+
**Read the exit status, not the output.** A failed compile leaves the
|
|
22
|
+
previously built `.so` importable, so the suite runs green against a kernel
|
|
23
|
+
that no longer corresponds to the source. Confirm the extension is the one you
|
|
24
|
+
just built:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
python -c "import blochsim._epg_cpu as k; print(k.__file__)"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Test
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
pytest tests/ # everything, with coverage
|
|
34
|
+
pytest tests/epg/ # one area
|
|
35
|
+
pytest tests/epg/test_shift.py -k inversion
|
|
36
|
+
pytest tests/ -n auto # across cores
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`tests/` mirrors the source. `epg/` pins the state machine operator by operator
|
|
40
|
+
against closed forms — the shift, the RF rotation, relaxation, diffusion, flow,
|
|
41
|
+
spoiling, the two-pool and three-pool longitudinal steps — while `sequence/`,
|
|
42
|
+
`model/`, `estimators/`, `recon/` and `optim/` cover the layers above.
|
|
43
|
+
|
|
44
|
+
## The Triton paths, without a GPU
|
|
45
|
+
|
|
46
|
+
The tests carrying the `interpreted` marker are deselected by `addopts`. They
|
|
47
|
+
run a Triton kernel through Triton's CPU interpreter — no card, no compile,
|
|
48
|
+
about a minute each — and are how the GPU plumbing is verified anywhere:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
pytest tests/ -m interpreted
|
|
52
|
+
TRITON_INTERPRET=1 python your_script.py # the same trick, by hand
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Triton has no wheel for macOS or Windows. On those platforms the default
|
|
56
|
+
deselection is not an optimisation, it is the only thing that runs.
|
|
57
|
+
|
|
58
|
+
## Before you time anything
|
|
59
|
+
|
|
60
|
+
Kernel compiles dominate a cold GPU run, not the arithmetic. A suite that takes
|
|
61
|
+
minutes on a card is mostly Triton compiling one specialization per feature
|
|
62
|
+
combination it meets; the second run of the same suite is a different number
|
|
63
|
+
entirely. Run the whole suite at natural boundaries rather than after every
|
|
64
|
+
edit.
|
|
65
|
+
|
|
66
|
+
The cache keys on the *source* of `_epg_triton.py`, not on what it means, so a
|
|
67
|
+
formatting pass or a deleted dead local costs the same full recompile as a new
|
|
68
|
+
`tl.constexpr`. If the suite suddenly takes an hour where it took minutes,
|
|
69
|
+
check whether that file changed before looking for a performance regression.
|
|
70
|
+
|
|
71
|
+
## Style
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
pre-commit install # once per clone; nothing runs on commit until you do
|
|
75
|
+
pre-commit run --all-files # the whole tree, which is what CI's Lint job runs
|
|
76
|
+
pre-commit run --files path/to/one.py
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`ruff format`, then `ruff check --fix`, plus whitespace and file hygiene. There
|
|
80
|
+
is no black and no isort, and `.pre-commit-config.yaml` pins the ruff version
|
|
81
|
+
so a local run and CI agree on it.
|
|
82
|
+
|
|
83
|
+
A hook that rewrites a file fails the commit and leaves the fix in the working
|
|
84
|
+
tree: read it, `git add` it, commit again.
|
|
85
|
+
|
|
86
|
+
To get a commit through without them — a work-in-progress commit, or a merge
|
|
87
|
+
you did not write:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
SKIP=ruff-check git commit -m "..." # one hook
|
|
91
|
+
git commit --no-verify -m "..." # all of them
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
CI runs the same hooks over the whole tree on every branch, so either one
|
|
95
|
+
defers the failure rather than avoiding it.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-the-docs
|
|
3
|
+
description: Build the BlochSim documentation, add a figure to an explanation page, or add a gallery example. Use when asked about docs, Sphinx, the gallery, MyST, or Read the Docs for blochsim.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Build the BlochSim documentation
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
bash scripts/build_docs.sh # incremental
|
|
10
|
+
bash scripts/build_docs.sh --clean # re-execute every example
|
|
11
|
+
PYTHON_BIN=~/envs/blochsim/bin/python bash scripts/build_docs.sh
|
|
12
|
+
python -m http.server --directory docs/build/html 8000
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The script checks that the interpreter it is given can import BlochSim and the
|
|
16
|
+
documentation extensions, then builds into `docs/build/html`. Two things make
|
|
17
|
+
it slower than a plain Sphinx run and are the point of it: **sphinx-gallery
|
|
18
|
+
executes the examples**, and **the explanation pages' figures are re-rendered**
|
|
19
|
+
by `docs/explanation_figures.py` with the BlochSim in your working tree.
|
|
20
|
+
|
|
21
|
+
An example is executed when the interpreter can import everything it imports:
|
|
22
|
+
an environment with the `dev` or `examples` extra runs the whole gallery, one
|
|
23
|
+
with `doc` alone runs what needs nothing but BlochSim. A page already carrying
|
|
24
|
+
output executed from the source as it stands is reused rather than re-run, and
|
|
25
|
+
the build names each example it did not run and where its output came from. To
|
|
26
|
+
build the pages without running any of them, pass `-D plot_gallery=0`.
|
|
27
|
+
|
|
28
|
+
## Where the published pages are built
|
|
29
|
+
|
|
30
|
+
`.github/workflows/docs.yml` builds them, and GitHub Pages serves them from
|
|
31
|
+
the `gh-pages` branch at <https://pulserver.github.io/blochsim/>.
|
|
32
|
+
|
|
33
|
+
Its **HTML** job runs on every branch and pull request with the `doc` extra:
|
|
34
|
+
every page is written and the examples needing nothing but BlochSim are
|
|
35
|
+
executed, in a few minutes, and the tree is uploaded as an artifact to read.
|
|
36
|
+
|
|
37
|
+
Its **Site** job runs on `main`, on a `v*.*.*` tag and on demand. It installs
|
|
38
|
+
the `examples` extra, so every notebook is executed, and hands what
|
|
39
|
+
Sphinx wrote to `scripts/publish_docs.py`, which places it in the site:
|
|
40
|
+
|
|
41
|
+
site/latest/ the development branch
|
|
42
|
+
site/v1.2.3/ one directory per release, kept as it was published
|
|
43
|
+
site/index.html a page sending a reader to the newest release
|
|
44
|
+
site/versions.json the list the switcher in the sidebar reads
|
|
45
|
+
|
|
46
|
+
`BLOCHSIM_DOCS_VERSION` is what a build calls itself; it names the directory,
|
|
47
|
+
the switcher's mark and the Binder path prefix, and defaults to `latest`.
|
|
48
|
+
|
|
49
|
+
## Markdown, and the two places it is not
|
|
50
|
+
|
|
51
|
+
Pages are **MyST Markdown**. Two file sets stay reStructuredText because the
|
|
52
|
+
tooling requires it — converting either breaks the build:
|
|
53
|
+
|
|
54
|
+
- `examples/**/README.rst` — sphinx-gallery concatenates a gallery header
|
|
55
|
+
verbatim into a generated `index.rst`.
|
|
56
|
+
- `docs/_templates/autosummary/*.rst` — `sphinx.ext.autosummary` writes stubs
|
|
57
|
+
with a hardcoded `.rst` suffix and finds its directives by regex over raw
|
|
58
|
+
source lines.
|
|
59
|
+
|
|
60
|
+
That regex is also why the API pages hold `autosummary` and `currentmodule`
|
|
61
|
+
inside `` ```{eval-rst} `` blocks rather than in MyST directive syntax: written
|
|
62
|
+
as `` ```{autosummary} `` the stub generator never sees them and every linked
|
|
63
|
+
page 404s.
|
|
64
|
+
|
|
65
|
+
## Add a figure to an explanation page
|
|
66
|
+
|
|
67
|
+
Write a function in `docs/explanation_figures.py` that returns a Matplotlib
|
|
68
|
+
figure, register it in the `FIGURES` mapping at the bottom, and reference the
|
|
69
|
+
file it writes:
|
|
70
|
+
|
|
71
|
+
````markdown
|
|
72
|
+
```{figure} /generated/figures/your_figure.png
|
|
73
|
+
:width: 100%
|
|
74
|
+
:alt: One sentence a screen reader can use.
|
|
75
|
+
|
|
76
|
+
The caption, which is where the reader is told what to look at.
|
|
77
|
+
```
|
|
78
|
+
````
|
|
79
|
+
|
|
80
|
+
Figures are simulated at build time rather than checked in, so one cannot
|
|
81
|
+
outlive the behaviour it shows.
|
|
82
|
+
|
|
83
|
+
## Add a gallery example
|
|
84
|
+
|
|
85
|
+
Drop a script into the right `examples/` section. The numeric prefix orders it
|
|
86
|
+
within the section, and the module docstring — an reStructuredText title block
|
|
87
|
+
— becomes the page's introduction. What it imports decides where it is
|
|
88
|
+
executed and where it is published as source.
|
|
89
|
+
|
|
90
|
+
## Writing
|
|
91
|
+
|
|
92
|
+
The audience is MR scientists: pulse sequences and physics, not software
|
|
93
|
+
architecture. Describe what BlochSim does and why that is right on its own
|
|
94
|
+
terms. These pages are not a changelog — never justify a design by describing
|
|
95
|
+
the design it replaced.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## Documentation architecture
|
|
99
|
+
|
|
100
|
+
Keep the public sidebar shallow and in this order:
|
|
101
|
+
|
|
102
|
+
1. User Guide
|
|
103
|
+
2. Developer Guide
|
|
104
|
+
3. Explanations
|
|
105
|
+
4. Examples
|
|
106
|
+
5. API
|
|
107
|
+
6. Miscellaneous
|
|
108
|
+
|
|
109
|
+
The first four Framework examples are the Course. They teach the public
|
|
110
|
+
abstraction in order; the remaining example sections are standalone Tours.
|
|
111
|
+
|
|
112
|
+
For a new sequence, teach {class}`blochsim.model.Simulator` as the extension
|
|
113
|
+
point. A state-machine simulator has two complementary inputs: its class-level
|
|
114
|
+
handlers interpret commands from an incoming Pulseq/MRD description, and
|
|
115
|
+
`layout()` constructs the same sequence offline. Lower-level
|
|
116
|
+
`SequenceDescription`, `SpinPhysics` and operator machinery are important
|
|
117
|
+
reference/developer concepts, not competing user-facing sequence APIs.
|
|
118
|
+
|
|
119
|
+
Functional `*_sim` calls are conveniences around shipped simulators. Do not
|
|
120
|
+
present them as the abstraction a user implements.
|
|
121
|
+
|
|
122
|
+
Figures must remain readable at final documentation width in both light and
|
|
123
|
+
dark mode. Use `docs/figure_style.py` for common typography, transparent
|
|
124
|
+
backgrounds and foreground colors; examples set only figure-specific geometry
|
|
125
|
+
and scientific encodings.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cut-a-release
|
|
3
|
+
description: Publish a BlochSim release to PyPI, and diagnose a wheel build. Use when asked about releasing, versioning, cibuildwheel, abi3 wheels, or the packaging setup.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cut a BlochSim release
|
|
7
|
+
|
|
8
|
+
The version comes from the git tag through setuptools-scm; nothing in the tree
|
|
9
|
+
states it. To release:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
git tag -a v0.1.0 -m "v0.1.0"
|
|
13
|
+
git push origin v0.1.0
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The `Wheels` workflow then builds the sdist and every wheel, tests each one,
|
|
17
|
+
and publishes to PyPI through trusted publishing — no token is stored
|
|
18
|
+
anywhere. The `pypi` environment on the repository gates it.
|
|
19
|
+
|
|
20
|
+
`workflow_dispatch` builds and tests everything without publishing, which is
|
|
21
|
+
how to check a packaging change before tagging. So does any pull request that
|
|
22
|
+
touches `pyproject.toml`, `CMakeLists.txt`, the `.cpp` sources, or the workflow.
|
|
23
|
+
|
|
24
|
+
## What gets built, and why there is so little of it
|
|
25
|
+
|
|
26
|
+
Both kernels are plain CPython extensions against the **stable ABI** from 3.10
|
|
27
|
+
on. They call no PyTorch API and link no PyTorch library. So:
|
|
28
|
+
|
|
29
|
+
- one `cp310-abi3` wheel per platform serves every supported interpreter —
|
|
30
|
+
there is no per-minor-version build to repeat;
|
|
31
|
+
- the wheel is a couple of megabytes rather than the size of libtorch, and
|
|
32
|
+
needs no `auditwheel`/`delocate` repair beyond manylinux compliance.
|
|
33
|
+
|
|
34
|
+
A `#include <torch/...>` in either `.cpp` ends all of that: the wheel would
|
|
35
|
+
become per-version, per-torch-version, and hundreds of megabytes.
|
|
36
|
+
`scripts/check_wheel.py` guards the size and is what cibuildwheel tests every
|
|
37
|
+
wheel with — it loads each kernel by file path, so it needs no PyTorch.
|
|
38
|
+
|
|
39
|
+
Platforms: manylinux x86_64 and aarch64 on native runners, macOS arm64 with the
|
|
40
|
+
Intel wheel cross-compiled beside it, Windows AMD64.
|
|
41
|
+
|
|
42
|
+
## The build itself
|
|
43
|
+
|
|
44
|
+
`scikit-build-core` drives `CMakeLists.txt`. `setup.py` is a shim for tools
|
|
45
|
+
that still shell out to it and configures nothing — do not put build logic
|
|
46
|
+
there. `[tool.scikit-build]` in `pyproject.toml` sets `wheel.py-api = "cp310"`,
|
|
47
|
+
which is what produces the abi3 tag, and excludes the `.cpp` and `.hpp` sources
|
|
48
|
+
from the wheel.
|
|
49
|
+
|
|
50
|
+
CMake 3.26 or newer is required, for `python_add_library(... USE_SABI ...)`.
|
|
51
|
+
scikit-build-core installs it as a build-time wheel when the system CMake is
|
|
52
|
+
older, so a stale system CMake is not a problem — unless you build with
|
|
53
|
+
`--no-build-isolation`, where it is.
|