pulserver 0.0.2__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.
Files changed (472) hide show
  1. pulserver-0.0.2/.claude/skills/build-and-test/SKILL.md +44 -0
  2. pulserver-0.0.2/.claude/skills/write-documentation/SKILL.md +91 -0
  3. pulserver-0.0.2/.dockerignore +11 -0
  4. pulserver-0.0.2/.gitattributes +16 -0
  5. pulserver-0.0.2/.github/ISSUE_TEMPLATE/bug_report.yml +43 -0
  6. pulserver-0.0.2/.github/ISSUE_TEMPLATE/config.yml +8 -0
  7. pulserver-0.0.2/.github/ISSUE_TEMPLATE/feature_request.yml +36 -0
  8. pulserver-0.0.2/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  9. pulserver-0.0.2/.github/dependabot.yml +40 -0
  10. pulserver-0.0.2/.github/workflows/codeql.yml +36 -0
  11. pulserver-0.0.2/.github/workflows/console.yml +39 -0
  12. pulserver-0.0.2/.github/workflows/docs.yml +133 -0
  13. pulserver-0.0.2/.github/workflows/fields.yml +72 -0
  14. pulserver-0.0.2/.github/workflows/image.yml +57 -0
  15. pulserver-0.0.2/.github/workflows/koma.yml +65 -0
  16. pulserver-0.0.2/.github/workflows/style.yml +42 -0
  17. pulserver-0.0.2/.github/workflows/tags-release.yml +59 -0
  18. pulserver-0.0.2/.github/workflows/test-ci.yml +107 -0
  19. pulserver-0.0.2/.github/workflows/wheels.yml +64 -0
  20. pulserver-0.0.2/.gitignore +38 -0
  21. pulserver-0.0.2/.pre-commit-config.yaml +31 -0
  22. pulserver-0.0.2/AGENTS.md +343 -0
  23. pulserver-0.0.2/CLAUDE.md +1 -0
  24. pulserver-0.0.2/CMakeLists.txt +62 -0
  25. pulserver-0.0.2/CODE_OF_CONDUCT.md +42 -0
  26. pulserver-0.0.2/CONTRIBUTING.md +26 -0
  27. pulserver-0.0.2/GEMINI.md +1 -0
  28. pulserver-0.0.2/LICENSE +21 -0
  29. pulserver-0.0.2/LICENSES/gadgetron-python-MIT.txt +21 -0
  30. pulserver-0.0.2/LICENSES/python-ismrmrd-server-MIT.txt +21 -0
  31. pulserver-0.0.2/NEXT.md +100 -0
  32. pulserver-0.0.2/PKG-INFO +245 -0
  33. pulserver-0.0.2/README.md +194 -0
  34. pulserver-0.0.2/SECURITY.md +36 -0
  35. pulserver-0.0.2/SKILLS.md +17 -0
  36. pulserver-0.0.2/codecov.yml +22 -0
  37. pulserver-0.0.2/docker/Dockerfile +59 -0
  38. pulserver-0.0.2/docker/compose.yaml +51 -0
  39. pulserver-0.0.2/docker/entrypoint.sh +20 -0
  40. pulserver-0.0.2/docker/limits/limits.txt +9 -0
  41. pulserver-0.0.2/docker/smoke.py +98 -0
  42. pulserver-0.0.2/docs/_static/architecture-dark.svg +46 -0
  43. pulserver-0.0.2/docs/_static/architecture.svg +46 -0
  44. pulserver-0.0.2/docs/_static/capabilities.js +15 -0
  45. pulserver-0.0.2/docs/_static/context-dark.svg +39 -0
  46. pulserver-0.0.2/docs/_static/context.svg +39 -0
  47. pulserver-0.0.2/docs/_static/pulseg-dark.svg +46 -0
  48. pulserver-0.0.2/docs/_static/pulseg.svg +46 -0
  49. pulserver-0.0.2/docs/_static/pulserver-logo-dark.svg +39 -0
  50. pulserver-0.0.2/docs/_static/pulserver-logo.svg +39 -0
  51. pulserver-0.0.2/docs/_static/pulserver-mark-dark.svg +38 -0
  52. pulserver-0.0.2/docs/_static/pulserver-mark.svg +38 -0
  53. pulserver-0.0.2/docs/_static/pulserver.css +86 -0
  54. pulserver-0.0.2/docs/_static/repetition-dark.svg +47 -0
  55. pulserver-0.0.2/docs/_static/repetition.svg +47 -0
  56. pulserver-0.0.2/docs/_static/safety-dark.svg +42 -0
  57. pulserver-0.0.2/docs/_static/safety.svg +42 -0
  58. pulserver-0.0.2/docs/_static/session-dark.svg +40 -0
  59. pulserver-0.0.2/docs/_static/session.svg +40 -0
  60. pulserver-0.0.2/docs/_static/virtual-dark.svg +40 -0
  61. pulserver-0.0.2/docs/_static/virtual.svg +40 -0
  62. pulserver-0.0.2/docs/_templates/autosummary/base.rst +5 -0
  63. pulserver-0.0.2/docs/_templates/autosummary/class.rst +29 -0
  64. pulserver-0.0.2/docs/_templates/autosummary/enum.rst +8 -0
  65. pulserver-0.0.2/docs/_templates/autosummary/function.rst +5 -0
  66. pulserver-0.0.2/docs/api/design.md +67 -0
  67. pulserver-0.0.2/docs/api/host.md +28 -0
  68. pulserver-0.0.2/docs/api/index.md +34 -0
  69. pulserver-0.0.2/docs/api/ir.md +46 -0
  70. pulserver-0.0.2/docs/api/mrd.md +53 -0
  71. pulserver-0.0.2/docs/api/protocol.md +100 -0
  72. pulserver-0.0.2/docs/api/proxy.md +56 -0
  73. pulserver-0.0.2/docs/api/recon.md +72 -0
  74. pulserver-0.0.2/docs/api/validate.md +32 -0
  75. pulserver-0.0.2/docs/api/virtual.md +70 -0
  76. pulserver-0.0.2/docs/api_objects.py +91 -0
  77. pulserver-0.0.2/docs/colab.py +129 -0
  78. pulserver-0.0.2/docs/conf.py +367 -0
  79. pulserver-0.0.2/docs/developer-guide/documentation.md +832 -0
  80. pulserver-0.0.2/docs/developer-guide/index.md +26 -0
  81. pulserver-0.0.2/docs/developer-guide/installation.md +52 -0
  82. pulserver-0.0.2/docs/developer-guide/internals/calibration.md +176 -0
  83. pulserver-0.0.2/docs/developer-guide/internals/index.md +25 -0
  84. pulserver-0.0.2/docs/developer-guide/internals/ir-cache.md +298 -0
  85. pulserver-0.0.2/docs/developer-guide/internals/protocol-wire.md +150 -0
  86. pulserver-0.0.2/docs/developer-guide/internals/reconstruction-proxy.md +289 -0
  87. pulserver-0.0.2/docs/developer-guide/internals/sar-ratios.md +57 -0
  88. pulserver-0.0.2/docs/developer-guide/internals/virtual-scanner.md +565 -0
  89. pulserver-0.0.2/docs/developer-guide/releases.md +14 -0
  90. pulserver-0.0.2/docs/developer-guide/style.md +43 -0
  91. pulserver-0.0.2/docs/developer-guide/terminology.md +265 -0
  92. pulserver-0.0.2/docs/developer-guide/workflow.md +39 -0
  93. pulserver-0.0.2/docs/examples/course.md +35 -0
  94. pulserver-0.0.2/docs/examples/index.md +37 -0
  95. pulserver-0.0.2/docs/examples/tours.md +18 -0
  96. pulserver-0.0.2/docs/explanations/architecture.md +124 -0
  97. pulserver-0.0.2/docs/explanations/index.md +34 -0
  98. pulserver-0.0.2/docs/explanations/protocol.md +99 -0
  99. pulserver-0.0.2/docs/explanations/raw-data.md +97 -0
  100. pulserver-0.0.2/docs/explanations/reconstruction-session.md +113 -0
  101. pulserver-0.0.2/docs/explanations/reconstruction.md +114 -0
  102. pulserver-0.0.2/docs/explanations/safety-checks.md +122 -0
  103. pulserver-0.0.2/docs/explanations/scanner-representation.md +192 -0
  104. pulserver-0.0.2/docs/explanations/virtual-scanner.md +110 -0
  105. pulserver-0.0.2/docs/figure_style.py +79 -0
  106. pulserver-0.0.2/docs/index.md +16 -0
  107. pulserver-0.0.2/docs/misc/contributors.md +7 -0
  108. pulserver-0.0.2/docs/misc/index.md +15 -0
  109. pulserver-0.0.2/docs/misc/license.md +25 -0
  110. pulserver-0.0.2/docs/misc/related.md +12 -0
  111. pulserver-0.0.2/docs/user-guide/index.md +97 -0
  112. pulserver-0.0.2/docs/user-guide/reconstruction-client.md +87 -0
  113. pulserver-0.0.2/docs/user-guide/reconstruction-plugins.md +422 -0
  114. pulserver-0.0.2/docs/user-guide/running.md +438 -0
  115. pulserver-0.0.2/docs/user-guide/scanner-sequences.md +540 -0
  116. pulserver-0.0.2/docs/user-guide/virtual-scanner.md +383 -0
  117. pulserver-0.0.2/gallery/01-course/01_protocol_to_image.py +242 -0
  118. pulserver-0.0.2/gallery/01-course/02_sequence_plugin.py +447 -0
  119. pulserver-0.0.2/gallery/01-course/03_scanner_representation.py +285 -0
  120. pulserver-0.0.2/gallery/01-course/04_reconstruction_plugin.py +304 -0
  121. pulserver-0.0.2/gallery/01-course/05_recon_plugin.py +249 -0
  122. pulserver-0.0.2/gallery/01-course/06_testing_on_the_virtual_scanner.py +340 -0
  123. pulserver-0.0.2/gallery/01-course/README.rst +6 -0
  124. pulserver-0.0.2/gallery/01-course/_gallery_header.md +1 -0
  125. pulserver-0.0.2/gallery/02-tours/01_protocol_resolution.py +216 -0
  126. pulserver-0.0.2/gallery/02-tours/02_segmentation.py +166 -0
  127. pulserver-0.0.2/gallery/02-tours/03_fov_offset_enrichment.py +209 -0
  128. pulserver-0.0.2/gallery/02-tours/README.rst +6 -0
  129. pulserver-0.0.2/gallery/02-tours/_gallery_header.md +1 -0
  130. pulserver-0.0.2/gallery/README.rst +6 -0
  131. pulserver-0.0.2/gallery/_gallery_header.md +2 -0
  132. pulserver-0.0.2/pyproject.toml +156 -0
  133. pulserver-0.0.2/scripts/build_docs.sh +22 -0
  134. pulserver-0.0.2/scripts/check_throughput.py +100 -0
  135. pulserver-0.0.2/scripts/format_and_lint.sh +19 -0
  136. pulserver-0.0.2/scripts/make_artwork.py +586 -0
  137. pulserver-0.0.2/scripts/publish_docs.py +150 -0
  138. pulserver-0.0.2/setup.py +5 -0
  139. pulserver-0.0.2/src/c/CMakeLists.txt +43 -0
  140. pulserver-0.0.2/src/c/cache/pulseg_cache.c +2992 -0
  141. pulserver-0.0.2/src/c/core/pulseg_core.c +1136 -0
  142. pulserver-0.0.2/src/c/core/pulseg_error.c +227 -0
  143. pulserver-0.0.2/src/c/core/pulseg_math.c +259 -0
  144. pulserver-0.0.2/src/c/include/pulseg/pulseg.h +34 -0
  145. pulserver-0.0.2/src/c/include/pulseg/pulseg_cache.h +161 -0
  146. pulserver-0.0.2/src/c/include/pulseg/pulseg_collection.h +887 -0
  147. pulserver-0.0.2/src/c/include/pulseg/pulseg_config.h +122 -0
  148. pulserver-0.0.2/src/c/include/pulseg/pulseg_errors.h +82 -0
  149. pulserver-0.0.2/src/c/include/pulseg/pulseg_io.h +66 -0
  150. pulserver-0.0.2/src/c/include/pulseg/pulseg_playout.h +241 -0
  151. pulserver-0.0.2/src/c/include/pulseg/pulseg_protocol.h +467 -0
  152. pulserver-0.0.2/src/c/include/pulseg/pulseg_types.h +1066 -0
  153. pulserver-0.0.2/src/c/include/pulseq/pulseq.h +45 -0
  154. pulserver-0.0.2/src/c/include/pulseq/pulseq_config.h +109 -0
  155. pulserver-0.0.2/src/c/include/pulseq/pulseq_types.h +449 -0
  156. pulserver-0.0.2/src/c/io/pulseg_opts.c +63 -0
  157. pulserver-0.0.2/src/c/io/pulseg_protocol.c +907 -0
  158. pulserver-0.0.2/src/c/playout/pulseg_playout.c +558 -0
  159. pulserver-0.0.2/src/c/pulseg_internal.h +1049 -0
  160. pulserver-0.0.2/src/c/pulseq/pulseq_internal.h +36 -0
  161. pulserver-0.0.2/src/c/pulseq/pulseq_shape.c +86 -0
  162. pulserver-0.0.2/src/c/structure/pulseg_descriptor.c +239 -0
  163. pulserver-0.0.2/src/c/structure/pulseg_getters.c +3522 -0
  164. pulserver-0.0.2/src/c/structure/pulseg_repetition.c +102 -0
  165. pulserver-0.0.2/src/c/structure/pulseg_waves.c +1015 -0
  166. pulserver-0.0.2/src/cpp/fourier/bindings.cpp +370 -0
  167. pulserver-0.0.2/src/cpp/fourier/bindings.hpp +13 -0
  168. pulserver-0.0.2/src/cpp/fourier/parallel.hpp +256 -0
  169. pulserver-0.0.2/src/cpp/fourier/timeline.cpp +473 -0
  170. pulserver-0.0.2/src/cpp/fourier/timeline.hpp +182 -0
  171. pulserver-0.0.2/src/cpp/ir/collection.cpp +254 -0
  172. pulserver-0.0.2/src/cpp/ir/dedup.cpp +1851 -0
  173. pulserver-0.0.2/src/cpp/ir/from_libraries.cpp +551 -0
  174. pulserver-0.0.2/src/cpp/ir/from_libraries.hpp +32 -0
  175. pulserver-0.0.2/src/cpp/ir/pulseg_convert.h +103 -0
  176. pulserver-0.0.2/src/cpp/ir/pulseq_file.cpp +329 -0
  177. pulserver-0.0.2/src/cpp/ir/pulseq_file.h +53 -0
  178. pulserver-0.0.2/src/cpp/ir/repetition.cpp +216 -0
  179. pulserver-0.0.2/src/cpp/ir/structure.cpp +3606 -0
  180. pulserver-0.0.2/src/cpp/ir/wave_plan.cpp +376 -0
  181. pulserver-0.0.2/src/cpp/ir/waves.cpp +474 -0
  182. pulserver-0.0.2/src/cpp/module.cpp +994 -0
  183. pulserver-0.0.2/src/cpp/native.hpp +269 -0
  184. pulserver-0.0.2/src/cpp/playout.cpp +684 -0
  185. pulserver-0.0.2/src/cpp/playout.hpp +26 -0
  186. pulserver-0.0.2/src/pulserver/__init__.py +13 -0
  187. pulserver-0.0.2/src/pulserver/_accelerators.py +68 -0
  188. pulserver-0.0.2/src/pulserver/_cli.py +54 -0
  189. pulserver-0.0.2/src/pulserver/_labels.py +184 -0
  190. pulserver-0.0.2/src/pulserver/_logs.py +44 -0
  191. pulserver-0.0.2/src/pulserver/_memory.py +21 -0
  192. pulserver-0.0.2/src/pulserver/_plugins.py +83 -0
  193. pulserver-0.0.2/src/pulserver/_zoo/__init__.py +35 -0
  194. pulserver-0.0.2/src/pulserver/_zoo/_evaluation.py +325 -0
  195. pulserver-0.0.2/src/pulserver/_zoo/_inversion.py +110 -0
  196. pulserver-0.0.2/src/pulserver/_zoo/_pmc.py +26 -0
  197. pulserver-0.0.2/src/pulserver/_zoo/_saturation.py +118 -0
  198. pulserver-0.0.2/src/pulserver/_zoo/_slab.py +37 -0
  199. pulserver-0.0.2/src/pulserver/_zoo/_user.py +160 -0
  200. pulserver-0.0.2/src/pulserver/_zoo/parameters/bssfp2d/retrospective.toml +2 -0
  201. pulserver-0.0.2/src/pulserver/_zoo/parameters/fse3d/dual_region.toml +2 -0
  202. pulserver-0.0.2/src/pulserver/_zoo/parameters/fse3d/navigator.toml +2 -0
  203. pulserver-0.0.2/src/pulserver/_zoo/parameters/fse3d/optimized.toml +2 -0
  204. pulserver-0.0.2/src/pulserver/_zoo/parameters/fse3d/shuffling.toml +2 -0
  205. pulserver-0.0.2/src/pulserver/_zoo/parameters/fse3d/wave.toml +2 -0
  206. pulserver-0.0.2/src/pulserver/_zoo/parameters/gre3d/full_plane.toml +2 -0
  207. pulserver-0.0.2/src/pulserver/_zoo/parameters/gre3d/wave.toml +2 -0
  208. pulserver-0.0.2/src/pulserver/_zoo/parameters/gre_multiecho2d/bipolar.toml +2 -0
  209. pulserver-0.0.2/src/pulserver/_zoo/parameters/gre_multiecho3d/bipolar.toml +2 -0
  210. pulserver-0.0.2/src/pulserver/_zoo/parameters/gre_multiecho3d/full_plane.toml +2 -0
  211. pulserver-0.0.2/src/pulserver/_zoo/parameters/gre_multiecho3d/wave.toml +2 -0
  212. pulserver-0.0.2/src/pulserver/_zoo/parameters/gre_spiral2d/variable_density.toml +2 -0
  213. pulserver-0.0.2/src/pulserver/_zoo/parameters/gre_stack_of_spirals3d/variable_density.toml +2 -0
  214. pulserver-0.0.2/src/pulserver/_zoo/parameters/mprage3d/navigator.toml +2 -0
  215. pulserver-0.0.2/src/pulserver/_zoo/parameters/mprage3d/shuffling.toml +2 -0
  216. pulserver-0.0.2/src/pulserver/_zoo/parameters/mprage3d/wave.toml +2 -0
  217. pulserver-0.0.2/src/pulserver/_zoo/parameters/mprage_stack_of_spirals3d/variable_density.toml +2 -0
  218. pulserver-0.0.2/src/pulserver/_zoo/parameters/se3d/full_plane.toml +2 -0
  219. pulserver-0.0.2/src/pulserver/_zoo/parameters/se_spiral2d/variable_density.toml +2 -0
  220. pulserver-0.0.2/src/pulserver/_zoo/parameters/se_stack_of_spirals3d/variable_density.toml +2 -0
  221. pulserver-0.0.2/src/pulserver/_zoo/parameters/zte3d/meridian.toml +2 -0
  222. pulserver-0.0.2/src/pulserver/_zoo/recon/epi.py +3 -0
  223. pulserver-0.0.2/src/pulserver/_zoo/recon/nufft.py +3 -0
  224. pulserver-0.0.2/src/pulserver/_zoo/recon/nufft_train.py +3 -0
  225. pulserver-0.0.2/src/pulserver/_zoo/recon/pics.py +3 -0
  226. pulserver-0.0.2/src/pulserver/_zoo/recon/pics_train.py +3 -0
  227. pulserver-0.0.2/src/pulserver/_zoo/recon/pmc.py +3 -0
  228. pulserver-0.0.2/src/pulserver/_zoo/sequences/bssfp2d.py +180 -0
  229. pulserver-0.0.2/src/pulserver/_zoo/sequences/bssfp3d.py +93 -0
  230. pulserver-0.0.2/src/pulserver/_zoo/sequences/epi2d.py +163 -0
  231. pulserver-0.0.2/src/pulserver/_zoo/sequences/epi3d.py +206 -0
  232. pulserver-0.0.2/src/pulserver/_zoo/sequences/fse3d.py +206 -0
  233. pulserver-0.0.2/src/pulserver/_zoo/sequences/gre2d.py +75 -0
  234. pulserver-0.0.2/src/pulserver/_zoo/sequences/gre3d.py +77 -0
  235. pulserver-0.0.2/src/pulserver/_zoo/sequences/gre_multiecho2d.py +69 -0
  236. pulserver-0.0.2/src/pulserver/_zoo/sequences/gre_multiecho3d.py +82 -0
  237. pulserver-0.0.2/src/pulserver/_zoo/sequences/gre_propeller2d.py +56 -0
  238. pulserver-0.0.2/src/pulserver/_zoo/sequences/gre_radial2d.py +55 -0
  239. pulserver-0.0.2/src/pulserver/_zoo/sequences/gre_spiral2d.py +73 -0
  240. pulserver-0.0.2/src/pulserver/_zoo/sequences/gre_stack_of_blades3d.py +61 -0
  241. pulserver-0.0.2/src/pulserver/_zoo/sequences/gre_stack_of_spirals3d.py +81 -0
  242. pulserver-0.0.2/src/pulserver/_zoo/sequences/gre_stack_of_stars3d.py +60 -0
  243. pulserver-0.0.2/src/pulserver/_zoo/sequences/mprage3d.py +133 -0
  244. pulserver-0.0.2/src/pulserver/_zoo/sequences/mprage_stack_of_spirals3d.py +91 -0
  245. pulserver-0.0.2/src/pulserver/_zoo/sequences/mprage_stack_of_stars3d.py +71 -0
  246. pulserver-0.0.2/src/pulserver/_zoo/sequences/se2d.py +71 -0
  247. pulserver-0.0.2/src/pulserver/_zoo/sequences/se3d.py +72 -0
  248. pulserver-0.0.2/src/pulserver/_zoo/sequences/se_epi_propeller2d.py +121 -0
  249. pulserver-0.0.2/src/pulserver/_zoo/sequences/se_propeller2d.py +60 -0
  250. pulserver-0.0.2/src/pulserver/_zoo/sequences/se_radial2d.py +59 -0
  251. pulserver-0.0.2/src/pulserver/_zoo/sequences/se_spiral2d.py +77 -0
  252. pulserver-0.0.2/src/pulserver/_zoo/sequences/se_stack_of_blades3d.py +65 -0
  253. pulserver-0.0.2/src/pulserver/_zoo/sequences/se_stack_of_spirals3d.py +85 -0
  254. pulserver-0.0.2/src/pulserver/_zoo/sequences/se_stack_of_stars3d.py +64 -0
  255. pulserver-0.0.2/src/pulserver/_zoo/sequences/zte3d.py +90 -0
  256. pulserver-0.0.2/src/pulserver/design/__init__.py +51 -0
  257. pulserver-0.0.2/src/pulserver/design/_entries.py +561 -0
  258. pulserver-0.0.2/src/pulserver/design/_options.py +133 -0
  259. pulserver-0.0.2/src/pulserver/design/_plugin.py +617 -0
  260. pulserver-0.0.2/src/pulserver/design/_rf.py +111 -0
  261. pulserver-0.0.2/src/pulserver/host/__init__.py +14 -0
  262. pulserver-0.0.2/src/pulserver/host/__main__.py +8 -0
  263. pulserver-0.0.2/src/pulserver/host/_blocks.py +116 -0
  264. pulserver-0.0.2/src/pulserver/host/_command.py +281 -0
  265. pulserver-0.0.2/src/pulserver/host/_limits.py +318 -0
  266. pulserver-0.0.2/src/pulserver/host/_push.py +65 -0
  267. pulserver-0.0.2/src/pulserver/host/_server.py +263 -0
  268. pulserver-0.0.2/src/pulserver/host/_service.py +637 -0
  269. pulserver-0.0.2/src/pulserver/host/_store.py +317 -0
  270. pulserver-0.0.2/src/pulserver/ir/__init__.py +47 -0
  271. pulserver-0.0.2/src/pulserver/ir/_checks.py +495 -0
  272. pulserver-0.0.2/src/pulserver/ir/_convert.py +649 -0
  273. pulserver-0.0.2/src/pulserver/ir/_playout.py +135 -0
  274. pulserver-0.0.2/src/pulserver/ir/_source.py +800 -0
  275. pulserver-0.0.2/src/pulserver/ir/_vendor.py +113 -0
  276. pulserver-0.0.2/src/pulserver/ir/_waves.py +191 -0
  277. pulserver-0.0.2/src/pulserver/mrd/__init__.py +38 -0
  278. pulserver-0.0.2/src/pulserver/mrd/_acquisitions.py +380 -0
  279. pulserver-0.0.2/src/pulserver/mrd/_header.py +269 -0
  280. pulserver-0.0.2/src/pulserver/mrd/_images.py +113 -0
  281. pulserver-0.0.2/src/pulserver/mrd/_metadata.py +229 -0
  282. pulserver-0.0.2/src/pulserver/mrd/_sequence.py +480 -0
  283. pulserver-0.0.2/src/pulserver/protocol/__init__.py +89 -0
  284. pulserver-0.0.2/src/pulserver/protocol/_keys.py +485 -0
  285. pulserver-0.0.2/src/pulserver/protocol/_prescription.py +67 -0
  286. pulserver-0.0.2/src/pulserver/protocol/_schema.py +141 -0
  287. pulserver-0.0.2/src/pulserver/protocol/_wire.py +584 -0
  288. pulserver-0.0.2/src/pulserver/proxy/__init__.py +26 -0
  289. pulserver-0.0.2/src/pulserver/proxy/__main__.py +170 -0
  290. pulserver-0.0.2/src/pulserver/proxy/_designs.py +171 -0
  291. pulserver-0.0.2/src/pulserver/proxy/_enrich.py +785 -0
  292. pulserver-0.0.2/src/pulserver/proxy/_held.py +154 -0
  293. pulserver-0.0.2/src/pulserver/proxy/_intake.py +159 -0
  294. pulserver-0.0.2/src/pulserver/proxy/_local.py +103 -0
  295. pulserver-0.0.2/src/pulserver/proxy/_motion.py +232 -0
  296. pulserver-0.0.2/src/pulserver/proxy/_proxy.py +1142 -0
  297. pulserver-0.0.2/src/pulserver/proxy/_queue.py +71 -0
  298. pulserver-0.0.2/src/pulserver/proxy/_seqdesc.py +343 -0
  299. pulserver-0.0.2/src/pulserver/proxy/_workers.py +206 -0
  300. pulserver-0.0.2/src/pulserver/recon/__init__.py +51 -0
  301. pulserver-0.0.2/src/pulserver/recon/__main__.py +106 -0
  302. pulserver-0.0.2/src/pulserver/recon/_buffers.py +765 -0
  303. pulserver-0.0.2/src/pulserver/recon/_calibration.py +481 -0
  304. pulserver-0.0.2/src/pulserver/recon/_correct.py +98 -0
  305. pulserver-0.0.2/src/pulserver/recon/_exam_image.py +107 -0
  306. pulserver-0.0.2/src/pulserver/recon/_loader.py +35 -0
  307. pulserver-0.0.2/src/pulserver/recon/_runtime/__init__.py +1 -0
  308. pulserver-0.0.2/src/pulserver/recon/_runtime/application.py +314 -0
  309. pulserver-0.0.2/src/pulserver/recon/_runtime/concurrency.py +252 -0
  310. pulserver-0.0.2/src/pulserver/recon/_runtime/connection.py +574 -0
  311. pulserver-0.0.2/src/pulserver/recon/_runtime/constants.py +63 -0
  312. pulserver-0.0.2/src/pulserver/recon/_runtime/exam.py +292 -0
  313. pulserver-0.0.2/src/pulserver/recon/_runtime/mrd2dicom.py +789 -0
  314. pulserver-0.0.2/src/pulserver/recon/_runtime/offline.py +91 -0
  315. pulserver-0.0.2/src/pulserver/recon/_runtime/readers.py +261 -0
  316. pulserver-0.0.2/src/pulserver/recon/_runtime/writers.py +213 -0
  317. pulserver-0.0.2/src/pulserver/recon/_units.py +115 -0
  318. pulserver-0.0.2/src/pulserver/recon/gadgets.py +270 -0
  319. pulserver-0.0.2/src/pulserver/recon/handlers/__init__.py +1 -0
  320. pulserver-0.0.2/src/pulserver/recon/handlers/epi.py +211 -0
  321. pulserver-0.0.2/src/pulserver/recon/handlers/nufft.py +293 -0
  322. pulserver-0.0.2/src/pulserver/recon/handlers/nufft_train.py +34 -0
  323. pulserver-0.0.2/src/pulserver/recon/handlers/pics.py +258 -0
  324. pulserver-0.0.2/src/pulserver/recon/handlers/pics_train.py +37 -0
  325. pulserver-0.0.2/src/pulserver/recon/handlers/pmc.py +128 -0
  326. pulserver-0.0.2/src/pulserver/recon/plugin.py +1095 -0
  327. pulserver-0.0.2/src/pulserver/validate/__init__.py +15 -0
  328. pulserver-0.0.2/src/pulserver/validate/_command.py +105 -0
  329. pulserver-0.0.2/src/pulserver/validate/_compare.py +274 -0
  330. pulserver-0.0.2/src/pulserver/validate/_validate.py +270 -0
  331. pulserver-0.0.2/src/pulserver/validate/_xml.py +162 -0
  332. pulserver-0.0.2/src/pulserver/virtual/__init__.py +50 -0
  333. pulserver-0.0.2/src/pulserver/virtual/_brainweb.py +381 -0
  334. pulserver-0.0.2/src/pulserver/virtual/_client.py +171 -0
  335. pulserver-0.0.2/src/pulserver/virtual/_coils.py +334 -0
  336. pulserver-0.0.2/src/pulserver/virtual/_command.py +433 -0
  337. pulserver-0.0.2/src/pulserver/virtual/_console.py +761 -0
  338. pulserver-0.0.2/src/pulserver/virtual/_export.py +212 -0
  339. pulserver-0.0.2/src/pulserver/virtual/_fourier.py +1978 -0
  340. pulserver-0.0.2/src/pulserver/virtual/_girf.py +85 -0
  341. pulserver-0.0.2/src/pulserver/virtual/_localizer.py +100 -0
  342. pulserver-0.0.2/src/pulserver/virtual/_motion.py +191 -0
  343. pulserver-0.0.2/src/pulserver/virtual/_phantom.py +293 -0
  344. pulserver-0.0.2/src/pulserver/virtual/_stream.py +514 -0
  345. pulserver-0.0.2/src/pulserver/virtual/_timeline.py +899 -0
  346. pulserver-0.0.2/src/pulserver/virtual/_tissue.py +72 -0
  347. pulserver-0.0.2/tests/_analytic.py +259 -0
  348. pulserver-0.0.2/tests/_host.py +72 -0
  349. pulserver-0.0.2/tests/_seqtext.py +103 -0
  350. pulserver-0.0.2/tests/_synthetic.py +25 -0
  351. pulserver-0.0.2/tests/_virtual.py +139 -0
  352. pulserver-0.0.2/tests/_zoo.py +97 -0
  353. pulserver-0.0.2/tests/conftest.py +319 -0
  354. pulserver-0.0.2/tests/fixtures/bloch/bssfp.npy +0 -0
  355. pulserver-0.0.2/tests/fixtures/bloch/epi_2d_main.npy +0 -0
  356. pulserver-0.0.2/tests/fixtures/bloch/gre_2d_3sl.npy +0 -0
  357. pulserver-0.0.2/tests/fixtures/bloch/steady_dess_hard_0hz.npy +0 -0
  358. pulserver-0.0.2/tests/fixtures/bloch/steady_dess_hard_30hz.npy +0 -0
  359. pulserver-0.0.2/tests/fixtures/bloch/steady_echo_hard_0hz.npy +0 -0
  360. pulserver-0.0.2/tests/fixtures/bloch/steady_echo_hard_30hz.npy +0 -0
  361. pulserver-0.0.2/tests/fixtures/bloch/steady_echo_selective_0hz.npy +0 -0
  362. pulserver-0.0.2/tests/fixtures/bloch/steady_fid_hard_0hz.npy +0 -0
  363. pulserver-0.0.2/tests/fixtures/sequences/dedup_gre_pair.seq +1742 -0
  364. pulserver-0.0.2/tests/fixtures/sequences/dedup_gre_pair_b.seq +1741 -0
  365. pulserver-0.0.2/tests/fixtures/sequences/epi_2d_main.seq +5834 -0
  366. pulserver-0.0.2/tests/fixtures/sequences/gre_2d_3sl.seq +1974 -0
  367. pulserver-0.0.2/tests/fixtures/sequences/mprage_stack_of_spirals_3d.seq +14929 -0
  368. pulserver-0.0.2/tests/fixtures/sequences/zte_3d.seq +2161 -0
  369. pulserver-0.0.2/tests/koma/Project.toml +8 -0
  370. pulserver-0.0.2/tests/koma/simulate.jl +89 -0
  371. pulserver-0.0.2/tests/native/check_initializers.c +55 -0
  372. pulserver-0.0.2/tests/native/print_wave_samples.c +113 -0
  373. pulserver-0.0.2/tests/native/read_cache_summary.c +220 -0
  374. pulserver-0.0.2/tests/native/read_rf_definitions.c +57 -0
  375. pulserver-0.0.2/tests/native/replay_an_instance.c +113 -0
  376. pulserver-0.0.2/tests/plugins/crash.py +18 -0
  377. pulserver-0.0.2/tests/plugins/gre2d.py +53 -0
  378. pulserver-0.0.2/tests/plugins/gre2d_raw.py +15 -0
  379. pulserver-0.0.2/tests/plugins/rf_train.py +43 -0
  380. pulserver-0.0.2/tests/plugins/stall.py +21 -0
  381. pulserver-0.0.2/tests/plugins/strong.py +30 -0
  382. pulserver-0.0.2/tests/plugins/tiny.py +44 -0
  383. pulserver-0.0.2/tests/plugins/typed.py +80 -0
  384. pulserver-0.0.2/tests/recon/test_app.py +194 -0
  385. pulserver-0.0.2/tests/recon/test_buffers.py +1017 -0
  386. pulserver-0.0.2/tests/recon/test_calibration.py +515 -0
  387. pulserver-0.0.2/tests/recon/test_coil_compression.py +279 -0
  388. pulserver-0.0.2/tests/recon/test_connection.py +401 -0
  389. pulserver-0.0.2/tests/recon/test_correct.py +165 -0
  390. pulserver-0.0.2/tests/recon/test_epi.py +201 -0
  391. pulserver-0.0.2/tests/recon/test_exam_image.py +73 -0
  392. pulserver-0.0.2/tests/recon/test_flags.py +59 -0
  393. pulserver-0.0.2/tests/recon/test_gadgets.py +377 -0
  394. pulserver-0.0.2/tests/recon/test_handlers.py +178 -0
  395. pulserver-0.0.2/tests/recon/test_images.py +436 -0
  396. pulserver-0.0.2/tests/recon/test_loader.py +32 -0
  397. pulserver-0.0.2/tests/recon/test_mrd2dicom.py +907 -0
  398. pulserver-0.0.2/tests/recon/test_nufft.py +496 -0
  399. pulserver-0.0.2/tests/recon/test_pics.py +296 -0
  400. pulserver-0.0.2/tests/recon/test_pmc.py +91 -0
  401. pulserver-0.0.2/tests/recon/test_prewhiten.py +292 -0
  402. pulserver-0.0.2/tests/recon/test_readers_writers.py +182 -0
  403. pulserver-0.0.2/tests/recon/test_slots.py +52 -0
  404. pulserver-0.0.2/tests/recon/test_units.py +770 -0
  405. pulserver-0.0.2/tests/recon_plugins/children.py +22 -0
  406. pulserver-0.0.2/tests/recon_plugins/crash.py +19 -0
  407. pulserver-0.0.2/tests/recon_plugins/device.py +18 -0
  408. pulserver-0.0.2/tests/recon_plugins/exam.py +19 -0
  409. pulserver-0.0.2/tests/recon_plugins/gre2d.py +87 -0
  410. pulserver-0.0.2/tests/recon_plugins/pose.py +24 -0
  411. pulserver-0.0.2/tests/test_console.py +863 -0
  412. pulserver-0.0.2/tests/test_console_sequences.py +237 -0
  413. pulserver-0.0.2/tests/test_design_push.py +370 -0
  414. pulserver-0.0.2/tests/test_design_server.py +371 -0
  415. pulserver-0.0.2/tests/test_design_service.py +991 -0
  416. pulserver-0.0.2/tests/test_docs.py +124 -0
  417. pulserver-0.0.2/tests/test_docstring_defaults.py +166 -0
  418. pulserver-0.0.2/tests/test_docstrings.py +28 -0
  419. pulserver-0.0.2/tests/test_enrich.py +642 -0
  420. pulserver-0.0.2/tests/test_exam_artifacts.py +97 -0
  421. pulserver-0.0.2/tests/test_exam_calibration.py +86 -0
  422. pulserver-0.0.2/tests/test_exam_sharing.py +169 -0
  423. pulserver-0.0.2/tests/test_host_slots.py +117 -0
  424. pulserver-0.0.2/tests/test_image.py +70 -0
  425. pulserver-0.0.2/tests/test_ir.py +973 -0
  426. pulserver-0.0.2/tests/test_ir_checks.py +357 -0
  427. pulserver-0.0.2/tests/test_ir_designed.py +81 -0
  428. pulserver-0.0.2/tests/test_ir_extensions.py +137 -0
  429. pulserver-0.0.2/tests/test_ir_grouping.py +97 -0
  430. pulserver-0.0.2/tests/test_ir_groups.py +85 -0
  431. pulserver-0.0.2/tests/test_ir_labels.py +56 -0
  432. pulserver-0.0.2/tests/test_ir_playout.py +385 -0
  433. pulserver-0.0.2/tests/test_ir_profile.py +77 -0
  434. pulserver-0.0.2/tests/test_ir_repetition.py +188 -0
  435. pulserver-0.0.2/tests/test_ir_repetition_gradients.py +150 -0
  436. pulserver-0.0.2/tests/test_ir_rf.py +242 -0
  437. pulserver-0.0.2/tests/test_ir_segments.py +212 -0
  438. pulserver-0.0.2/tests/test_ir_source.py +233 -0
  439. pulserver-0.0.2/tests/test_ir_steady_excitation.py +153 -0
  440. pulserver-0.0.2/tests/test_ir_vendor.py +108 -0
  441. pulserver-0.0.2/tests/test_ir_waves.py +291 -0
  442. pulserver-0.0.2/tests/test_keys.py +177 -0
  443. pulserver-0.0.2/tests/test_koma.py +163 -0
  444. pulserver-0.0.2/tests/test_limits.py +419 -0
  445. pulserver-0.0.2/tests/test_logs.py +46 -0
  446. pulserver-0.0.2/tests/test_memory.py +27 -0
  447. pulserver-0.0.2/tests/test_motion.py +246 -0
  448. pulserver-0.0.2/tests/test_mrd_images.py +16 -0
  449. pulserver-0.0.2/tests/test_mrd_sequence.py +311 -0
  450. pulserver-0.0.2/tests/test_plugin_options.py +240 -0
  451. pulserver-0.0.2/tests/test_plugins.py +90 -0
  452. pulserver-0.0.2/tests/test_protocol.py +506 -0
  453. pulserver-0.0.2/tests/test_proxy.py +1319 -0
  454. pulserver-0.0.2/tests/test_publish_docs.py +114 -0
  455. pulserver-0.0.2/tests/test_resolution.py +245 -0
  456. pulserver-0.0.2/tests/test_rf_layout.py +771 -0
  457. pulserver-0.0.2/tests/test_scan_command.py +294 -0
  458. pulserver-0.0.2/tests/test_seqdesc.py +231 -0
  459. pulserver-0.0.2/tests/test_sequence_plugin.py +459 -0
  460. pulserver-0.0.2/tests/test_smoke.py +14 -0
  461. pulserver-0.0.2/tests/test_validate.py +314 -0
  462. pulserver-0.0.2/tests/test_virtual.py +653 -0
  463. pulserver-0.0.2/tests/test_virtual_brainweb.py +224 -0
  464. pulserver-0.0.2/tests/test_virtual_clock.py +205 -0
  465. pulserver-0.0.2/tests/test_virtual_coils.py +275 -0
  466. pulserver-0.0.2/tests/test_virtual_export.py +239 -0
  467. pulserver-0.0.2/tests/test_virtual_fourier.py +721 -0
  468. pulserver-0.0.2/tests/test_virtual_localizer.py +143 -0
  469. pulserver-0.0.2/tests/test_virtual_sequences.py +84 -0
  470. pulserver-0.0.2/tests/test_wire.py +111 -0
  471. pulserver-0.0.2/tests/test_zoo_evaluation.py +1245 -0
  472. pulserver-0.0.2/tests/test_zoo_wave.py +101 -0
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: build-and-test
3
+ description: Build pulserver from this checkout and run its formatter, linter, test suite and documentation build. Use before reporting any change complete, and whenever a test result or a skip has to be quoted rather than assumed.
4
+ ---
5
+
6
+ # Build and test
7
+
8
+ The extension `pulserver._ext` is compiled from `src/cpp/` and `src/c/`, so a
9
+ checkout has to be installed before anything imports `pulserver`. Run the whole
10
+ sequence and report the results it actually produced.
11
+
12
+ ```bash
13
+ pip install -e '.[dev,doc]'
14
+ bash scripts/format_and_lint.sh --check
15
+ pytest -q -ra
16
+ bash scripts/build_docs.sh
17
+ ```
18
+
19
+ `scripts/format_and_lint.sh` runs `ruff format` and `ruff check`; without
20
+ `--check` it rewrites the files instead of reporting them. It is the entry point
21
+ pre-commit and CI use, so a style failure in CI is reproducible here.
22
+
23
+ ## Interpreting the run
24
+
25
+ - The install needs a C compiler, a C++17 compiler and CMake. `src/c/` is
26
+ compiled with `-std=c90 -pedantic-errors`: a C99 construct is a build error,
27
+ not a warning to silence.
28
+ - `tests/test_ir.py` compiles `src/c/` as a 32-bit scanner build and skips
29
+ without a 32-bit toolchain (`gcc-multilib`). Report that skip; it is not a
30
+ pass.
31
+ - The CUDA leg of the `device` fixture skips without a device.
32
+ - The scanner-sequence plugins under `tests/plugins/` bind arguments of the
33
+ installed pypulseqpp's sequence functions. A failure naming an argument the
34
+ function does not take means the plugin and the installed pypulseqpp
35
+ disagree; check `pip show pypulseqpp` against the floor in `pyproject.toml`
36
+ before changing either.
37
+ - `tests/test_docs.py` runs the user-guide doctests and holds every public name
38
+ to its API page; a new public name needs a row there.
39
+
40
+ ## Documentation
41
+
42
+ Documentation changes are validated by the documentation build and
43
+ `tests/test_docs.py`, not by reading the source. See the `write-documentation`
44
+ skill.
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: write-documentation
3
+ description: Write, move or audit pulserver documentation — docstrings, user-guide, explanation, API and developer-guide pages, and the README. Use before creating or substantially modifying any documentation, and when deciding which documentation type a piece of material belongs to.
4
+ ---
5
+
6
+ # Write documentation
7
+
8
+ Two documents govern documentation and both are binding. Read them before
9
+ writing:
10
+
11
+ - `docs/developer-guide/documentation.md` — what belongs in each form of
12
+ documentation and how each is written.
13
+ - `docs/developer-guide/terminology.md` — terminology, register, units,
14
+ frames, safety language and source-of-truth rules.
15
+
16
+ The `Docstrings` and `Comments` sections of `AGENTS.md` govern docstrings and
17
+ comments.
18
+
19
+ ## Choose the type first
20
+
21
+ | Location | Type | Answers |
22
+ |---|---|---|
23
+ | `docs/user-guide/` | How-to | How do I install, run and extend pulserver? |
24
+ | `docs/explanations/` | Conceptual explanation, one flat list in data-flow order | Why does it work this way? |
25
+ | `gallery/01-course/` | Course lessons, read in order | What does a new user need to work independently? |
26
+ | `gallery/02-tours/` | Tours: applications, advanced branches, specialised workflows | What does a representative workflow look like? |
27
+ | `docs/api/` | Reference, from the docstrings | What exactly does this object do? |
28
+ | `docs/developer-guide/` | Contributor procedure | How is this repository developed? |
29
+ | `docs/developer-guide/internals/` | Implementation design | How is it built, and what does a playout rely on? |
30
+ | `README.md` | Project summary and documentation landing page | What is this, and where is the rest? |
31
+
32
+ Material in the wrong type is moved, not deleted. Implementation design found
33
+ on an explanation page — file layouts, memory budgets, tolerances, test
34
+ inventories — moves to `docs/developer-guide/internals/`, and the explanation
35
+ links to it.
36
+
37
+ A lesson belongs in the course only if it is on the shortest coherent path
38
+ that gives a new user the framework's core mental model and enough practical
39
+ competence to work independently; anything else is a Tour. A lesson has an
40
+ introduction, a *Learning objectives* list and previous/next lines; a Tour
41
+ opens with its objective and a prerequisites line and has neither.
42
+
43
+ The IR is written in PulSeg's terms — base block, virtual segment, segment
44
+ instance, execution stream — and *repetition* is the period
45
+ `pypulseqpp.Sequence.repetition()` reports. Never "repeating unit", never
46
+ "app" for a sequence function (`terminology.md`).
47
+
48
+ ## Verify before writing
49
+
50
+ State nothing the code does not do. Read the implementation, its callers and
51
+ its tests, and the C or C++ behind it when there is any. For the file formats
52
+ and wire protocols, the authorities are the code in `src/pulserver/protocol/`,
53
+ `src/c/include/pulseg/` and `src/pulserver/recon/_runtime/`. Flag a discrepancy
54
+ you cannot resolve rather than guessing.
55
+
56
+ ## Mechanics
57
+
58
+ - A runnable example on a user-guide page is a `pycon` block with `>>>`
59
+ prompts, ending with a blank line before the closing fence; it is executed
60
+ by `tests/test_docs.py`. An example that needs a running service or a data
61
+ file is a plain `python` block.
62
+ - An API page lists its subpackage's public names in `| Object | Description |`
63
+ tables of `{obj}` links under a `currentmodule` directive.
64
+ `docs/api_objects.py` writes the per-object stubs from those tables into
65
+ `docs/generated/`, which is not tracked.
66
+ - An explanation page ends with a `## See also` list linking the how-to and
67
+ the API pages it relates to. One with more than one `##` section opens with
68
+ a TL;DR admonition, ```` ```{admonition} TL;DR ```` and `:class: tldr`,
69
+ directly under its title; no landing, API or example page has one.
70
+ - A figure takes its style from `docs/figure_style.py`; a script sets no font
71
+ size, DPI or colour literal and imports the colours it needs. A static
72
+ figure is a light/dark SVG pair written by `scripts/make_artwork.py` and
73
+ shown with `only-light` and `only-dark`.
74
+ - A new page is added to the table and the hidden toctree of its section's
75
+ `index.md`.
76
+ - A new gallery script goes into its section's directory under `gallery/`,
77
+ named with a numeric prefix, and gets a row and a toctree entry on the
78
+ section's landing page under `docs/examples/` (`course.md` or `tours.md`). A new section is a directory
79
+ with `README.rst` and `_gallery_header.md`, an entry in `GALLERY_SECTIONS`,
80
+ and a landing page listed in `docs/examples/index.md`.
81
+
82
+ ## Validate
83
+
84
+ ```bash
85
+ pytest -q tests/test_docs.py tests/test_docstrings.py tests/test_docstring_defaults.py
86
+ bash scripts/build_docs.sh
87
+ ```
88
+
89
+ Open `docs/build/html/index.html` and check the rendered pages in the light
90
+ and the dark theme, and the sidebar: User guide, Developer guide, Explanations,
91
+ Examples (Course, then Tours), API, Misc.
@@ -0,0 +1,11 @@
1
+ # The image is built from the sources alone; its version is pretended.
2
+ .git
3
+ **/__pycache__
4
+ .pytest_cache
5
+ .ruff_cache
6
+ .coverage
7
+ build
8
+ dist
9
+ wheelhouse
10
+ docs/build
11
+ docs/generated
@@ -0,0 +1,16 @@
1
+ * text=auto eol=lf
2
+
3
+ *.png binary
4
+ *.jpg binary
5
+ *.svg text
6
+ *.npy binary
7
+ *.npz binary
8
+ *.mat binary
9
+ *.h5 binary
10
+ *.dcm binary
11
+ # The IR cache a sequence is converted to.
12
+ *.pseg binary
13
+
14
+ # Sequence files written by pypulseqpp for the tests: collapsed in diffs and
15
+ # left out of the language statistics.
16
+ tests/fixtures/** linguist-generated=true
@@ -0,0 +1,43 @@
1
+ name: Bug report
2
+ description: Report reproducible incorrect behaviour or a documentation defect.
3
+ labels: ["bug"]
4
+ body:
5
+ - type: dropdown
6
+ id: subsystem
7
+ attributes:
8
+ label: Affected area
9
+ options:
10
+ - "Scanner sequences (pulserver.design, pulserver.protocol)"
11
+ - "Design calls and the design store (pulserver.host)"
12
+ - "IR conversion or the C cache library (pulserver.ir, src/c)"
13
+ - "Reconstruction proxy and enrichment (pulserver.proxy)"
14
+ - "Reconstruction plugins and MRD data (pulserver.recon, pulserver.mrd)"
15
+ - "Documentation"
16
+ - "Other"
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: observed
21
+ attributes:
22
+ label: Observed and expected behaviour
23
+ validations:
24
+ required: true
25
+ - type: textarea
26
+ id: reproduce
27
+ attributes:
28
+ label: Smallest reproducer
29
+ description: >
30
+ Self-contained Python code, a plugin file, a minimal `.seq` file, or the
31
+ design call and its reply. Prefer synthetic data to a scanner
32
+ acquisition.
33
+ render: python
34
+ validations:
35
+ required: true
36
+ - type: textarea
37
+ id: environment
38
+ attributes:
39
+ label: Environment
40
+ description: pulserver, pypulseqpp and Python versions, plus OS and architecture.
41
+ placeholder: "pulserver 0.x; pypulseqpp 0.x; Python 3.12; Ubuntu 24.04 x86-64"
42
+ validations:
43
+ 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/pulserver/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/pulserver/security/advisories/new
8
+ about: Report privately. Please do not open a public issue.
@@ -0,0 +1,36 @@
1
+ name: Feature request
2
+ description: Propose a narrowly scoped addition to pulserver.
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: use-case
7
+ attributes:
8
+ label: Scientific or technical use case
9
+ description: State the missing capability and the acquisition or reconstruction workflow it serves.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: Proposed interface or behaviour
16
+ description: Include primary literature, a vendor or MRD convention, or an existing implementation where relevant.
17
+ validations:
18
+ required: true
19
+ - type: dropdown
20
+ id: layer
21
+ attributes:
22
+ label: Where it belongs
23
+ description: >
24
+ Sequence design belongs to pypulseqpp and reconstruction algorithms to
25
+ bartorch; pulserver holds the orchestration between them and the scanner.
26
+ options:
27
+ - "pulserver"
28
+ - "pypulseqpp (sequence design)"
29
+ - "bartorch (reconstruction)"
30
+ - "Not sure"
31
+ validations:
32
+ required: true
33
+ - type: textarea
34
+ id: alternatives
35
+ attributes:
36
+ label: Alternatives considered
@@ -0,0 +1,15 @@
1
+ ## What changed
2
+
3
+ <!-- Concise implementation summary. -->
4
+
5
+ ## Why
6
+
7
+ <!-- Problem and relevant issue or discussion. -->
8
+
9
+ ## Validation
10
+
11
+ <!-- Exact commands and results. Include tests added for new behaviour. -->
12
+
13
+ ## Documentation impact
14
+
15
+ <!-- User-facing changes, or "None" with a reason. -->
@@ -0,0 +1,40 @@
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
+ target-branch: main
8
+ schedule:
9
+ interval: weekly
10
+ day: monday
11
+ labels: ["dependencies", "ci"]
12
+ commit-message:
13
+ prefix: "ci"
14
+ groups:
15
+ actions:
16
+ patterns: ["*"]
17
+
18
+ - package-ecosystem: pip
19
+ directory: "/"
20
+ target-branch: main
21
+ schedule:
22
+ interval: weekly
23
+ day: monday
24
+ open-pull-requests-limit: 5
25
+ labels: ["dependencies", "python"]
26
+ commit-message:
27
+ prefix: "deps"
28
+ groups:
29
+ # The sequence engine's signatures are what the scanner plugins bind to,
30
+ # so its bumps arrive alone and get a full run of their own.
31
+ engine:
32
+ patterns: ["pypulseqpp"]
33
+ mr-data:
34
+ patterns: ["numpy", "ismrmrd", "pydicom"]
35
+ build:
36
+ patterns: ["scikit-build-core", "pybind11", "setuptools_scm"]
37
+ dev-tooling:
38
+ patterns: ["pytest*", "coverage", "ruff", "pre-commit", "build"]
39
+ docs:
40
+ patterns: ["sphinx*", "myst-parser", "linkify-it-py", "matplotlib"]
@@ -0,0 +1,36 @@
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 ${{ matrix.language }}
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
+ strategy:
24
+ fail-fast: false
25
+ matrix:
26
+ # c-cpp covers src/c, the library a scanner links, and src/cpp.
27
+ language: [python, c-cpp]
28
+ steps:
29
+ - uses: actions/checkout@v7
30
+ - uses: github/codeql-action/init@v4
31
+ with:
32
+ languages: ${{ matrix.language }}
33
+ build-mode: none
34
+ - uses: github/codeql-action/analyze@v4
35
+ with:
36
+ category: "/language:${{ matrix.language }}"
@@ -0,0 +1,39 @@
1
+ # The console of the virtual scanner with Gadgetron behind pulserver's proxy,
2
+ # composed from docker/ and driven through one exam and one scan.
3
+ name: Console
4
+
5
+ on:
6
+ workflow_dispatch:
7
+ pull_request:
8
+ paths:
9
+ - docker/**
10
+ - src/pulserver/virtual/_console.py
11
+ - src/pulserver/proxy/**
12
+ - .github/workflows/console.yml
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ compose:
19
+ runs-on: ubuntu-latest
20
+ timeout-minutes: 60
21
+ steps:
22
+ - uses: actions/checkout@v7
23
+ with:
24
+ fetch-depth: 0
25
+ - uses: actions/setup-python@v7
26
+ with:
27
+ python-version: "3.12"
28
+ - name: Start the console, the proxy and Gadgetron
29
+ run: docker compose -f docker/compose.yaml up -d --build
30
+ - name: Scan through the console
31
+ run: |
32
+ pip install websockets pydicom numpy
33
+ python docker/smoke.py ws://127.0.0.1:8765
34
+ - name: Logs
35
+ if: always()
36
+ run: docker compose -f docker/compose.yaml logs --no-color
37
+ - name: Stop
38
+ if: always()
39
+ run: docker compose -f docker/compose.yaml down -v
@@ -0,0 +1,133 @@
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.
7
+ #
8
+ # A pull request builds only when a maintainer comments `/build-docs` on it,
9
+ # and the build answers on the pull request with its result. That build
10
+ # publishes nothing; main publishes after the merge.
11
+ #
12
+ # The branch is the site's archive. GitHub Pages can be deployed from an
13
+ # artifact instead, but a deployment replaces the whole site, so publishing one
14
+ # version would drop the others.
15
+
16
+ on:
17
+ push:
18
+ branches: [main]
19
+ tags: ["v[0-9]+.[0-9]+.[0-9]+"]
20
+ issue_comment:
21
+ types: [created]
22
+ workflow_dispatch:
23
+
24
+ permissions:
25
+ contents: read
26
+
27
+ # Every publish commits to the same branch, so main, the tags and a manual run
28
+ # share one group and wait for each other rather than racing to push. A pull
29
+ # request publishes nothing and gets a group of its own.
30
+ concurrency:
31
+ group: docs-${{ github.event.issue.number || 'publish' }}
32
+ cancel-in-progress: ${{ github.event_name == 'issue_comment' }}
33
+
34
+ jobs:
35
+ docs:
36
+ if: >-
37
+ github.event_name != 'issue_comment' ||
38
+ (github.event.issue.pull_request &&
39
+ startsWith(github.event.comment.body, '/build-docs') &&
40
+ contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association))
41
+ runs-on: ubuntu-latest
42
+ permissions:
43
+ contents: write # the publish step pushes the built site to gh-pages
44
+ pull-requests: write # a requested build answers on its pull request
45
+ steps:
46
+ - uses: actions/checkout@v7
47
+ with:
48
+ # A comment runs on the default branch; the build is of the pull
49
+ # request's head.
50
+ ref: ${{ github.event_name == 'issue_comment' && format('refs/pull/{0}/head', github.event.issue.number) || '' }}
51
+ fetch-depth: 0 # setuptools_scm reads the tags
52
+
53
+ - uses: actions/setup-python@v7
54
+ with:
55
+ python-version: "3.12"
56
+ cache: pip
57
+
58
+ - name: Name this version
59
+ id: version
60
+ # A release is built as `stable`, the URL a reader should land on, and
61
+ # archived under its tag as well; the canonical link in both copies
62
+ # points at `stable`.
63
+ run: |
64
+ if [ "$GITHUB_REF_TYPE" = tag ]; then
65
+ echo "dir=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
66
+ echo "canonical=stable" >> "$GITHUB_OUTPUT"
67
+ else
68
+ echo "dir=latest" >> "$GITHUB_OUTPUT"
69
+ echo "canonical=latest" >> "$GITHUB_OUTPUT"
70
+ fi
71
+
72
+ # autodoc imports the package, so the compiled extension is built too.
73
+ # The gallery reconstructs with the shipped pics plugin, on bartorch
74
+ # over torch's CPU build.
75
+ - name: Install
76
+ run: |
77
+ python -m pip install --upgrade pip
78
+ python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
79
+ python -m pip install '.[doc]'
80
+
81
+ - name: Build
82
+ env:
83
+ PULSERVER_DOCS_VERSION: ${{ steps.version.outputs.canonical }}
84
+ PULSERVER_DOCS_RELEASE: ${{ steps.version.outputs.dir }}
85
+ run: bash scripts/build_docs.sh
86
+
87
+ - name: Check that the site is only the site
88
+ # Sphinx caches parsed documents in the output directory unless given
89
+ # `-d`, and the cache is far larger than the pages. Publishing commits
90
+ # whatever is there to a branch that is never pruned.
91
+ run: |
92
+ if [ -e docs/build/html/.doctrees ]; then
93
+ echo "::error::The doctree cache is inside the built site and would be published." >&2
94
+ exit 1
95
+ fi
96
+
97
+ - name: Publish
98
+ if: >-
99
+ github.event_name != 'issue_comment' &&
100
+ (github.ref == 'refs/heads/main' || github.ref_type == 'tag')
101
+ env:
102
+ DIR: ${{ steps.version.outputs.dir }}
103
+ GH_TOKEN: ${{ github.token }}
104
+ run: |
105
+ site="$RUNNER_TEMP/pages"
106
+ remote="https://x-access-token:$GH_TOKEN@github.com/$GITHUB_REPOSITORY"
107
+ # The branch does not exist before the first publish.
108
+ if ! git clone --depth 1 --branch gh-pages "$remote" "$site"; then
109
+ git init -b gh-pages "$site"
110
+ git -C "$site" remote add origin "$remote"
111
+ fi
112
+
113
+ # Only this version's directory is replaced; a release refreshes
114
+ # stable only when it is the newest, and the root and the switcher's
115
+ # list are rewritten from what the site then holds.
116
+ python scripts/publish_docs.py docs/build/html "$DIR" "$site"
117
+
118
+ git -C "$site" add -A
119
+ git -C "$site" -c user.name='github-actions[bot]' \
120
+ -c user.email='41898282+github-actions[bot]@users.noreply.github.com' \
121
+ commit -m "Documentation for $DIR from $GITHUB_SHA" \
122
+ || { echo "No documentation change to publish."; exit 0; }
123
+ git -C "$site" push origin gh-pages
124
+
125
+ - name: Answer on the pull request
126
+ if: always() && github.event_name == 'issue_comment'
127
+ env:
128
+ GH_TOKEN: ${{ github.token }}
129
+ RESULT: ${{ job.status }}
130
+ RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
131
+ run: |
132
+ gh pr comment ${{ github.event.issue.number }} --repo "$GITHUB_REPOSITORY" \
133
+ --body "Documentation build: $RESULT ($RUN)"
@@ -0,0 +1,72 @@
1
+ # BrainWeb's head in the virtual scanner's coils: each coil's transmit and
2
+ # receive maps and the transmit coils' VOPs, solved by mariepy's
3
+ # examples/brainweb.py and published as an image that holds only those files,
4
+ # which docker/Dockerfile copies in by digest. mariepy runs here as a program;
5
+ # none of its code enters pulserver or its image.
6
+ name: Fields
7
+
8
+ on:
9
+ workflow_dispatch:
10
+ inputs:
11
+ mariepy:
12
+ description: mariepy commit the fields are solved with
13
+ required: true
14
+ resolution:
15
+ description: Voxel pitch of the head, in mm
16
+ required: false
17
+ default: "5"
18
+
19
+ permissions:
20
+ contents: read
21
+ packages: write
22
+
23
+ jobs:
24
+ solve:
25
+ runs-on: ubuntu-latest
26
+ timeout-minutes: 360
27
+ env:
28
+ RESOLUTION: ${{ inputs.resolution }}
29
+ steps:
30
+ - uses: actions/checkout@v7
31
+ with:
32
+ repository: pulserver/mariepy
33
+ ref: ${{ inputs.mariepy }}
34
+ fetch-depth: 0 # setuptools_scm reads the version from the history
35
+
36
+ - uses: actions/setup-python@v7
37
+ with:
38
+ python-version: "3.12"
39
+
40
+ - name: Install mariepy
41
+ run: |
42
+ python -m pip install --upgrade pip
43
+ python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
44
+ python -m pip install . brainweb-dl scipy
45
+
46
+ - name: Solve
47
+ run: python examples/brainweb.py --out fields --resolution "$RESOLUTION"
48
+
49
+ - name: Record what solved them
50
+ env:
51
+ RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
52
+ run: >-
53
+ printf '{"mariepy": "%s", "resolution_mm": %d, "run": "%s"}\n'
54
+ "$(git rev-parse HEAD)" "$RESOLUTION" "$RUN" > fields/provenance.json
55
+
56
+ - uses: actions/upload-artifact@v7
57
+ with:
58
+ name: brainweb-fields
59
+ path: fields
60
+
61
+ - name: Publish
62
+ env:
63
+ TOKEN: ${{ secrets.GITHUB_TOKEN }}
64
+ ACTOR: ${{ github.actor }}
65
+ run: |
66
+ image="ghcr.io/pulserver/brainweb-fields:$(git rev-parse --short HEAD)-${RESOLUTION}mm"
67
+ echo "$TOKEN" | docker login ghcr.io -u "$ACTOR" --password-stdin
68
+ printf '%s\n' 'FROM scratch' \
69
+ 'LABEL org.opencontainers.image.source=https://github.com/pulserver/pulserver' \
70
+ 'COPY . /' | docker build -t "$image" -f - fields
71
+ docker push "$image"
72
+ echo "Published $(docker inspect --format '{{index .RepoDigests 0}}' "$image")" >> "$GITHUB_STEP_SUMMARY"
@@ -0,0 +1,57 @@
1
+ # pulserver's image, whose default command is the console of the virtual
2
+ # scanner reconstructing in its own process: built with the coils' field maps,
3
+ # scanned through on the BrainWeb brain it carries, which loads without a
4
+ # network, in the head coils' maps, and published from main.
5
+ name: Image
6
+
7
+ on:
8
+ push:
9
+ branches: [main]
10
+ pull_request:
11
+ paths:
12
+ - docker/**
13
+ - src/**
14
+ - tests/plugins/gre2d.py
15
+ - pyproject.toml
16
+ - CMakeLists.txt
17
+ - .dockerignore
18
+ - .github/workflows/image.yml
19
+ workflow_dispatch:
20
+
21
+ permissions:
22
+ contents: read
23
+ packages: write
24
+
25
+ jobs:
26
+ image:
27
+ runs-on: ubuntu-latest
28
+ timeout-minutes: 60
29
+ steps:
30
+ - uses: actions/checkout@v7
31
+ - uses: actions/setup-python@v7
32
+ with:
33
+ python-version: "3.12"
34
+ - name: Build
35
+ run: docker build -f docker/Dockerfile -t pulserver .
36
+ - name: Scan through its console
37
+ run: |
38
+ docker run -d --name console -p 127.0.0.1:8765:8765 pulserver
39
+ pip install websockets pydicom numpy
40
+ python docker/smoke.py ws://127.0.0.1:8765 head8/head32
41
+ - name: Load BrainWeb without a network
42
+ run: >-
43
+ docker run --rm --network none --entrypoint python pulserver -c
44
+ "from pulserver.virtual import BrainWeb; print(BrainWeb().fractions.shape)"
45
+ - name: Give its console options after the image's name
46
+ run: docker run --rm pulserver --help | grep -e --spacing
47
+ - name: Publish
48
+ if: github.event_name == 'push'
49
+ run: |
50
+ echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
51
+ for tag in latest "${{ github.sha }}"; do
52
+ docker tag pulserver "ghcr.io/pulserver/pulserver:$tag"
53
+ docker push "ghcr.io/pulserver/pulserver:$tag"
54
+ done
55
+ - name: Logs
56
+ if: always()
57
+ run: docker logs console