pulserver 0.4.4__tar.gz → 0.4.5__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 (461) hide show
  1. {pulserver-0.4.4 → pulserver-0.4.5}/.github/workflows/fields.yml +26 -5
  2. {pulserver-0.4.4 → pulserver-0.4.5}/PKG-INFO +5 -2
  3. {pulserver-0.4.4 → pulserver-0.4.5}/docker/Dockerfile +6 -10
  4. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api/proxy.md +2 -1
  5. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/internals/index.md +1 -1
  6. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/internals/ir-cache.md +15 -1
  7. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/internals/protocol-wire.md +7 -3
  8. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/internals/reconstruction-proxy.md +3 -1
  9. {pulserver-0.4.4 → pulserver-0.4.5}/docs/explanations/raw-data.md +3 -0
  10. {pulserver-0.4.4 → pulserver-0.4.5}/docs/explanations/reconstruction-session.md +3 -3
  11. {pulserver-0.4.4 → pulserver-0.4.5}/docs/explanations/scanner-representation.md +5 -3
  12. {pulserver-0.4.4 → pulserver-0.4.5}/docs/user-guide/reconstruction-client.md +14 -4
  13. {pulserver-0.4.4 → pulserver-0.4.5}/docs/user-guide/running.md +24 -7
  14. {pulserver-0.4.4 → pulserver-0.4.5}/docs/user-guide/scanner-sequences.md +2 -2
  15. {pulserver-0.4.4 → pulserver-0.4.5}/pyproject.toml +4 -1
  16. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/core/pulseg_error.c +0 -6
  17. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseg/pulseg_collection.h +18 -8
  18. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseg/pulseg_errors.h +0 -1
  19. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/structure/pulseg_getters.c +55 -33
  20. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/structure.cpp +3 -22
  21. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/module.cpp +7 -4
  22. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/_evaluation.py +19 -6
  23. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/bssfp2d.py +24 -6
  24. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/fse3d.py +8 -2
  25. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/gre2d.py +1 -1
  26. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/se2d.py +1 -1
  27. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/zte3d.py +9 -3
  28. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/host/_command.py +1 -1
  29. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/host/_limits.py +40 -2
  30. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/host/_service.py +18 -9
  31. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/__init__.py +2 -0
  32. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/__main__.py +36 -0
  33. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/_enrich.py +37 -4
  34. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/_held.py +34 -4
  35. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/_proxy.py +33 -11
  36. pulserver-0.4.5/src/pulserver/proxy/_receiver.py +97 -0
  37. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_runtime/mrd2dicom.py +58 -35
  38. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/handlers/nufft.py +16 -3
  39. {pulserver-0.4.4 → pulserver-0.4.5}/tests/native/read_cache_summary.c +4 -4
  40. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_mrd2dicom.py +59 -11
  41. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_nufft.py +28 -0
  42. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_console_sequences.py +15 -3
  43. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_enrich.py +23 -0
  44. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir.py +38 -1
  45. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_repetition.py +8 -6
  46. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_rf.py +28 -0
  47. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_timing.py +46 -21
  48. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_limits.py +33 -0
  49. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_protocol.py +21 -1
  50. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_proxy.py +102 -4
  51. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_scan_command.py +9 -1
  52. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_virtual.py +21 -5
  53. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_virtual_coils.py +8 -5
  54. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_zoo_evaluation.py +29 -10
  55. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_zoo_wave.py +10 -5
  56. {pulserver-0.4.4 → pulserver-0.4.5}/.claude/skills/build-and-test/SKILL.md +0 -0
  57. {pulserver-0.4.4 → pulserver-0.4.5}/.claude/skills/write-documentation/SKILL.md +0 -0
  58. {pulserver-0.4.4 → pulserver-0.4.5}/.dockerignore +0 -0
  59. {pulserver-0.4.4 → pulserver-0.4.5}/.gitattributes +0 -0
  60. {pulserver-0.4.4 → pulserver-0.4.5}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
  61. {pulserver-0.4.4 → pulserver-0.4.5}/.github/DISCUSSION_TEMPLATE/q-a.yml +0 -0
  62. {pulserver-0.4.4 → pulserver-0.4.5}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  63. {pulserver-0.4.4 → pulserver-0.4.5}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  64. {pulserver-0.4.4 → pulserver-0.4.5}/.github/ISSUE_TEMPLATE/documentation.yml +0 -0
  65. {pulserver-0.4.4 → pulserver-0.4.5}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  66. {pulserver-0.4.4 → pulserver-0.4.5}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  67. {pulserver-0.4.4 → pulserver-0.4.5}/.github/dependabot.yml +0 -0
  68. {pulserver-0.4.4 → pulserver-0.4.5}/.github/workflows/codeql.yml +0 -0
  69. {pulserver-0.4.4 → pulserver-0.4.5}/.github/workflows/console.yml +0 -0
  70. {pulserver-0.4.4 → pulserver-0.4.5}/.github/workflows/docs.yml +0 -0
  71. {pulserver-0.4.4 → pulserver-0.4.5}/.github/workflows/image.yml +0 -0
  72. {pulserver-0.4.4 → pulserver-0.4.5}/.github/workflows/koma.yml +0 -0
  73. {pulserver-0.4.4 → pulserver-0.4.5}/.github/workflows/style.yml +0 -0
  74. {pulserver-0.4.4 → pulserver-0.4.5}/.github/workflows/tags-release.yml +0 -0
  75. {pulserver-0.4.4 → pulserver-0.4.5}/.github/workflows/test-ci.yml +0 -0
  76. {pulserver-0.4.4 → pulserver-0.4.5}/.github/workflows/wheels.yml +0 -0
  77. {pulserver-0.4.4 → pulserver-0.4.5}/.gitignore +0 -0
  78. {pulserver-0.4.4 → pulserver-0.4.5}/.pre-commit-config.yaml +0 -0
  79. {pulserver-0.4.4 → pulserver-0.4.5}/AGENTS.md +0 -0
  80. {pulserver-0.4.4 → pulserver-0.4.5}/CMakeLists.txt +0 -0
  81. {pulserver-0.4.4 → pulserver-0.4.5}/CODE_OF_CONDUCT.md +0 -0
  82. {pulserver-0.4.4 → pulserver-0.4.5}/CONTRIBUTING.md +0 -0
  83. {pulserver-0.4.4 → pulserver-0.4.5}/LICENSE +0 -0
  84. {pulserver-0.4.4 → pulserver-0.4.5}/LICENSES/gadgetron-python-MIT.txt +0 -0
  85. {pulserver-0.4.4 → pulserver-0.4.5}/LICENSES/python-ismrmrd-server-MIT.txt +0 -0
  86. {pulserver-0.4.4 → pulserver-0.4.5}/NEXT.md +0 -0
  87. {pulserver-0.4.4 → pulserver-0.4.5}/README.md +0 -0
  88. {pulserver-0.4.4 → pulserver-0.4.5}/SECURITY.md +0 -0
  89. {pulserver-0.4.4 → pulserver-0.4.5}/SKILLS.md +0 -0
  90. {pulserver-0.4.4 → pulserver-0.4.5}/codecov.yml +0 -0
  91. {pulserver-0.4.4 → pulserver-0.4.5}/docker/compose.yaml +0 -0
  92. {pulserver-0.4.4 → pulserver-0.4.5}/docker/entrypoint.sh +0 -0
  93. {pulserver-0.4.4 → pulserver-0.4.5}/docker/limits/limits.txt +0 -0
  94. {pulserver-0.4.4 → pulserver-0.4.5}/docker/smoke.py +0 -0
  95. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/architecture-dark.svg +0 -0
  96. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/architecture.svg +0 -0
  97. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/capabilities.js +0 -0
  98. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/context-dark.svg +0 -0
  99. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/context.svg +0 -0
  100. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/pulseg-dark.svg +0 -0
  101. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/pulseg.svg +0 -0
  102. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/pulserver-logo-dark.svg +0 -0
  103. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/pulserver-logo.svg +0 -0
  104. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/pulserver-mark-dark.svg +0 -0
  105. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/pulserver-mark.svg +0 -0
  106. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/pulserver.css +0 -0
  107. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/repetition-dark.svg +0 -0
  108. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/repetition.svg +0 -0
  109. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/safety-dark.svg +0 -0
  110. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/safety.svg +0 -0
  111. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/session-dark.svg +0 -0
  112. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/session.svg +0 -0
  113. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/virtual-dark.svg +0 -0
  114. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_static/virtual.svg +0 -0
  115. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_templates/autosummary/base.rst +0 -0
  116. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_templates/autosummary/class.rst +0 -0
  117. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_templates/autosummary/enum.rst +0 -0
  118. {pulserver-0.4.4 → pulserver-0.4.5}/docs/_templates/autosummary/function.rst +0 -0
  119. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api/design.md +0 -0
  120. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api/host.md +0 -0
  121. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api/index.md +0 -0
  122. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api/ir.md +0 -0
  123. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api/mrd.md +0 -0
  124. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api/protocol.md +0 -0
  125. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api/recon.md +0 -0
  126. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api/validate.md +0 -0
  127. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api/virtual.md +0 -0
  128. {pulserver-0.4.4 → pulserver-0.4.5}/docs/api_objects.py +0 -0
  129. {pulserver-0.4.4 → pulserver-0.4.5}/docs/colab.py +0 -0
  130. {pulserver-0.4.4 → pulserver-0.4.5}/docs/conf.py +0 -0
  131. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/documentation.md +0 -0
  132. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/index.md +0 -0
  133. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/installation.md +0 -0
  134. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/internals/calibration.md +0 -0
  135. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/internals/sar-ratios.md +0 -0
  136. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/internals/virtual-scanner.md +0 -0
  137. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/releases.md +0 -0
  138. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/style.md +0 -0
  139. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/terminology.md +0 -0
  140. {pulserver-0.4.4 → pulserver-0.4.5}/docs/developer-guide/workflow.md +0 -0
  141. {pulserver-0.4.4 → pulserver-0.4.5}/docs/examples/course.md +0 -0
  142. {pulserver-0.4.4 → pulserver-0.4.5}/docs/examples/index.md +0 -0
  143. {pulserver-0.4.4 → pulserver-0.4.5}/docs/examples/tours.md +0 -0
  144. {pulserver-0.4.4 → pulserver-0.4.5}/docs/explanations/architecture.md +0 -0
  145. {pulserver-0.4.4 → pulserver-0.4.5}/docs/explanations/index.md +0 -0
  146. {pulserver-0.4.4 → pulserver-0.4.5}/docs/explanations/protocol.md +0 -0
  147. {pulserver-0.4.4 → pulserver-0.4.5}/docs/explanations/reconstruction.md +0 -0
  148. {pulserver-0.4.4 → pulserver-0.4.5}/docs/explanations/safety-checks.md +0 -0
  149. {pulserver-0.4.4 → pulserver-0.4.5}/docs/explanations/virtual-scanner.md +0 -0
  150. {pulserver-0.4.4 → pulserver-0.4.5}/docs/figure_style.py +0 -0
  151. {pulserver-0.4.4 → pulserver-0.4.5}/docs/index.md +0 -0
  152. {pulserver-0.4.4 → pulserver-0.4.5}/docs/misc/contributors.md +0 -0
  153. {pulserver-0.4.4 → pulserver-0.4.5}/docs/misc/index.md +0 -0
  154. {pulserver-0.4.4 → pulserver-0.4.5}/docs/misc/license.md +0 -0
  155. {pulserver-0.4.4 → pulserver-0.4.5}/docs/misc/related.md +0 -0
  156. {pulserver-0.4.4 → pulserver-0.4.5}/docs/user-guide/index.md +0 -0
  157. {pulserver-0.4.4 → pulserver-0.4.5}/docs/user-guide/reconstruction-plugins.md +0 -0
  158. {pulserver-0.4.4 → pulserver-0.4.5}/docs/user-guide/virtual-scanner.md +0 -0
  159. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/01-course/01_protocol_to_image.py +0 -0
  160. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/01-course/02_sequence_plugin.py +0 -0
  161. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/01-course/03_scanner_representation.py +0 -0
  162. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/01-course/04_reconstruction_plugin.py +0 -0
  163. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/01-course/05_recon_plugin.py +0 -0
  164. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/01-course/06_testing_on_the_virtual_scanner.py +0 -0
  165. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/01-course/README.rst +0 -0
  166. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/01-course/_gallery_header.md +0 -0
  167. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/02-tours/01_protocol_resolution.py +0 -0
  168. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/02-tours/02_segmentation.py +0 -0
  169. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/02-tours/03_fov_offset_enrichment.py +0 -0
  170. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/02-tours/README.rst +0 -0
  171. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/02-tours/_gallery_header.md +0 -0
  172. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/README.rst +0 -0
  173. {pulserver-0.4.4 → pulserver-0.4.5}/gallery/_gallery_header.md +0 -0
  174. {pulserver-0.4.4 → pulserver-0.4.5}/scripts/build_docs.sh +0 -0
  175. {pulserver-0.4.4 → pulserver-0.4.5}/scripts/check_throughput.py +0 -0
  176. {pulserver-0.4.4 → pulserver-0.4.5}/scripts/format_and_lint.sh +0 -0
  177. {pulserver-0.4.4 → pulserver-0.4.5}/scripts/make_artwork.py +0 -0
  178. {pulserver-0.4.4 → pulserver-0.4.5}/scripts/publish_docs.py +0 -0
  179. {pulserver-0.4.4 → pulserver-0.4.5}/setup.py +0 -0
  180. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/CMakeLists.txt +0 -0
  181. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/cache/pulseg_cache.c +0 -0
  182. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/core/pulseg_core.c +0 -0
  183. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/core/pulseg_math.c +0 -0
  184. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseg/pulseg.h +0 -0
  185. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseg/pulseg_cache.h +0 -0
  186. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseg/pulseg_config.h +0 -0
  187. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseg/pulseg_io.h +0 -0
  188. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseg/pulseg_playout.h +0 -0
  189. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseg/pulseg_protocol.h +0 -0
  190. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseg/pulseg_types.h +0 -0
  191. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseq/pulseq.h +0 -0
  192. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseq/pulseq_config.h +0 -0
  193. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/include/pulseq/pulseq_types.h +0 -0
  194. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/io/pulseg_opts.c +0 -0
  195. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/io/pulseg_protocol.c +0 -0
  196. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/playout/pulseg_playout.c +0 -0
  197. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/pulseg_internal.h +0 -0
  198. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/pulseq/pulseq_internal.h +0 -0
  199. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/pulseq/pulseq_shape.c +0 -0
  200. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/structure/pulseg_descriptor.c +0 -0
  201. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/structure/pulseg_repetition.c +0 -0
  202. {pulserver-0.4.4 → pulserver-0.4.5}/src/c/structure/pulseg_waves.c +0 -0
  203. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/fourier/bindings.cpp +0 -0
  204. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/fourier/bindings.hpp +0 -0
  205. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/fourier/parallel.hpp +0 -0
  206. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/fourier/timeline.cpp +0 -0
  207. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/fourier/timeline.hpp +0 -0
  208. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/collection.cpp +0 -0
  209. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/dedup.cpp +0 -0
  210. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/from_libraries.cpp +0 -0
  211. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/from_libraries.hpp +0 -0
  212. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/gradient_stretch.cpp +0 -0
  213. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/pulseg_convert.h +0 -0
  214. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/pulseq_file.cpp +0 -0
  215. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/pulseq_file.h +0 -0
  216. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/wave_plan.cpp +0 -0
  217. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/ir/waves.cpp +0 -0
  218. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/native.hpp +0 -0
  219. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/playout.cpp +0 -0
  220. {pulserver-0.4.4 → pulserver-0.4.5}/src/cpp/playout.hpp +0 -0
  221. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/__init__.py +0 -0
  222. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_accelerators.py +0 -0
  223. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_cli.py +0 -0
  224. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_labels.py +0 -0
  225. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_logs.py +0 -0
  226. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_memory.py +0 -0
  227. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_plugins.py +0 -0
  228. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/__init__.py +0 -0
  229. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/_inversion.py +0 -0
  230. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/_pmc.py +0 -0
  231. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/_saturation.py +0 -0
  232. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/_slab.py +0 -0
  233. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/_user.py +0 -0
  234. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/recon/epi.py +0 -0
  235. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/recon/nufft.py +0 -0
  236. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/recon/nufft_train.py +0 -0
  237. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/recon/pics.py +0 -0
  238. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/recon/pics_train.py +0 -0
  239. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/recon/pmc.py +0 -0
  240. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/bssfp3d.py +0 -0
  241. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/epi2d.py +0 -0
  242. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/epi3d.py +0 -0
  243. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/gre3d.py +0 -0
  244. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/gre_multiecho2d.py +0 -0
  245. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/gre_multiecho3d.py +0 -0
  246. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/gre_propeller2d.py +0 -0
  247. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/gre_radial2d.py +0 -0
  248. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/gre_spiral2d.py +0 -0
  249. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/gre_stack_of_blades3d.py +0 -0
  250. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/gre_stack_of_spirals3d.py +0 -0
  251. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/gre_stack_of_stars3d.py +0 -0
  252. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/mprage3d.py +0 -0
  253. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/mprage_stack_of_spirals3d.py +0 -0
  254. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/mprage_stack_of_stars3d.py +0 -0
  255. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/se3d.py +0 -0
  256. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/se_epi_propeller2d.py +0 -0
  257. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/se_propeller2d.py +0 -0
  258. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/se_radial2d.py +0 -0
  259. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/se_spiral2d.py +0 -0
  260. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/se_stack_of_blades3d.py +0 -0
  261. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/se_stack_of_spirals3d.py +0 -0
  262. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/_zoo/sequences/se_stack_of_stars3d.py +0 -0
  263. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/design/__init__.py +0 -0
  264. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/design/_entries.py +0 -0
  265. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/design/_options.py +0 -0
  266. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/design/_plugin.py +0 -0
  267. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/design/_rf.py +0 -0
  268. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/host/__init__.py +0 -0
  269. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/host/__main__.py +0 -0
  270. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/host/_blocks.py +0 -0
  271. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/host/_push.py +0 -0
  272. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/host/_server.py +0 -0
  273. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/host/_store.py +0 -0
  274. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/ir/__init__.py +0 -0
  275. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/ir/_checks.py +0 -0
  276. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/ir/_convert.py +0 -0
  277. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/ir/_playout.py +0 -0
  278. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/ir/_source.py +0 -0
  279. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/ir/_vendor.py +0 -0
  280. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/ir/_waves.py +0 -0
  281. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/mrd/__init__.py +0 -0
  282. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/mrd/_acquisitions.py +0 -0
  283. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/mrd/_header.py +0 -0
  284. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/mrd/_images.py +0 -0
  285. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/mrd/_metadata.py +0 -0
  286. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/mrd/_sequence.py +0 -0
  287. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/protocol/__init__.py +0 -0
  288. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/protocol/_keys.py +0 -0
  289. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/protocol/_prescription.py +0 -0
  290. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/protocol/_schema.py +0 -0
  291. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/protocol/_wire.py +0 -0
  292. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/_designs.py +0 -0
  293. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/_intake.py +0 -0
  294. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/_local.py +0 -0
  295. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/_motion.py +0 -0
  296. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/_queue.py +0 -0
  297. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/_seqdesc.py +0 -0
  298. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/proxy/_workers.py +0 -0
  299. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/__init__.py +0 -0
  300. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/__main__.py +0 -0
  301. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_buffers.py +0 -0
  302. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_calibration.py +0 -0
  303. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_correct.py +0 -0
  304. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_exam_image.py +0 -0
  305. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_figure.py +0 -0
  306. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_loader.py +0 -0
  307. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_replay.py +0 -0
  308. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_runtime/__init__.py +0 -0
  309. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_runtime/application.py +0 -0
  310. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_runtime/concurrency.py +0 -0
  311. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_runtime/connection.py +0 -0
  312. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_runtime/constants.py +0 -0
  313. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_runtime/exam.py +0 -0
  314. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_runtime/offline.py +0 -0
  315. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_runtime/readers.py +0 -0
  316. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_runtime/writers.py +0 -0
  317. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/_units.py +0 -0
  318. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/gadgets.py +0 -0
  319. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/handlers/__init__.py +0 -0
  320. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/handlers/epi.py +0 -0
  321. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/handlers/nufft_train.py +0 -0
  322. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/handlers/pics.py +0 -0
  323. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/handlers/pics_train.py +0 -0
  324. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/handlers/pmc.py +0 -0
  325. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/recon/plugin.py +0 -0
  326. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/validate/__init__.py +0 -0
  327. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/validate/_command.py +0 -0
  328. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/validate/_compare.py +0 -0
  329. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/validate/_validate.py +0 -0
  330. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/validate/_xml.py +0 -0
  331. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/__init__.py +0 -0
  332. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_brainweb.py +0 -0
  333. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_client.py +0 -0
  334. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_coils.py +0 -0
  335. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_command.py +0 -0
  336. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_console.py +0 -0
  337. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_export.py +0 -0
  338. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_fourier.py +0 -0
  339. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_girf.py +0 -0
  340. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_localizer.py +0 -0
  341. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_motion.py +0 -0
  342. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_phantom.py +0 -0
  343. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_stream.py +0 -0
  344. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_timeline.py +0 -0
  345. {pulserver-0.4.4 → pulserver-0.4.5}/src/pulserver/virtual/_tissue.py +0 -0
  346. {pulserver-0.4.4 → pulserver-0.4.5}/tests/_analytic.py +0 -0
  347. {pulserver-0.4.4 → pulserver-0.4.5}/tests/_host.py +0 -0
  348. {pulserver-0.4.4 → pulserver-0.4.5}/tests/_seqtext.py +0 -0
  349. {pulserver-0.4.4 → pulserver-0.4.5}/tests/_synthetic.py +0 -0
  350. {pulserver-0.4.4 → pulserver-0.4.5}/tests/_virtual.py +0 -0
  351. {pulserver-0.4.4 → pulserver-0.4.5}/tests/_zoo.py +0 -0
  352. {pulserver-0.4.4 → pulserver-0.4.5}/tests/conftest.py +0 -0
  353. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/bloch/bssfp.npy +0 -0
  354. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/bloch/epi_2d_main.npy +0 -0
  355. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/bloch/gre_2d_3sl.npy +0 -0
  356. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/bloch/steady_dess_hard_0hz.npy +0 -0
  357. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/bloch/steady_dess_hard_30hz.npy +0 -0
  358. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/bloch/steady_echo_hard_0hz.npy +0 -0
  359. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/bloch/steady_echo_hard_30hz.npy +0 -0
  360. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/bloch/steady_echo_selective_0hz.npy +0 -0
  361. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/bloch/steady_fid_hard_0hz.npy +0 -0
  362. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/sequences/dedup_gre_pair.seq +0 -0
  363. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/sequences/dedup_gre_pair_b.seq +0 -0
  364. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/sequences/epi_2d_main.seq +0 -0
  365. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/sequences/gre_2d_3sl.seq +0 -0
  366. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/sequences/mprage_stack_of_spirals_3d.seq +0 -0
  367. {pulserver-0.4.4 → pulserver-0.4.5}/tests/fixtures/sequences/zte_3d.seq +0 -0
  368. {pulserver-0.4.4 → pulserver-0.4.5}/tests/koma/Project.toml +0 -0
  369. {pulserver-0.4.4 → pulserver-0.4.5}/tests/koma/simulate.jl +0 -0
  370. {pulserver-0.4.4 → pulserver-0.4.5}/tests/native/check_initializers.c +0 -0
  371. {pulserver-0.4.4 → pulserver-0.4.5}/tests/native/print_wave_samples.c +0 -0
  372. {pulserver-0.4.4 → pulserver-0.4.5}/tests/native/read_rf_definitions.c +0 -0
  373. {pulserver-0.4.4 → pulserver-0.4.5}/tests/native/read_rf_timing.c +0 -0
  374. {pulserver-0.4.4 → pulserver-0.4.5}/tests/native/replay_an_instance.c +0 -0
  375. {pulserver-0.4.4 → pulserver-0.4.5}/tests/plugins/crash.py +0 -0
  376. {pulserver-0.4.4 → pulserver-0.4.5}/tests/plugins/gre2d.py +0 -0
  377. {pulserver-0.4.4 → pulserver-0.4.5}/tests/plugins/gre2d_raw.py +0 -0
  378. {pulserver-0.4.4 → pulserver-0.4.5}/tests/plugins/rf_train.py +0 -0
  379. {pulserver-0.4.4 → pulserver-0.4.5}/tests/plugins/stall.py +0 -0
  380. {pulserver-0.4.4 → pulserver-0.4.5}/tests/plugins/strong.py +0 -0
  381. {pulserver-0.4.4 → pulserver-0.4.5}/tests/plugins/tiny.py +0 -0
  382. {pulserver-0.4.4 → pulserver-0.4.5}/tests/plugins/typed.py +0 -0
  383. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_app.py +0 -0
  384. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_buffers.py +0 -0
  385. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_calibration.py +0 -0
  386. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_coil_compression.py +0 -0
  387. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_connection.py +0 -0
  388. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_correct.py +0 -0
  389. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_epi.py +0 -0
  390. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_exam_image.py +0 -0
  391. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_flags.py +0 -0
  392. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_gadgets.py +0 -0
  393. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_handlers.py +0 -0
  394. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_images.py +0 -0
  395. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_loader.py +0 -0
  396. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_pics.py +0 -0
  397. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_pmc.py +0 -0
  398. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_prewhiten.py +0 -0
  399. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_readers_writers.py +0 -0
  400. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_slots.py +0 -0
  401. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon/test_units.py +0 -0
  402. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon_plugins/children.py +0 -0
  403. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon_plugins/crash.py +0 -0
  404. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon_plugins/device.py +0 -0
  405. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon_plugins/exam.py +0 -0
  406. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon_plugins/gre2d.py +0 -0
  407. {pulserver-0.4.4 → pulserver-0.4.5}/tests/recon_plugins/pose.py +0 -0
  408. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_console.py +0 -0
  409. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_design_push.py +0 -0
  410. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_design_server.py +0 -0
  411. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_design_service.py +0 -0
  412. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_docs.py +0 -0
  413. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_docstring_defaults.py +0 -0
  414. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_docstrings.py +0 -0
  415. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_exam_artifacts.py +0 -0
  416. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_exam_calibration.py +0 -0
  417. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_exam_sharing.py +0 -0
  418. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_host_slots.py +0 -0
  419. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_image.py +0 -0
  420. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_checks.py +0 -0
  421. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_designed.py +0 -0
  422. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_extensions.py +0 -0
  423. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_gradient_stretch.py +0 -0
  424. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_grouping.py +0 -0
  425. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_labels.py +0 -0
  426. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_playout.py +0 -0
  427. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_prescan.py +0 -0
  428. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_prescan_tour.py +0 -0
  429. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_profile.py +0 -0
  430. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_rf_freq.py +0 -0
  431. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_segments.py +0 -0
  432. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_source.py +0 -0
  433. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_steady_excitation.py +0 -0
  434. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_vendor.py +0 -0
  435. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_ir_waves.py +0 -0
  436. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_keys.py +0 -0
  437. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_koma.py +0 -0
  438. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_logs.py +0 -0
  439. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_memory.py +0 -0
  440. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_motion.py +0 -0
  441. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_mrd_images.py +0 -0
  442. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_mrd_sequence.py +0 -0
  443. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_plugin_options.py +0 -0
  444. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_plugins.py +0 -0
  445. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_publish_docs.py +0 -0
  446. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_resolution.py +0 -0
  447. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_rf_layout.py +0 -0
  448. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_seqdesc.py +0 -0
  449. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_sequence_plugin.py +0 -0
  450. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_smoke.py +0 -0
  451. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_validate.py +0 -0
  452. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_virtual_brainweb.py +0 -0
  453. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_virtual_clock.py +0 -0
  454. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_virtual_export.py +0 -0
  455. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_virtual_fourier.py +0 -0
  456. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_virtual_localizer.py +0 -0
  457. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_virtual_sequences.py +0 -0
  458. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_wire.py +0 -0
  459. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_zoo_defaults.py +0 -0
  460. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_zoo_fov_offset.py +0 -0
  461. {pulserver-0.4.4 → pulserver-0.4.5}/tests/test_zoo_mrd_labels.py +0 -0
@@ -1,8 +1,10 @@
1
1
  # BrainWeb's head in the virtual scanner's coils: each coil's transmit and
2
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.
3
+ # examples/brainweb.py, published with the normal brain they are solved in as
4
+ # an image that holds only those files, /fields and /brainweb, which
5
+ # docker/Dockerfile copies in by digest, so that no build of pulserver's image
6
+ # reaches BrainWeb's server. mariepy runs here as a program; none of its code
7
+ # enters pulserver or its image.
6
8
  name: Fields
7
9
 
8
10
  on:
@@ -43,8 +45,26 @@ jobs:
43
45
  python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
44
46
  python -m pip install . brainweb-dl scipy
45
47
 
48
+ # From BrainWeb's server, or, while it does not answer, from the
49
+ # pulserver image that already carries it; either way the same bytes.
50
+ - name: Fetch BrainWeb's normal brain
51
+ env:
52
+ PHANTOM: phantom_1.0mm_normal_fuzzy.nii.gz
53
+ SHA256: cb56eb3e684ddbea48f6146839d18402c742f3b0ffdfb24b3d8ae1e3fc47fc5d
54
+ MIRROR: ghcr.io/pulserver/pulserver@sha256:28a3c682d8ad281e8e3ffd871b03b9477a51c59c373e8a5c41d6f398d085d386
55
+ run: |
56
+ timeout 900 python -c "import brainweb_dl; brainweb_dl.get_mri(0, 'fuzzy', brainweb_dir='brainweb')" || {
57
+ rm -rf brainweb && mkdir brainweb
58
+ cid=$(docker create "$MIRROR")
59
+ docker cp "$cid:/opt/brainweb/$PHANTOM" brainweb/
60
+ docker rm "$cid"
61
+ }
62
+ echo "$SHA256 brainweb/$PHANTOM" | sha256sum -c
63
+
46
64
  - name: Solve
47
- run: python examples/brainweb.py --out fields --resolution "$RESOLUTION"
65
+ run: >-
66
+ python examples/brainweb.py --out fields --resolution "$RESOLUTION"
67
+ --brainweb-dir brainweb
48
68
 
49
69
  - name: Record what solved them
50
70
  env:
@@ -65,8 +85,9 @@ jobs:
65
85
  run: |
66
86
  image="ghcr.io/pulserver/brainweb-fields:$(git rev-parse --short HEAD)-${RESOLUTION}mm"
67
87
  echo "$TOKEN" | docker login ghcr.io -u "$ACTOR" --password-stdin
88
+ mkdir image && cp -r fields brainweb image/
68
89
  printf '%s\n' 'FROM scratch' \
69
90
  'LABEL org.opencontainers.image.source=https://github.com/pulserver/pulserver' \
70
- 'COPY . /' | docker build -t "$image" -f - fields
91
+ 'COPY . /' | docker build -t "$image" -f - image
71
92
  docker push "$image"
72
93
  echo "Published $(docker inspect --format '{{index .RepoDigests 0}}' "$image")" >> "$GITHUB_STEP_SUMMARY"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulserver
3
- Version: 0.4.4
3
+ Version: 0.4.5
4
4
  Summary: Orchestrator for MR acquisitions: sequence design, scanner preparation and reconstruction.
5
5
  Keywords: mri,pulseq,mrd,ismrmrd,reconstruction,scanner
6
6
  Author-Email: Matteo Cencini <matteo.cencini@gmail.com>
@@ -21,7 +21,7 @@ Project-URL: Documentation, https://pulserver.github.io/pulserver/
21
21
  Project-URL: Issues, https://github.com/pulserver/pulserver/issues
22
22
  Project-URL: Source, https://github.com/pulserver/pulserver
23
23
  Requires-Python: >=3.10
24
- Requires-Dist: pypulseqpp>=0.0.49
24
+ Requires-Dist: pypulseqpp>=0.0.51
25
25
  Requires-Dist: numpy>=2.2.6
26
26
  Requires-Dist: ismrmrd>=1.15.0
27
27
  Requires-Dist: pydicom>=3.0.2
@@ -30,7 +30,10 @@ Requires-Dist: blochsim>=0.0.12
30
30
  Requires-Dist: bartorch>=0.0.17
31
31
  Requires-Dist: brainweb-dl>=0.4.6
32
32
  Requires-Dist: websockets>=16.1.1
33
+ Provides-Extra: dicom
34
+ Requires-Dist: pynetdicom>=3.0; extra == "dicom"
33
35
  Provides-Extra: dev
36
+ Requires-Dist: pynetdicom>=3.0; extra == "dev"
34
37
  Requires-Dist: pytest>=9.1.1; extra == "dev"
35
38
  Requires-Dist: pytest-cov>=7.1.0; extra == "dev"
36
39
  Requires-Dist: pytest-xdist>=3; extra == "dev"
@@ -38,17 +38,13 @@ RUN pip install --no-cache-dir "$(echo /wheels/pulserver-*.whl)" \
38
38
  # installed from PyPI, where its source is.
39
39
  RUN pip install --no-cache-dir "bartorch[pyhysco]"
40
40
 
41
- # BrainWeb's normal brain, downloaded while the image is built, so that no
42
- # exam reaches BrainWeb's server; brainweb-dl reads it from BRAINWEB_DIR.
41
+ # BrainWeb's normal brain, and the coils' field maps and VOPs that the Fields
42
+ # workflow solves in it with mariepy, which that workflow publishes as an image
43
+ # of those files alone, so that neither a build nor an exam reaches BrainWeb's
44
+ # server; brainweb-dl reads the brain from BRAINWEB_DIR.
43
45
  ENV BRAINWEB_DIR=/opt/brainweb
44
- RUN for attempt in 1 2 3; do \
45
- python -c "from pulserver.virtual import BrainWeb; BrainWeb().fractions" && break; \
46
- rm -rf "$BRAINWEB_DIR"; [ "$attempt" = 3 ] && exit 1; sleep 30; \
47
- done
48
-
49
- # The coils' field maps and VOPs, which the Fields workflow solves in the same
50
- # brain with mariepy and publishes as an image of those files alone.
51
- COPY --from=ghcr.io/pulserver/brainweb-fields@sha256:c102b4f2563e1a1a19ca25d9cd3b9b9d7505555041b4795310aee4725a659ddb / /console/fields/
46
+ COPY --from=ghcr.io/pulserver/brainweb-fields@sha256:b6ca42ee0d21e16fccb77fee165f15fa7b77dc2f6073ade0ff7000c902e3acb6 /brainweb/ /opt/brainweb/
47
+ COPY --from=ghcr.io/pulserver/brainweb-fields@sha256:b6ca42ee0d21e16fccb77fee165f15fa7b77dc2f6073ade0ff7000c902e3acb6 /fields/ /console/fields/
52
48
 
53
49
  # The limits the console's sequences design under.
54
50
  COPY docker/limits/limits.txt /console/limits.txt
@@ -11,7 +11,7 @@ and runs it on a reconstruction worker.
11
11
  The proxy listens on a TCP port and is started with
12
12
 
13
13
  ```bash
14
- pulserver proxy --store DIR --port N --plugins DIR [--intake-port N] [--slots N] [--spares 1] [--save-data DIR] [--idle-timeout S]
14
+ pulserver proxy --store DIR --port N --plugins DIR [--intake-port N] [--slots N] [--spares 1] [--dicom-receiver HOST:PORT --dicom-receiver-title AE] [--save-data DIR] [--idle-timeout S]
15
15
  pulserver proxy --store DIR --port N --forward HOST:PORT [--forward-config NAME] [--dicom]
16
16
  ```
17
17
 
@@ -35,6 +35,7 @@ and fields of a series in {doc}`../user-guide/reconstruction-client`.
35
35
  | --- | --- |
36
36
  | {obj}`~pulserver.proxy.ReconProxy` | TCP MRD server enriching each series and routing it to a reconstruction worker or server. |
37
37
  | {obj}`~pulserver.proxy.ReconServer` | TCP MRD server reconstructing each series with the plugin its config names. |
38
+ | {obj}`~pulserver.proxy.DicomReceiver` | DICOM storage service the images of a series whose client has gone are stored to. |
38
39
  | {obj}`~pulserver.proxy.LocalReconstruction` | Each series checked, enriched and reconstructed in the calling process, as the proxy's workers do, for a host that starts no processes. |
39
40
 
40
41
  ## Designs
@@ -7,7 +7,7 @@ authors.
7
7
  | Page | Contents |
8
8
  | --- | --- |
9
9
  | {doc}`calibration` | Prewhitening, coil compression, sensitivity maps and the reuse of stored maps |
10
- | {doc}`ir-cache` | Conversion passes, waves, playout stages, the gradient stretches, the cache file and the C89 library |
10
+ | {doc}`ir-cache` | Conversion passes, waves, playout stages, the gradient stretches, the RF averaging span, the cache file and the C89 library |
11
11
  | {doc}`protocol-wire` | RF layout, protocol keys and values, and the protocol text blocks |
12
12
  | {doc}`reconstruction-proxy` | Reconstruction units, image headers, enrichment and trajectory rules, readout placement and workers |
13
13
  | {doc}`sar-ratios` | pTx SAR ratios from VOPs against a reference pulse |
@@ -48,7 +48,7 @@ and two designs ({doc}`../../explanations/architecture`).
48
48
  | Pass | Result |
49
49
  | --- | --- |
50
50
  | Event deduplication | A library of distinct RF, gradient and ADC definitions, and a per-block instance table recording the definition each block plays and its amplitude |
51
- | Repetition | The repetition of each subsequence and its repetition time (TR): the period pypulseqpp's `Sequence.repetition` finds, from the first block; a subsequence that does not repeat is one repetition, refused when it is longer than 15 s |
51
+ | Repetition | The repetition of each subsequence and its repetition time (TR): the period pypulseqpp's `Sequence.repetition` finds, from the first block; a subsequence that does not repeat is one repetition, however long |
52
52
  | Segmentation | The repetition divided into virtual segments at block boundaries the {class}`~pulserver.ir.Grouping` admits |
53
53
  | Execution stream | The segment instances of the whole scan, in play order |
54
54
  | Label table | The Pulseq labels in force at every readout, three of which fill the ADC label columns |
@@ -292,6 +292,20 @@ axes and linear in between; the prescription's rotation takes them to the
292
292
  physical axes, and a model that needs them on a raster samples them at the
293
293
  centres of its intervals (`pulseg_sample_corner_points`).
294
294
 
295
+ ## RF averaging span
296
+
297
+ A scanner holds SAR and its RF amplifier to averages over windows, such as
298
+ 10 s and 6 min. `pulseg_get_rf_window` gives the span of a subsequence a
299
+ window is costed over, and the plays of each pulse of the repetition in it,
300
+ each play at its block's start and weighed by the energy the caller gives its
301
+ pulse. The span is costed over its own duration.
302
+
303
+ | Subsequence | Span |
304
+ |---|---|
305
+ | Its hyper-repetition repeats and is shorter than the window | One hyper-repetition from the start, which plays at the subsequence's mean power; a window-long span would add up to one repetition's energy at its edges. Weighed by `pulseg_get_rf_array`, which takes each pulse at the worst repetition instance, the repetition of largest $\sum A^2 P$, every repetition in it plays as that instance |
306
+ | No longer than the window | The whole subsequence |
307
+ | Otherwise | Of the window-long spans starting at a play or ending at the subsequence's end, the one of most energy, the earliest on a tie; plays are costed by count, so unlike a gradient stretch it is not widened to whole segment instances |
308
+
295
309
  ## Cache file
296
310
 
297
311
  The cache has the name of the first sequence file with its extension replaced,
@@ -45,7 +45,11 @@ sequence the evaluation builds, in the order of first play. The listing carries
45
45
  the definitions of the evaluation at the default protocol, and a layout names
46
46
  the pulses of the listing only where the protocol does not change which pulses
47
47
  are played first: the length of a train, a flip angle schedule and the matrix do
48
- not, and a protocol that adds a preparation pulse does.
48
+ not, and a protocol that adds a preparation pulse does. Explicit saturation
49
+ bands are the exception a console needs, since it places them without listing
50
+ again: the listing's evaluation places every band the plugin offers, and the
51
+ shipped plugins number the band pulse after the others, so a band placed or
52
+ removed changes no other number.
49
53
 
50
54
  The layout is an estimate for the prescription. An evaluation that states none
51
55
  states no estimate and is valid, and what the scanner checks before the scan is
@@ -115,8 +119,8 @@ where the evaluation is invalid or states no layout. They are lists of numbers:
115
119
  each number is ASCII decimal with nine significant digits, the numbers of a list
116
120
  are separated by single spaces, and each list is one line, so that a reader
117
121
  takes tokens. `[RfDefinitions]` follows the listing of a `list` call asked with
118
- `rf_definitions`, which evaluates the plugin at its default protocol under the
119
- scanner limits. Each definition is a `definition` line, then the sample times,
122
+ `rf_definitions`, which evaluates the plugin at its default protocol, with
123
+ every explicit saturation band it offers placed, under the scanner limits. Each definition is a `definition` line, then the sample times,
120
124
  then the real and the imaginary parts of each channel:
121
125
 
122
126
  ```text
@@ -252,7 +252,9 @@ is applied to the stream as follows.
252
252
  on the flat top of its readout gradient alone. In a stack of slices, its
253
253
  position, the field-of-view centre the client sends, is moved along
254
254
  `slice_dir` by the `SlicePositions` entry its `SLC` indexes, to the centre of
255
- its slice. When the client numbers its
255
+ its slice, and by half a voxel along each axis of even matrix size, its
256
+ samples given the phase of the same shift, so that the reconstruction grid
257
+ is centred on the field of view (`SequenceTable.grid_offset_m`). When the client numbers its
256
258
  acquisitions, each `scan_counter` must follow the previous one by one; a gap
257
259
  or a repeat stops the series before it is reconstructed, since every later
258
260
  row would be shifted.
@@ -44,6 +44,9 @@ before and after.
44
44
  - **Applies the field-of-view phase the scanner's offsets cannot, and any later position change in the header.**
45
45
 
46
46
  Code: {mod}`pulserver.proxy`. Tests: *a curving readout carries the phase its receiver cannot apply*; *a steady readout needs no curve*; *a stated position away from the converted shift adds its whole phase* (`test_enrich.py`).
47
+ - **Centres the reconstruction grid on the field of view, voxel centres symmetric about the prescribed centre.**
48
+
49
+ Code: `SequenceTable.grid_offset_m`. Tests: *the reconstruction grid is centred half a voxel from an fft one* (`test_enrich.py`); *a point off the centre reconstructs where it was acquired* (`test_proxy.py`).
47
50
  - **Writes TR, TE, TI and flip angles into the header, measuring the ones the sequence does not define.**
48
51
 
49
52
  Code: {mod}`pulserver.mrd`. Tests: *te and tr a sequence does not define are the ones pypulseqpp measures*; *the header lists every flip angle the sequence plays* (`test_mrd_sequence.py`, `test_enrich.py`).
@@ -56,10 +56,10 @@ on the other end refuses a series it cannot serve, enriches it from its design
56
56
  Code: `pulserver.proxy._motion`. Tests: *a motion corrected series publishes its poses to the scan*; *a series not corrected for motion writes no pose file* (`test_proxy.py`).
57
57
  - **Keeps each series enriched, for an offline rerun that gives the same image.**
58
58
 
59
- Code: `--save-data`. Tests: *a kept series runs offline and gives the image the proxy returned*; *what a proxy keeps is the series it reconstructed, enriched*; *a kept series given its design is not enriched twice* (`test_proxy.py`).
60
- - **Holds images for a client that dropped, and closes on its own when idle.**
59
+ Code: `--save-data`. Tests: *a kept series runs offline and gives the image the proxy returned*; *what a proxy keeps is the series it reconstructed, enriched*; *a kept series given its design is not enriched twice*; *a kept series takes its name only once its stream has ended* (`test_proxy.py`).
60
+ - **Holds images for a client that dropped, or stores them to a DICOM receiver, and closes on its own when idle.**
61
61
 
62
- Code: `--idle-timeout`. Tests: *images whose client has gone reach it when it returns*; *the idle timeout counts from the last client leaving* (`test_proxy.py`).
62
+ Code: `--idle-timeout`, `--dicom-receiver`. Tests: *images whose client has gone reach it when it returns*; *the images of a series whose client has gone reach the dicom receiver*; *a series the dicom receiver does not take is held for its client*; *the idle timeout counts from the last client leaving* (`test_proxy.py`).
63
63
 
64
64
  :::
65
65
 
@@ -25,9 +25,9 @@ its segments.
25
25
  - **Takes the repetition pypulseqpp reports, and segments within it.**
26
26
 
27
27
  Code: `src/cpp/ir/structure.cpp`. Tests: *the ir segments the repetition pypulseqpp finds*; *a hyper tr declared as pypulseqpp writes it is the repeating unit* (`test_ir_repetition.py`).
28
- - **Treats a sequence that does not repeat as one repetition, and refuses one longer than 15 s.**
28
+ - **Treats a sequence that does not repeat as one repetition, however long it plays.**
29
29
 
30
- Code: `SINGLE_TR_MAX_DURATION_US`. Tests: *a sequence that does not repeat is one repetition*; *a sequence that does not repeat is refused past 15 s* (`test_ir_repetition.py`).
30
+ Code: `src/cpp/ir/structure.cpp`. Tests: *a sequence that does not repeat is one repetition*; *a sequence that does not repeat is one repetition however long it plays* (`test_ir_repetition.py`); *a repetition past a 32 bit count of microseconds reads the same in the scanner reader* (`test_ir.py`).
31
31
  - **Cuts virtual segments only where every gradient is near zero, under a tunable grouping.**
32
32
 
33
33
  Code: {class}`~pulserver.ir.Grouping`. Tests: *the default grouping is what a conversion does unasked*; *a grouping moves the boundaries and not the gradient* (`test_ir_grouping.py`); *a gradient its file ends live may not end the repetition* (`test_ir.py`).
@@ -98,7 +98,9 @@ at the first block and is the first of these that applies:
98
98
  3. The shortest period dividing the sequence over which blocks match in
99
99
  duration and in the channels they play, so that shots with their own
100
100
  pulses or gradient shapes still repeat.
101
- 4. Otherwise the whole file is one repetition, refused above 15 s.
101
+ 4. Otherwise the whole file is one repetition, however long. Nothing holds a
102
+ repetition's samples: the timing and RF costing walk its blocks and plays,
103
+ and gradient heating is costed over stretches of at most `PULSEG_STRETCH_US`.
102
104
 
103
105
  A slice played with its own preparation and dummy shots is therefore one
104
106
  repetition, and a block played once makes the whole file one. The segment IDs
@@ -86,8 +86,8 @@ of the image it is written into; `{{` and `}}` are literal braces:
86
86
  | Name | Value |
87
87
  | --- | --- |
88
88
  | `slice_location` | The image centre along the plane normal, in mm: the `SliceLocation` written by default |
89
- | `location` | The image centre along the patient axis the normal lies closest to, in mm, positive towards right, anterior or superior; for an oblique plane, along the normal turned towards those |
90
- | `location_letter` | The side `location` lies on: `R` or `L`, `A` or `P`, `S` or `I`, and `+` or `-` for an oblique plane |
89
+ | `location` | The image centre's coordinate on the patient axis the normal lies closest to, in mm, positive towards right, anterior or superior; an oblique plane is located on that axis too |
90
+ | `location_letter` | The side `location` lies on: `R` or `L`, `A` or `P`, `S` or `I` |
91
91
  | `instance_number`, `series_number` | The image's `InstanceNumber` and `SeriesNumber` |
92
92
 
93
93
  An attribute that resolves to no tag, for want of the dictionary, is logged and
@@ -103,15 +103,25 @@ noise scans and navigators included, and no other.
103
103
  | Field | Client | Proxy |
104
104
  | --- | --- | --- |
105
105
  | `number_of_samples` | The sample count of the readout's ADC event | Checked |
106
- | `active_channels`, data | The samples, demodulated by each ADC's frequency and phase offsets | Multiplied by the phase a field-of-view offset adds to a readout under a moving gradient, and by any phase modulation the sequence file stores |
106
+ | `active_channels`, data | The samples, demodulated by each ADC's frequency and phase offsets | Multiplied by the phase a field-of-view offset adds to a readout under a moving gradient, by the phase that centres the reconstruction grid (below), and by any phase modulation the sequence file stores |
107
107
  | `scan_counter` | 0 on every acquisition, or increasing by one from any start | Checked |
108
108
  | `flags` | None, or `LAST_IN_MEASUREMENT` on the last acquisition | Replaced |
109
109
  | `idx`, `sample_time_us`, `encoding_space_ref` | Any value | Replaced |
110
110
  | `center_sample` | Any value | Replaced, except on a readout whose k-space location does not change |
111
111
  | `trajectory_dimensions`, `traj` | Any value | Replaced on a readout whose k-space location changes, in 1/m along the sequence's gradient axes |
112
- | `position` | The prescribed field-of-view centre, in mm from isocentre | Moved along `slice_dir` to the centre of the readout's slice, for a stack of 2D slices whose sequence defines `SlicePositions`; an image takes it from its reference acquisition |
112
+ | `position` | The prescribed field-of-view centre, in mm from isocentre | Moved along `slice_dir` to the centre of the readout's slice, for a stack of 2D slices whose sequence defines `SlicePositions`, and by half a voxel along each axis of even matrix size (below); an image takes it from its reference acquisition |
113
113
  | `measurement_uid`, `read_dir`, `phase_dir`, `slice_dir`, `patient_table_position`, `acquisition_time_stamp`, `physiology_time_stamp`, `user_int`, `user_float` | The scanner's values, as MRD defines them | Passed on unchanged; an image takes them from its reference acquisition |
114
114
 
115
+ The reconstruction grid is centred on the field of view: the voxel centres of
116
+ an axis of `n` voxels lie symmetrically about the prescribed centre, at
117
+ `(i - (n - 1) / 2)` voxels from it. An FFT puts the centre on voxel `n // 2`
118
+ instead, half a voxel off along an axis of even `n`, so each acquisition's
119
+ `position` is moved by `FOV / (2 n)` along each such axis of its encoding
120
+ space's matrix, and its samples are given the phase of the same shift of the
121
+ field of view. Voxel `n // 2` of the reconstruction, which MRD's `position`
122
+ locates, then lies half a voxel past the prescribed centre, and the content
123
+ moves with it.
124
+
115
125
  A series is refused, and its reconstruction stopped, when an acquisition has a
116
126
  sample count other than its readout's, when the scan counters skip or repeat
117
127
  one, when an acquisition before the last is flagged `LAST_IN_MEASUREMENT`,
@@ -50,8 +50,9 @@ in {doc}`../explanations/protocol`.
50
50
 
51
51
  The RF blocks are sent only when asked for, and only where the plugin's
52
52
  evaluation states an RF layout ({ref}`stating-the-rf-layout`).
53
- `--rf-definitions` evaluates the plugin at its default protocol under
54
- `--limits`, which it then requires. `--rf-layout` follows a valid reply with the
53
+ `--rf-definitions` evaluates the plugin at its default protocol, with every
54
+ explicit saturation band it offers placed, under `--limits`, which it then
55
+ requires. `--rf-layout` follows a valid reply with the
55
56
  RF layout of the evaluated request, its amplitudes relative to the peaks the
56
57
  listing states. Without `--rf-definitions`, `list` depends on the plugin file,
57
58
  its options and the installed packages only, so its reply can be written once
@@ -133,9 +134,16 @@ scanner for the prescription's rotation:
133
134
  | --- | --- |
134
135
  | `design_max_grad` | Gradient amplitude each logical axis is designed under, in the `grad_unit` of `max_grad` |
135
136
  | `design_max_slew` | Slew rate each logical axis is designed under, in the `slew_unit` of `max_slew` |
137
+ | `design_rf_dead_time` | Least delay of an RF pulse in its block, in s |
138
+ | `design_rf_ringdown_time` | Least time from the end of an RF pulse to the end of its block, in s |
139
+ | `design_adc_dead_time` | Least delay of a readout in its block, and least time after it, in s |
136
140
 
137
141
  A design limit above the scanner's leaves the scanner's, and one left out is the
138
- scanner's. The plugin designs under these limits derated once by
142
+ scanner's; a design dead time below the scanner's leaves the scanner's. The
143
+ design dead times are the room a playout needs around an RF pulse or a readout
144
+ in some layouts and not in others, such as a readout that starts right after
145
+ its excitation: designs make it everywhere, and the checks, which hold a file
146
+ to the scanner's own dead times, do not ask it of an imported chain. The plugin designs under these limits derated once by
139
147
  `pypulseqpp.apply_system_derates`: the gradient amplitude, slew rate and peak
140
148
  B1 scaled by `pypulseqpp.MAX_GRAD_DERATE`, `MAX_SLEW_DERATE` and
141
149
  `MAX_B1_DERATE`. The checks, the design's identity and its manifest keep the
@@ -270,8 +278,8 @@ scan beside the rest of that scan's log.
270
278
  ## Reconstruction proxy
271
279
 
272
280
  ```bash
273
- pulserver proxy --store DIR --port N --plugins DIR [--host ADDR] [--intake-port N] [--queue DIR] [--exams DIR] [--slots N] [--gpu-slots 1] [--spares 1] [--recon-timeout S] [--dicom] [--save-data DIR] [--idle-timeout S] [--logfile FILE] [--log-level LEVEL]
274
- pulserver proxy --store DIR --port N --forward HOST:PORT [--forward-config NAME] [--host ADDR] [--intake-port N] [--recon-timeout S] [--dicom] [--save-data DIR] [--idle-timeout S] [--logfile FILE] [--log-level LEVEL]
281
+ pulserver proxy --store DIR --port N --plugins DIR [--host ADDR] [--intake-port N] [--queue DIR] [--exams DIR] [--slots N] [--gpu-slots 1] [--spares 1] [--recon-timeout S] [--dicom] [--dicom-receiver HOST:PORT --dicom-receiver-title AE [--dicom-title AE]] [--save-data DIR] [--idle-timeout S] [--logfile FILE] [--log-level LEVEL]
282
+ pulserver proxy --store DIR --port N --forward HOST:PORT [--forward-config NAME] [--host ADDR] [--intake-port N] [--recon-timeout S] [--dicom] [--dicom-receiver HOST:PORT --dicom-receiver-title AE [--dicom-title AE]] [--save-data DIR] [--idle-timeout S] [--logfile FILE] [--log-level LEVEL]
275
283
  ```
276
284
 
277
285
  | Option | Meaning |
@@ -290,6 +298,9 @@ pulserver proxy --store DIR --port N --forward HOST:PORT [--forward-config NAME]
290
298
  | `--forward` | `HOST:PORT` of the MRD server that reconstructs every series, instead of local workers |
291
299
  | `--forward-config` | Config name sent to the `--forward` server; the series' reconstruction plugin when unset |
292
300
  | `--dicom` | Convert each image to DICOM before it is relayed, whatever reconstructed it; for a client that reads DICOM only |
301
+ | `--dicom-receiver` | `HOST:PORT` of a DICOM storage service the images of a series whose client has gone are stored to by C-STORE; held for the client's return when unset. Needs `pynetdicom` (`pulserver[dicom]`) |
302
+ | `--dicom-receiver-title` | Application entity title of the `--dicom-receiver`; required with it |
303
+ | `--dicom-title` | Application entity title the proxy calls the `--dicom-receiver` as; `PULSERVER` when unset |
293
304
  | `--save-data` | Directory each series is kept in, enriched; kept nowhere when unset |
294
305
  | `--idle-timeout` | Seconds without a client after which the proxy closes, never while a series is reconstructed. Unlimited when unset |
295
306
  | `--logfile` | File the log is appended to, together with the standard output and error of the proxy and its workers, so whatever a reconstruction plugin logs, prints or warns lands there too; standard error when unset |
@@ -312,14 +323,20 @@ A series that finds every slot busy is written to the queue directory as it
312
323
  arrives and reconstructed once a slot frees; the client stays connected
313
324
  meanwhile. What goes back to a client whose connection has dropped is kept for
314
325
  a day: a client that opens a series with the same `measurementID` is sent it in
315
- place of a new reconstruction.
326
+ place of a new reconstruction. With `--dicom-receiver`, the series' DICOM
327
+ images are stored to the receiver instead once its reconstruction ends, all of
328
+ them, since which ones the client read before it went cannot be told; the
329
+ output is kept only if the receiver did not store every one. A scanner client
330
+ whose process may be ended before a slow reconstruction finishes names its
331
+ image database here.
316
332
 
317
333
  ### Saved series
318
334
 
319
335
  With `--save-data`, each series is also written to
320
336
  `<save-data>/mrd_<timestamp>.h5` as the proxy reconstructs it: header and
321
337
  acquisitions enriched, the header marked `pulserver_enriched`, each acquisition
322
- as it arrives. `pulserver replay` runs a plugin on that file as it stands and
338
+ as it arrives. Until the stream ends the file is `mrd_<timestamp>.h5.part`, so
339
+ whatever collects the directory can tell a series still arriving. `pulserver replay` runs a plugin on that file as it stands and
323
340
  gives the image the proxy did ({ref}`series-replay`). The queue directory holds a series only until it is
324
341
  reconstructed.
325
342
 
@@ -433,7 +433,7 @@ saturation bands are the console's own controls:
433
433
  The saturation bands of `gre2d` and `se2d` are placed graphically, as a
434
434
  scanner's console places an explicit band, and each is played before every
435
435
  excitation while it is placed; a plugin offers as many bands as its module
436
- constant `BANDS`, 2, and refuses a mask placing more.
436
+ constant `BANDS`, 6, and refuses a mask placing more.
437
437
  `exsat<n>_normal_x`, `_y` and `_z`, `exsat<n>_loc` and `exsat<n>_thickness`
438
438
  give each band's normal along the physical axes, the distance of its centre
439
439
  from the isocentre along that normal, and its thickness, in mm. The
@@ -487,7 +487,7 @@ same user entry in every plugin:
487
487
  | `gre3d`, `gre_multiecho3d`, `mprage3d`, `fse3d` | `wave` | `user37` | Wave-CAIPI; the calibration region is acquired first without the wave, and `pics` and `pmc` reconstruct the wave-encoded volume | `user10` and `user11`: wave amplitude and cycles |
488
488
  | `gre3d`, `se3d`, `gre_multiecho3d` | `elliptical` | `user40` | Only the phase encodes inside the ky-kz ellipse; on by default | None |
489
489
  | `gre_multiecho2d`, `gre_multiecho3d` | `flyback` | `user41` | Monopolar echoes, on by default; off reads even echoes reversed | None |
490
- | `zte3d` | `scheme` | `user43` | Spokes ordered `"spiral"` or `"meridian"` | None |
490
+ | `zte3d` | `scheme` | `user43` | Spokes ordered `"spiral"`, at a constant step across many rings; `"meridian"`; or `"quiet"`, the default: the spiral's directions in steps about a ring gap long, every other shell played backwards | None |
491
491
  | `bssfp2d` | `retrospective` | `user44` | ECG gating: off, prospective, each heartbeat triggered and acquired once per cardiac phase; on, retrospective, each segment cycled over a heartbeat and binned into cardiac phases by the reconstruction | None |
492
492
  | `gre_spiral2d`, `se_spiral2d`, `gre_stack_of_spirals3d`, `se_stack_of_spirals3d`, `mprage_stack_of_spirals3d` | `variable_density` | `user42` | Variable-density spirals | `user12`: periphery undersampling |
493
493
 
@@ -24,7 +24,7 @@ classifiers = [
24
24
  ]
25
25
 
26
26
  dependencies = [
27
- "pypulseqpp>=0.0.49",
27
+ "pypulseqpp>=0.0.51",
28
28
  "numpy>=2.2.6",
29
29
  "ismrmrd>=1.15.0",
30
30
  "pydicom>=3.0.2",
@@ -37,7 +37,10 @@ dependencies = [
37
37
  ]
38
38
 
39
39
  [project.optional-dependencies]
40
+ # The proxy's --dicom-receiver: images stored by C-STORE.
41
+ dicom = ["pynetdicom>=3.0"]
40
42
  dev = [
43
+ "pynetdicom>=3.0",
41
44
  "pytest>=9.1.1",
42
45
  "pytest-cov>=7.1.0",
43
46
  "pytest-xdist>=3",
@@ -81,8 +81,6 @@ const char *pulseg_get_error_message(int code)
81
81
  return "A segment is played with too many distinct pulse patterns";
82
82
  case PULSEG_ERR_TR_NO_BLOCKS:
83
83
  return "Sequence contains no blocks";
84
- case PULSEG_ERR_TR_NO_PERIODIC_PATTERN:
85
- return "No periodic TR pattern found";
86
84
  case PULSEG_ERR_SEG_NONZERO_START_GRAD:
87
85
  return "TR does not start with zero gradient amplitude";
88
86
  case PULSEG_ERR_SEG_NONZERO_END_GRAD:
@@ -154,10 +152,6 @@ const char *pulseg_get_error_hint(int code)
154
152
  case PULSEG_ERR_SIGNATURE_MISSING:
155
153
  return "The .seq file does not contain a [SIGNATURE] section. "
156
154
  "Re-export the sequence to include a signature.";
157
- case PULSEG_ERR_TR_NO_PERIODIC_PATTERN:
158
- return "This often occurs when phase-encoding gradients are created inside "
159
- "the sequence loop with varying amplitudes. Instead, create gradient "
160
- "events ONCE outside the loop and use 'scale' parameter to vary amplitude.";
161
155
  case PULSEG_ERR_SEG_NONZERO_START_GRAD:
162
156
  case PULSEG_ERR_SEG_NONZERO_END_GRAD:
163
157
  return "Each segment must begin and end with gradient amplitudes that can "
@@ -289,33 +289,43 @@ extern "C"
289
289
  int subseq_idx);
290
290
 
291
291
  /**
292
- * @brief The span of a subsequence's timeline in which its RF plays
293
- * carry the most energy, as plays per pulse of the repetition.
292
+ * @brief The span of a subsequence's timeline over which its RF plays are
293
+ * averaged against a window, as plays per pulse of the repetition.
294
294
  *
295
295
  * Each play is placed at the start of its block, every block timed at its
296
296
  * own duration, and weighs @p weights[k], k being its pulse in the
297
- * repetition as pulseg_get_rf_array() orders them. Of the half-open spans
298
- * of @p window_us starting at a play, the one of largest total weight is
299
- * taken, the earliest on a tie; a subsequence shorter than the span plays
300
- * whole inside it. Two passes over the execution stream, no allocation.
297
+ * repetition as pulseg_get_rf_array() orders them. Where the
298
+ * hyper-repetition repeats and is shorter than @p window_us, it is the
299
+ * span: every window averages what it does, and weighed by
300
+ * pulseg_get_rf_array(), every repetition plays at the worst repetition
301
+ * instance's amplitudes. Otherwise a subsequence no
302
+ * longer than the window is the span. Otherwise, of the half-open spans of
303
+ * @p window_us starting at a play, or ending at the subsequence's end, the
304
+ * one of largest total weight is taken, the earliest on a tie: plays are
305
+ * costed by count, so the span needs no whole segment instances. Two
306
+ * passes over the execution stream, no allocation.
301
307
  *
302
308
  * @param[in] coll Loaded collection, with its execution stream.
303
309
  * @param[in] subseq_idx Subsequence index.
304
- * @param[in] window_us Span, us; > 0.
310
+ * @param[in] timing Its pulseg_get_tr_timing().
311
+ * @param[in] window_us Averaging window, us; > 0.
305
312
  * @param[in] weights Energy of one play of each pulse of the repetition.
306
313
  * @param[in] num_weights Pulses in the repetition.
307
314
  * @param[out] counts num_weights entries: plays of each pulse in the span.
308
315
  * @param[out] start_us Where the span starts; may be NULL.
316
+ * @param[out] span_us Its duration, the one to average over; may be NULL.
309
317
  * @return Plays in the span (0 without RF), or a negative error code.
310
318
  */
311
319
  int pulseg_get_rf_window(
312
320
  const pulseg_collection *coll,
313
321
  int subseq_idx,
322
+ const pulseg_tr_timing *timing,
314
323
  double window_us,
315
324
  const double *weights,
316
325
  int num_weights,
317
326
  int *counts,
318
- double *start_us);
327
+ double *start_us,
328
+ double *span_us);
319
329
 
320
330
  /**
321
331
  * @brief Return decompressed RF magnitude waveform (multi-channel).
@@ -32,7 +32,6 @@
32
32
 
33
33
  /* TR detection errors (-100 to -199) */
34
34
  #define PULSEG_ERR_TR_NO_BLOCKS -100
35
- #define PULSEG_ERR_TR_NO_PERIODIC_PATTERN -102
36
35
 
37
36
  /* Segmentation errors (-200 to -299) */
38
37
  #define PULSEG_ERR_SEG_NONZERO_START_GRAD -200