pulserver 0.3.0__tar.gz → 0.4.0__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.
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/workflows/wheels.yml +1 -1
- {pulserver-0.3.0 → pulserver-0.4.0}/PKG-INFO +3 -3
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api/recon.md +1 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/internals/virtual-scanner.md +10 -5
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/user-guide/reconstruction-client.md +32 -1
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/user-guide/reconstruction-plugins.md +33 -2
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/user-guide/running.md +26 -5
- {pulserver-0.3.0 → pulserver-0.4.0}/pyproject.toml +2 -2
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseg/pulseg_types.h +1 -1
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/structure/pulseg_getters.c +20 -2
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_cli.py +5 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/ir/_checks.py +1 -1
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/__init__.py +2 -0
- pulserver-0.4.0/src/pulserver/recon/_figure.py +31 -0
- pulserver-0.4.0/src/pulserver/recon/_replay.py +75 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_runtime/application.py +8 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_runtime/exam.py +1 -1
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_runtime/mrd2dicom.py +338 -65
- pulserver-0.4.0/src/pulserver/recon/_runtime/offline.py +162 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/plugin.py +41 -11
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_coils.py +15 -8
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_command.py +1 -1
- pulserver-0.4.0/tests/native/read_rf_timing.c +50 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_app.py +3 -3
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_images.py +58 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_mrd2dicom.py +342 -3
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_console.py +4 -2
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_checks.py +4 -3
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_rf.py +38 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_proxy.py +236 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_virtual_coils.py +15 -1
- pulserver-0.3.0/src/pulserver/recon/_runtime/offline.py +0 -91
- {pulserver-0.3.0 → pulserver-0.4.0}/.claude/skills/build-and-test/SKILL.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.claude/skills/write-documentation/SKILL.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.dockerignore +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.gitattributes +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/DISCUSSION_TEMPLATE/q-a.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/ISSUE_TEMPLATE/documentation.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/dependabot.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/workflows/codeql.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/workflows/console.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/workflows/docs.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/workflows/fields.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/workflows/image.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/workflows/koma.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/workflows/style.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/workflows/tags-release.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.github/workflows/test-ci.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.gitignore +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/.pre-commit-config.yaml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/AGENTS.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/CMakeLists.txt +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/CODE_OF_CONDUCT.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/CONTRIBUTING.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/LICENSE +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/LICENSES/gadgetron-python-MIT.txt +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/LICENSES/python-ismrmrd-server-MIT.txt +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/NEXT.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/README.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/SECURITY.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/SKILLS.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/codecov.yml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docker/Dockerfile +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docker/compose.yaml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docker/entrypoint.sh +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docker/limits/limits.txt +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docker/smoke.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/architecture-dark.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/architecture.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/capabilities.js +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/context-dark.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/context.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/pulseg-dark.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/pulseg.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/pulserver-logo-dark.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/pulserver-logo.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/pulserver-mark-dark.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/pulserver-mark.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/pulserver.css +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/repetition-dark.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/repetition.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/safety-dark.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/safety.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/session-dark.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/session.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/virtual-dark.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_static/virtual.svg +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_templates/autosummary/base.rst +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_templates/autosummary/class.rst +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_templates/autosummary/enum.rst +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/_templates/autosummary/function.rst +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api/design.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api/host.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api/index.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api/ir.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api/mrd.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api/protocol.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api/proxy.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api/validate.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api/virtual.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/api_objects.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/colab.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/conf.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/documentation.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/index.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/installation.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/internals/calibration.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/internals/index.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/internals/ir-cache.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/internals/protocol-wire.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/internals/reconstruction-proxy.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/internals/sar-ratios.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/releases.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/style.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/terminology.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/developer-guide/workflow.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/examples/course.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/examples/index.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/examples/tours.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/explanations/architecture.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/explanations/index.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/explanations/protocol.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/explanations/raw-data.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/explanations/reconstruction-session.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/explanations/reconstruction.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/explanations/safety-checks.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/explanations/scanner-representation.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/explanations/virtual-scanner.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/figure_style.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/index.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/misc/contributors.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/misc/index.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/misc/license.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/misc/related.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/user-guide/index.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/user-guide/scanner-sequences.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/docs/user-guide/virtual-scanner.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/01-course/01_protocol_to_image.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/01-course/02_sequence_plugin.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/01-course/03_scanner_representation.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/01-course/04_reconstruction_plugin.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/01-course/05_recon_plugin.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/01-course/06_testing_on_the_virtual_scanner.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/01-course/README.rst +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/01-course/_gallery_header.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/02-tours/01_protocol_resolution.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/02-tours/02_segmentation.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/02-tours/03_fov_offset_enrichment.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/02-tours/README.rst +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/02-tours/_gallery_header.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/README.rst +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/gallery/_gallery_header.md +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/scripts/build_docs.sh +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/scripts/check_throughput.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/scripts/format_and_lint.sh +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/scripts/make_artwork.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/scripts/publish_docs.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/setup.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/CMakeLists.txt +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/cache/pulseg_cache.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/core/pulseg_core.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/core/pulseg_error.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/core/pulseg_math.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseg/pulseg.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseg/pulseg_cache.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseg/pulseg_collection.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseg/pulseg_config.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseg/pulseg_errors.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseg/pulseg_io.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseg/pulseg_playout.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseg/pulseg_protocol.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseq/pulseq.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseq/pulseq_config.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/include/pulseq/pulseq_types.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/io/pulseg_opts.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/io/pulseg_protocol.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/playout/pulseg_playout.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/pulseg_internal.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/pulseq/pulseq_internal.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/pulseq/pulseq_shape.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/structure/pulseg_descriptor.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/structure/pulseg_repetition.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/c/structure/pulseg_waves.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/fourier/bindings.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/fourier/bindings.hpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/fourier/parallel.hpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/fourier/timeline.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/fourier/timeline.hpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/collection.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/dedup.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/from_libraries.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/from_libraries.hpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/pulseg_convert.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/pulseq_file.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/pulseq_file.h +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/repetition.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/structure.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/wave_plan.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/ir/waves.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/module.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/native.hpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/playout.cpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/cpp/playout.hpp +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_accelerators.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_labels.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_logs.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_memory.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_plugins.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/_evaluation.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/_inversion.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/_pmc.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/_saturation.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/_slab.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/_user.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/bssfp2d/retrospective.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/fse3d/dual_region.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/fse3d/navigator.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/fse3d/optimized.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/fse3d/shuffling.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/fse3d/wave.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/gre3d/full_plane.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/gre3d/wave.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/gre_multiecho2d/bipolar.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/gre_multiecho3d/bipolar.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/gre_multiecho3d/full_plane.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/gre_multiecho3d/wave.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/gre_spiral2d/variable_density.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/gre_stack_of_spirals3d/variable_density.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/mprage3d/navigator.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/mprage3d/shuffling.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/mprage3d/wave.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/mprage_stack_of_spirals3d/variable_density.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/se3d/full_plane.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/se_spiral2d/variable_density.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/se_stack_of_spirals3d/variable_density.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/parameters/zte3d/meridian.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/recon/epi.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/recon/nufft.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/recon/nufft_train.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/recon/pics.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/recon/pics_train.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/recon/pmc.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/bssfp2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/bssfp3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/epi2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/epi3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/fse3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/gre2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/gre3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/gre_multiecho2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/gre_multiecho3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/gre_propeller2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/gre_radial2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/gre_spiral2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/gre_stack_of_blades3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/gre_stack_of_spirals3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/gre_stack_of_stars3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/mprage3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/mprage_stack_of_spirals3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/mprage_stack_of_stars3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/se2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/se3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/se_epi_propeller2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/se_propeller2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/se_radial2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/se_spiral2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/se_stack_of_blades3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/se_stack_of_spirals3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/se_stack_of_stars3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/_zoo/sequences/zte3d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/design/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/design/_entries.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/design/_options.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/design/_plugin.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/design/_rf.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/host/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/host/__main__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/host/_blocks.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/host/_command.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/host/_limits.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/host/_push.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/host/_server.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/host/_service.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/host/_store.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/ir/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/ir/_convert.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/ir/_playout.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/ir/_source.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/ir/_vendor.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/ir/_waves.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/mrd/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/mrd/_acquisitions.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/mrd/_header.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/mrd/_images.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/mrd/_metadata.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/mrd/_sequence.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/protocol/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/protocol/_keys.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/protocol/_prescription.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/protocol/_schema.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/protocol/_wire.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/__main__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/_designs.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/_enrich.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/_held.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/_intake.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/_local.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/_motion.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/_proxy.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/_queue.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/_seqdesc.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/proxy/_workers.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/__main__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_buffers.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_calibration.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_correct.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_exam_image.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_loader.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_runtime/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_runtime/concurrency.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_runtime/connection.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_runtime/constants.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_runtime/readers.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_runtime/writers.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/_units.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/gadgets.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/handlers/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/handlers/epi.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/handlers/nufft.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/handlers/nufft_train.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/handlers/pics.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/handlers/pics_train.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/recon/handlers/pmc.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/validate/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/validate/_command.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/validate/_compare.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/validate/_validate.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/validate/_xml.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/__init__.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_brainweb.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_client.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_console.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_export.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_fourier.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_girf.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_localizer.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_motion.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_phantom.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_stream.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_timeline.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/src/pulserver/virtual/_tissue.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/_analytic.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/_host.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/_seqtext.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/_synthetic.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/_virtual.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/_zoo.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/conftest.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/bloch/bssfp.npy +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/bloch/epi_2d_main.npy +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/bloch/gre_2d_3sl.npy +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/bloch/steady_dess_hard_0hz.npy +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/bloch/steady_dess_hard_30hz.npy +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/bloch/steady_echo_hard_0hz.npy +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/bloch/steady_echo_hard_30hz.npy +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/bloch/steady_echo_selective_0hz.npy +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/bloch/steady_fid_hard_0hz.npy +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/sequences/dedup_gre_pair.seq +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/sequences/dedup_gre_pair_b.seq +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/sequences/epi_2d_main.seq +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/sequences/gre_2d_3sl.seq +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/sequences/mprage_stack_of_spirals_3d.seq +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/fixtures/sequences/zte_3d.seq +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/koma/Project.toml +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/koma/simulate.jl +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/native/check_initializers.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/native/print_wave_samples.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/native/read_cache_summary.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/native/read_rf_definitions.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/native/replay_an_instance.c +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/plugins/crash.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/plugins/gre2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/plugins/gre2d_raw.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/plugins/rf_train.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/plugins/stall.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/plugins/strong.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/plugins/tiny.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/plugins/typed.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_buffers.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_calibration.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_coil_compression.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_connection.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_correct.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_epi.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_exam_image.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_flags.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_gadgets.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_handlers.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_loader.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_nufft.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_pics.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_pmc.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_prewhiten.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_readers_writers.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_slots.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon/test_units.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon_plugins/children.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon_plugins/crash.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon_plugins/device.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon_plugins/exam.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon_plugins/gre2d.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/recon_plugins/pose.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_console_sequences.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_design_push.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_design_server.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_design_service.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_docs.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_docstring_defaults.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_docstrings.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_enrich.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_exam_artifacts.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_exam_calibration.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_exam_sharing.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_host_slots.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_image.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_designed.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_extensions.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_grouping.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_groups.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_labels.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_playout.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_profile.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_repetition.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_repetition_gradients.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_segments.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_source.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_steady_excitation.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_vendor.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_ir_waves.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_keys.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_koma.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_limits.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_logs.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_memory.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_motion.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_mrd_images.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_mrd_sequence.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_plugin_options.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_plugins.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_protocol.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_publish_docs.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_resolution.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_rf_layout.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_scan_command.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_seqdesc.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_sequence_plugin.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_smoke.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_validate.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_virtual.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_virtual_brainweb.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_virtual_clock.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_virtual_export.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_virtual_fourier.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_virtual_localizer.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_virtual_sequences.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_wire.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_zoo_evaluation.py +0 -0
- {pulserver-0.3.0 → pulserver-0.4.0}/tests/test_zoo_wave.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pulserver
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
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.
|
|
24
|
+
Requires-Dist: pypulseqpp>=0.0.42
|
|
25
25
|
Requires-Dist: numpy>=2.2.6
|
|
26
26
|
Requires-Dist: ismrmrd>=1.15.0
|
|
27
27
|
Requires-Dist: pydicom>=3.0.2
|
|
@@ -36,7 +36,7 @@ Requires-Dist: pytest>=9.1.1; extra == "dev"
|
|
|
36
36
|
Requires-Dist: pytest-cov>=7.1.0; extra == "dev"
|
|
37
37
|
Requires-Dist: pytest-xdist>=3; extra == "dev"
|
|
38
38
|
Requires-Dist: coverage>=7.16.2; extra == "dev"
|
|
39
|
-
Requires-Dist: ruff==0.
|
|
39
|
+
Requires-Dist: ruff==0.17.0; extra == "dev"
|
|
40
40
|
Requires-Dist: pre-commit>=4.6.2; extra == "dev"
|
|
41
41
|
Requires-Dist: build; extra == "dev"
|
|
42
42
|
Provides-Extra: doc
|
|
@@ -70,3 +70,4 @@ sensitivity maps, noise prewhitening and coil compression are the subject of
|
|
|
70
70
|
| {obj}`~pulserver.recon.ReconData` | The readouts of one reconstruction unit: imaging and calibration k-space, counters and waveforms. |
|
|
71
71
|
| {obj}`~pulserver.recon.ReconBuffer` | K-space of one encoding space, filled one acquisition at a time, with the acquisition nearest the k-space centre. |
|
|
72
72
|
| {obj}`~pulserver.recon.ReconResult` | Image array the runtime packages as an MRD image or DICOM dataset, with the acquisition its geometry is taken from and the rescale of its DICOM pixels. |
|
|
73
|
+
| {obj}`~pulserver.recon.figure_rgb` | Return a matplotlib figure drawn to the pixels of an RGB result, sent as a DICOM secondary capture. |
|
|
@@ -227,9 +227,14 @@ the models show none of the dielectric effects of a wavelength comparable to
|
|
|
227
227
|
the head.
|
|
228
228
|
|
|
229
229
|
A pulse plays on every transmit channel, weighted by the coil's default shim,
|
|
230
|
-
the
|
|
231
|
-
pulse then has its nominal amplitude:
|
|
232
|
-
|
|
230
|
+
the weights of magnitude $1/\sqrt{N}$ for $N$ channels that bring the channels
|
|
231
|
+
into phase at the isocentre, where the pulse then has its nominal amplitude:
|
|
232
|
+
each cube sees the transmit field
|
|
233
|
+
$b^+(\mathbf{r}) = \sum_c w_c\,s^+_c(\mathbf{r})$, for the weights $w_c$. The
|
|
234
|
+
squares of the weights sum to 1, so the channels together carry the power of
|
|
235
|
+
one channel at the pulse's amplitude, and an RF shim is written in the same
|
|
236
|
+
normalisation: a circularly polarised shim of $N$ channels has weights of
|
|
237
|
+
magnitude $1/\sqrt{N}$.
|
|
233
238
|
|
|
234
239
|
A console given field maps takes the coils, and the subject's field, from
|
|
235
240
|
electromagnetic and susceptibility models of BrainWeb's head instead
|
|
@@ -506,8 +511,8 @@ The maps' transmit coils come with the VOPs mariepy compresses from the same
|
|
|
506
511
|
fields, and every design is made under those of the exam's transmit coil: its
|
|
507
512
|
limits name the VOP file, the default shim, the drive of every channel per
|
|
508
513
|
hertz of a pulse's amplitude with which the channels' fields reach that
|
|
509
|
-
amplitude at the isocentre
|
|
510
|
-
maps' unit of drive, and the head and local SAR limits of IEC 60601-2-33's
|
|
514
|
+
amplitude at the isocentre through the default shim,
|
|
515
|
+
$2\sqrt{N} / (\gamma \sum_c |B^-_c(\mathbf{0})|)$ in the maps' unit of drive, and the head and local SAR limits of IEC 60601-2-33's
|
|
511
516
|
normal operating mode. The IR cache then reports each subsequence's SAR against
|
|
512
517
|
the reference pulse in that coil ({doc}`../../explanations/safety-checks`).
|
|
513
518
|
|
|
@@ -49,13 +49,44 @@ connection, so the client can finish sending and read the reason.
|
|
|
49
49
|
| `ExamID`, a `userParameterString`, or else `studyInformation.studyInstanceUID`, or else `studyInformation.studyID` | Optional | The exam; the series of one exam share its exam cache, and a series without one is an exam of its own |
|
|
50
50
|
| `fov_offset_mm`, a `userParameterString` | Optional | The position of the field-of-view centre, three millimetres along the logical readout, phase and slice axes separated by spaces; a difference from the offset the design was converted at is applied to the samples as a receive phase. Without it, the converted offset |
|
|
51
51
|
| `subjectInformation`, `studyInformation`, `measurementInformation`, `acquisitionSystemInformation` | Optional | Copied into the DICOM datasets; `relativeTablePosition` is not |
|
|
52
|
-
| `measurementInformation.measurementID` | A non-negative integer when `systemVendor` names GE | The DICOM series number on a GE system |
|
|
52
|
+
| `measurementInformation.measurementID` | A non-negative integer when `systemVendor` names GE | The DICOM series number on a GE system: of the first series the reconstruction returns, and `100 × measurementID + k` of the `k`-th after it |
|
|
53
|
+
| `dicom:<attribute>`, a `userParameterString` | Optional | A DICOM attribute of every image ({ref}`dicom-attributes`) |
|
|
53
54
|
| `encoding` | Optional | Replaced by one encoding space per subsequence, and one more for the navigator readouts of a subsequence that has them. The reconstruction space is the sequence's matrix size and field of view, one slice deep for a stack of 2D slices; the encoded space of a Cartesian space has the readout widened to the full echo, oversampling included, and its field of view in proportion. The encoding limits are the extremes of the counters the readouts reach, centred on the k-space centre line and partition the sequence defines. A matrix size or field of view the sequence does not define is kept from the client's encoding at the same index |
|
|
54
55
|
| `sequenceParameters` | Optional | TR, TE, TI and flip angles replaced by those the sequence defines; TR and TE it does not define are measured by pypulseqpp's `test_report_dict`, flip angles it does not define are the distinct values of `rf_flip_angles` |
|
|
55
56
|
|
|
56
57
|
A header that the ISMRMRD schema does not accept, or that names no design the
|
|
57
58
|
store holds for its scan, is refused before any acquisition is read.
|
|
58
59
|
|
|
60
|
+
(dicom-attributes)=
|
|
61
|
+
### DICOM attributes
|
|
62
|
+
|
|
63
|
+
A client states the DICOM attributes the MRD header has no element for as
|
|
64
|
+
`userParameterString` entries named `dicom:<attribute>`. The DICOM builder
|
|
65
|
+
reads them once, with the rest of the header, into the attributes every image
|
|
66
|
+
of the series starts from; an entry whose value names a quantity of the image
|
|
67
|
+
is filled in for each image instead. An image's own meta attributes take
|
|
68
|
+
precedence over both. `<attribute>` is one of:
|
|
69
|
+
|
|
70
|
+
| Form | Example | Resolved by |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| A keyword of the DICOM standard | `dicom:ImagedNucleus` = `23Na` | pydicom's dictionary |
|
|
73
|
+
| An explicit tag and value representation | `dicom:(0011,1011)FL` = `{location}` | Itself; a private group's creator is one more entry, `dicom:(0011,0010)LO` |
|
|
74
|
+
| A keyword of a private dictionary | `dicom:PulseSequenceLabel` = `pulserver` | The file `dicom:dictionary` names, in MATLAB's format, one `(gggg,eeee) VR Keyword VM` line per attribute |
|
|
75
|
+
|
|
76
|
+
A value separates multiple values with `\` and may name, in braces, a quantity
|
|
77
|
+
of the image it is written into; `{{` and `}}` are literal braces:
|
|
78
|
+
|
|
79
|
+
| Name | Value |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `slice_location` | The image centre along the plane normal, in mm: the `SliceLocation` written by default |
|
|
82
|
+
| `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 |
|
|
83
|
+
| `location_letter` | The side `location` lies on: `R` or `L`, `A` or `P`, `S` or `I`, and `+` or `-` for an oblique plane |
|
|
84
|
+
| `instance_number`, `series_number` | The image's `InstanceNumber` and `SeriesNumber` |
|
|
85
|
+
|
|
86
|
+
An attribute that resolves to no tag, for want of the dictionary, is logged and
|
|
87
|
+
left out. `pulserver replay --dicom-dictionary` names another dictionary for a
|
|
88
|
+
series replayed where the header's is not.
|
|
89
|
+
|
|
59
90
|
## Acquisitions
|
|
60
91
|
|
|
61
92
|
The proxy matches acquisitions to readouts by their position in the stream, so
|
|
@@ -284,7 +284,7 @@ receives carries the message. `required=False` returns `None` instead of
|
|
|
284
284
|
raising.
|
|
285
285
|
|
|
286
286
|
(dicom-pixel-values)=
|
|
287
|
-
## DICOM
|
|
287
|
+
## DICOM output
|
|
288
288
|
|
|
289
289
|
A DICOM dataset stores integer pixels, made when a result with `dicom=True` is
|
|
290
290
|
converted from the image the plugin returned. The dataset's rescale maps them
|
|
@@ -331,6 +331,32 @@ with one mapping per DICOM series, a series being the images that share
|
|
|
331
331
|
|
|
332
332
|
`RescaleType` is `US`, unspecified: the units are those of the reconstruction.
|
|
333
333
|
|
|
334
|
+
A DICOM image is written in the radiological display orientation of the plane
|
|
335
|
+
it lies closest to: an axial image with the patient's right on the left and
|
|
336
|
+
anterior at the top, a coronal one with the right on the left and superior at
|
|
337
|
+
the top, a sagittal one with anterior on the left and superior at the top. Its
|
|
338
|
+
pixels are flipped and transposed to that orientation, never resampled; the MRD
|
|
339
|
+
image keeps the orientation the reconstruction returned.
|
|
340
|
+
|
|
341
|
+
Each `series_index` is a DICOM series of its own. The first to arrive takes the
|
|
342
|
+
series identity the header states; each later one a series UID derived from it
|
|
343
|
+
and, on a GE system, the series number `100 × measurementID + k` for the
|
|
344
|
+
`k`-th after the first.
|
|
345
|
+
|
|
346
|
+
A plot, a fit or a report reaches the scanner as an RGB result: a `(y, x, 3)`
|
|
347
|
+
array of values from 0 to 255, which {func}`~pulserver.recon.figure_rgb` draws
|
|
348
|
+
from a matplotlib figure, stored as a DICOM secondary capture.
|
|
349
|
+
|
|
350
|
+
```python
|
|
351
|
+
return recon.ReconResult(
|
|
352
|
+
recon.figure_rgb(figure),
|
|
353
|
+
image_type="rgb",
|
|
354
|
+
series_index=10,
|
|
355
|
+
dicom=True,
|
|
356
|
+
attributes={"SeriesDescription": "T1 fit"},
|
|
357
|
+
)
|
|
358
|
+
```
|
|
359
|
+
|
|
334
360
|
## Diffusion tables
|
|
335
361
|
|
|
336
362
|
The proxy states the diffusion table a design names in the header's
|
|
@@ -365,12 +391,17 @@ process ID, level and logger name.
|
|
|
365
391
|
{meth}`~pulserver.recon.ReconPlugin.run` reconstructs an ISMRMRD HDF5 file in
|
|
366
392
|
the calling process, through the same hooks. A file recorded as the scanner
|
|
367
393
|
sends it, such as `pulserver scan --mrd raw.h5` or the proxy's `--save-data`
|
|
368
|
-
writes, is enriched from
|
|
394
|
+
writes, is enriched first from the design it was played from, found in a design
|
|
395
|
+
store or given as its sequence file, with its manifest beside it:
|
|
369
396
|
|
|
370
397
|
```python
|
|
371
398
|
images = PLUGIN.run("raw.h5", store="designs")
|
|
399
|
+
images = PLUGIN.run("raw.h5", design="designs/scan/9c74a8aa28527cf231/sequence.seq")
|
|
372
400
|
```
|
|
373
401
|
|
|
402
|
+
`pulserver replay` does the same from the command line
|
|
403
|
+
({ref}`series-replay`).
|
|
404
|
+
|
|
374
405
|
Calling the plugin on an {class}`~pulserver.mrd.AcquisitionBucket` runs
|
|
375
406
|
`startup`, passes every acquisition to `receive`, reconstructs the units still
|
|
376
407
|
open, runs `finish`, and returns the last output. A header need only describe
|
|
@@ -167,7 +167,7 @@ gradient heating from it.
|
|
|
167
167
|
| `vop_file` | `.mat` or `.npz` file of VOPs and the head SAR matrix of each body model, at a path the design calls can read; its `safety_factor` multiplies local SAR |
|
|
168
168
|
| `vop_head_limit`, `vop_local_limit` | The scanner's head and local SAR limits in W/kg in its current operating mode |
|
|
169
169
|
| `vop_drive_per_hz` | Channel drive per Hz of RF amplitude, one value or one per channel separated by spaces; a scale common to every channel cancels. Equal drives when left out |
|
|
170
|
-
| `vop_default_shim` | Magnitude and phase in rad of each channel's weight for a pulse played without an RF shim, separated by spaces; equal weights when left out |
|
|
170
|
+
| `vop_default_shim` | Magnitude and phase in rad of each channel's weight for a pulse played without an RF shim, separated by spaces; equal weights whose squares sum to 1 when left out |
|
|
171
171
|
| `vop_coil` | Transmit configuration the scanner reports; the VOP file's `transmit` metadata must name the same one |
|
|
172
172
|
| `acoustic_file` | HDF5 file of the gradient coil's acoustic transfer function, at a path the design calls can read; the peak and A-weighted average sound pressure levels are held to the limits of IEC 60601-2-33 and written into the cache |
|
|
173
173
|
| `acoustic_interval_us` | Sampling interval in µs that the bins of `acoustic_file` refer to; given with it |
|
|
@@ -305,10 +305,10 @@ place of a new reconstruction.
|
|
|
305
305
|
|
|
306
306
|
With `--save-data`, each series is also written to
|
|
307
307
|
`<save-data>/mrd_<timestamp>.h5` as the scanner sends it, header first and each
|
|
308
|
-
acquisition as it arrives, before it is enriched.
|
|
309
|
-
|
|
310
|
-
({ref}`
|
|
311
|
-
|
|
308
|
+
acquisition as it arrives, before it is enriched. `pulserver replay` runs a
|
|
309
|
+
plugin on that file and reconstructs it offline as the proxy did
|
|
310
|
+
({ref}`series-replay`). The queue directory holds a series only until it is
|
|
311
|
+
reconstructed.
|
|
312
312
|
|
|
313
313
|
### Proxy lifetime
|
|
314
314
|
|
|
@@ -387,6 +387,27 @@ the proxy forwarded it, enriched. Its stream is neither authenticated nor
|
|
|
387
387
|
encrypted, and `--host` names the interface the proxy reaches it on. It stops
|
|
388
388
|
on `SIGINT` or `SIGTERM` and waits for the series it is running.
|
|
389
389
|
|
|
390
|
+
(series-replay)=
|
|
391
|
+
## Series replay
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
pulserver replay SERIES --plugin FILE (--store DIR | --design SEQ) [--config TEXT] [--dicom] [--dicom-dictionary FILE] [--output DIR]
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
`pulserver replay` reconstructs one series kept by `--save-data` in the calling
|
|
398
|
+
process, with no proxy running. The series is enriched from the design it was
|
|
399
|
+
played from, at the field-of-view offset its header states, as the proxy
|
|
400
|
+
enriches it, and runs through the plugin's hooks
|
|
401
|
+
({ref}`offline-reconstruction`). The design is the one the header names in the
|
|
402
|
+
store `--store`, or the one whose sequence file, the first of its chain, is
|
|
403
|
+
`--design`. That file must be one the manifest beside it records, and the
|
|
404
|
+
manifest must name the design the header names. A series exported beside a
|
|
405
|
+
copy of its design's files replays with no store. Images go to `images.h5` in `--output`, and DICOM datasets to the files
|
|
406
|
+
they are named by; with `--dicom` every image is written as DICOM, as the
|
|
407
|
+
proxy's `--dicom` writes it, and `--dicom-dictionary` names the private
|
|
408
|
+
dictionary of the header's DICOM attributes ({ref}`dicom-attributes`). An exception raised by the plugin is not caught, so its
|
|
409
|
+
traceback names the line that raised it.
|
|
410
|
+
|
|
390
411
|
## Playout validation
|
|
391
412
|
|
|
392
413
|
```bash
|
|
@@ -24,7 +24,7 @@ classifiers = [
|
|
|
24
24
|
]
|
|
25
25
|
|
|
26
26
|
dependencies = [
|
|
27
|
-
"pypulseqpp>=0.0.
|
|
27
|
+
"pypulseqpp>=0.0.42",
|
|
28
28
|
"numpy>=2.2.6",
|
|
29
29
|
"ismrmrd>=1.15.0",
|
|
30
30
|
"pydicom>=3.0.2",
|
|
@@ -45,7 +45,7 @@ dev = [
|
|
|
45
45
|
"coverage>=7.16.2",
|
|
46
46
|
# Pinned, not ranged: a formatter that differs between a contributor and
|
|
47
47
|
# CI makes "one entry point" a lie. Dependabot proposes the bumps.
|
|
48
|
-
"ruff==0.
|
|
48
|
+
"ruff==0.17.0",
|
|
49
49
|
"pre-commit>=4.6.2",
|
|
50
50
|
"build",
|
|
51
51
|
]
|
|
@@ -846,7 +846,7 @@ typedef struct pulseg_block_info
|
|
|
846
846
|
int rf_num_samples; /**< samples per channel, -1 if absent */
|
|
847
847
|
int rf_duration_us; /**< RF shape duration (us), -1 if absent */
|
|
848
848
|
int rf_is_complex; /**< 1 if phase shape exists */
|
|
849
|
-
int rf_uniform_raster; /**< 1 if
|
|
849
|
+
int rf_uniform_raster; /**< 1 if samples sit on the RF raster */
|
|
850
850
|
|
|
851
851
|
/* ADC */
|
|
852
852
|
int has_adc; /**< 1 if ADC acquisition active */
|
|
@@ -1301,13 +1301,19 @@ static int block_has_rf(const pulseg_collection *coll, int seg_idx, int blk_idx)
|
|
|
1301
1301
|
return (bdef->rf_id != -1) ? 1 : 0;
|
|
1302
1302
|
}
|
|
1303
1303
|
|
|
1304
|
+
static int get_rf_num_samples(const pulseg_collection *coll, int seg_idx, int blk_idx);
|
|
1305
|
+
|
|
1306
|
+
/* 1 when the RF samples sit at the centres of consecutive RF raster periods:
|
|
1307
|
+
* no time shape, or one that places them there, as a writer may state the
|
|
1308
|
+
* default explicitly. */
|
|
1304
1309
|
static int block_rf_has_uniform_raster(const pulseg_collection *coll, int seg_idx, int blk_idx)
|
|
1305
1310
|
{
|
|
1306
1311
|
const pulseg_sequence_descriptor *desc;
|
|
1307
1312
|
const pulseg_virtual_segment *seg;
|
|
1308
|
-
int local_blk;
|
|
1313
|
+
int local_blk, i, n, uniform;
|
|
1309
1314
|
const pulseg_base_block *bdef;
|
|
1310
1315
|
const pulseg_rf_definition *rdef;
|
|
1316
|
+
float *t, r;
|
|
1311
1317
|
|
|
1312
1318
|
if (!resolve_block(coll, &desc, &seg, &local_blk, seg_idx, blk_idx))
|
|
1313
1319
|
return -1;
|
|
@@ -1317,7 +1323,19 @@ static int block_rf_has_uniform_raster(const pulseg_collection *coll, int seg_id
|
|
|
1317
1323
|
return -1;
|
|
1318
1324
|
|
|
1319
1325
|
rdef = &desc->rf_definitions[bdef->rf_id];
|
|
1320
|
-
|
|
1326
|
+
if (rdef->time_shape_id == 0)
|
|
1327
|
+
return 1;
|
|
1328
|
+
|
|
1329
|
+
t = pulseg_get_rf_time_us(coll, seg_idx, blk_idx);
|
|
1330
|
+
if (!t)
|
|
1331
|
+
return 0;
|
|
1332
|
+
n = get_rf_num_samples(coll, seg_idx, blk_idx);
|
|
1333
|
+
r = desc->rf_raster_us;
|
|
1334
|
+
uniform = (n > 0 && r > 0.0f);
|
|
1335
|
+
for (i = 0; uniform && i < n; ++i)
|
|
1336
|
+
uniform = fabs((double)t[i] - (i + 0.5) * r) <= 1e-3 * r;
|
|
1337
|
+
PULSEG_FREE(t);
|
|
1338
|
+
return uniform;
|
|
1321
1339
|
}
|
|
1322
1340
|
|
|
1323
1341
|
static float *alloc_uniform_time_us(int num_samples, float raster_us)
|
|
@@ -11,6 +11,7 @@ _USAGE = (
|
|
|
11
11
|
" pulserver validate SEQ [--vendor NAME] [--played FILE] ...\n"
|
|
12
12
|
" pulserver proxy --store DIR --port N (--plugins DIR | --forward HOST:PORT) ...\n"
|
|
13
13
|
" pulserver recon --plugins DIR --port N ...\n"
|
|
14
|
+
" pulserver replay SERIES --plugin FILE (--store DIR | --design SEQ) ...\n"
|
|
14
15
|
)
|
|
15
16
|
|
|
16
17
|
|
|
@@ -38,6 +39,10 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
38
39
|
|
|
39
40
|
recon(argv[1:])
|
|
40
41
|
return 0
|
|
42
|
+
if argv and argv[0] == "replay":
|
|
43
|
+
from .recon._replay import main as replay
|
|
44
|
+
|
|
45
|
+
return replay(argv[1:])
|
|
41
46
|
if argv and argv[0] == "validate":
|
|
42
47
|
from .validate._command import main as check
|
|
43
48
|
|
|
@@ -59,7 +59,7 @@ class CheckLimits:
|
|
|
59
59
|
the ratios.
|
|
60
60
|
default_shim
|
|
61
61
|
Complex channel weights of a pulse played without an RF shim, and of
|
|
62
|
-
the reference pulse; equal weights when None.
|
|
62
|
+
the reference pulse; equal weights whose squares sum to 1 when None.
|
|
63
63
|
vop_coil
|
|
64
64
|
The transmit configuration the scanner reports. When given, the VOP
|
|
65
65
|
file's ``metadata["transmit"]`` must name the same one.
|
|
@@ -8,6 +8,7 @@ from ._calibration import (
|
|
|
8
8
|
)
|
|
9
9
|
from ._correct import gradient_unwarped
|
|
10
10
|
from ._exam_image import ExamImage
|
|
11
|
+
from ._figure import figure_rgb
|
|
11
12
|
from ._loader import load_plugin
|
|
12
13
|
from .gadgets import AsymmetricEcho, Prewhiten, RemoveReadoutOversampling
|
|
13
14
|
from .plugin import (
|
|
@@ -46,6 +47,7 @@ __all__ = [
|
|
|
46
47
|
"ReconResult",
|
|
47
48
|
"RemoveReadoutOversampling",
|
|
48
49
|
"coil_maps",
|
|
50
|
+
"figure_rgb",
|
|
49
51
|
"gradient_unwarped",
|
|
50
52
|
"load_plugin",
|
|
51
53
|
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""A matplotlib figure as the pixels of an RGB reconstruction result."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = ["figure_rgb"]
|
|
6
|
+
|
|
7
|
+
import io
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def figure_rgb(figure: Any, dpi: float | None = None) -> np.ndarray:
|
|
14
|
+
"""Return a matplotlib figure drawn to a ``(y, x, 3)`` ``uint8`` array.
|
|
15
|
+
|
|
16
|
+
Pass it as ``ReconResult(figure_rgb(fig), image_type="rgb")`` to send a
|
|
17
|
+
plot, a fit or a report to the scanner as a secondary capture.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
figure : matplotlib.figure.Figure
|
|
22
|
+
The figure; drawn as ``savefig`` draws it, whatever its canvas.
|
|
23
|
+
dpi : float, default=None
|
|
24
|
+
Resolution to draw at; the figure's own when not given.
|
|
25
|
+
"""
|
|
26
|
+
dpi = figure.dpi if dpi is None else dpi
|
|
27
|
+
buffer = io.BytesIO()
|
|
28
|
+
figure.savefig(buffer, format="rgba", dpi=dpi)
|
|
29
|
+
width = round(figure.get_figwidth() * dpi)
|
|
30
|
+
rgba = np.frombuffer(buffer.getvalue(), dtype=np.uint8).reshape(-1, width, 4)
|
|
31
|
+
return rgba[..., :3].copy()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Reconstruct a kept series in this process: ``pulserver replay SERIES --plugin FILE``."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _parser() -> argparse.ArgumentParser:
|
|
10
|
+
parser = argparse.ArgumentParser(
|
|
11
|
+
prog="pulserver replay",
|
|
12
|
+
description="Reconstruct a series as the scanner sent it, in this process, "
|
|
13
|
+
"enriched from the design it was played from as the proxy enriches it.",
|
|
14
|
+
)
|
|
15
|
+
parser.add_argument(
|
|
16
|
+
"series",
|
|
17
|
+
type=Path,
|
|
18
|
+
help="ISMRMRD file of the series, as the proxy's --save-data keeps it",
|
|
19
|
+
)
|
|
20
|
+
parser.add_argument(
|
|
21
|
+
"--plugin", type=Path, required=True, help="reconstruction plugin file"
|
|
22
|
+
)
|
|
23
|
+
played = parser.add_mutually_exclusive_group(required=True)
|
|
24
|
+
played.add_argument(
|
|
25
|
+
"--store", type=Path, help="design store holding the design the header names"
|
|
26
|
+
)
|
|
27
|
+
played.add_argument(
|
|
28
|
+
"--design",
|
|
29
|
+
type=Path,
|
|
30
|
+
help="the design's sequence file, the first of its chain, with its "
|
|
31
|
+
"manifest beside it",
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--config", help="configuration payload, as the scanner's stream carries it"
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"--dicom",
|
|
38
|
+
action="store_true",
|
|
39
|
+
help="write every image as DICOM, as the proxy's --dicom does",
|
|
40
|
+
)
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--dicom-dictionary",
|
|
43
|
+
type=Path,
|
|
44
|
+
help="private DICOM dictionary for the header's dicom: attributes, in "
|
|
45
|
+
"place of the one the header names",
|
|
46
|
+
)
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"--output",
|
|
49
|
+
type=Path,
|
|
50
|
+
default=Path(),
|
|
51
|
+
help="directory the reconstruction's images are written to",
|
|
52
|
+
)
|
|
53
|
+
return parser
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def main(argv: list[str] | None = None) -> int:
|
|
57
|
+
"""Run ``pulserver replay`` with ``argv``; return its exit status.
|
|
58
|
+
|
|
59
|
+
Images go to ``images.h5`` in ``--output`` and DICOM datasets to the files
|
|
60
|
+
they are named by. A plugin's exception is not caught, so its traceback
|
|
61
|
+
names the line that raised it.
|
|
62
|
+
"""
|
|
63
|
+
from ..virtual._command import _received
|
|
64
|
+
from ._loader import load_plugin
|
|
65
|
+
|
|
66
|
+
args = _parser().parse_args(argv)
|
|
67
|
+
emitted = load_plugin(args.plugin).run(
|
|
68
|
+
str(args.series),
|
|
69
|
+
config=args.config,
|
|
70
|
+
store=None if args.store is None else str(args.store),
|
|
71
|
+
design=None if args.design is None else str(args.design),
|
|
72
|
+
dicom=args.dicom,
|
|
73
|
+
dicom_dictionary=args.dicom_dictionary,
|
|
74
|
+
)
|
|
75
|
+
return _received(emitted, args.output)
|
|
@@ -157,6 +157,13 @@ def _make_images(
|
|
|
157
157
|
) -> tuple[list[ismrmrd.Image], int]:
|
|
158
158
|
data = as_numpy(result.data)
|
|
159
159
|
unit = _unit_header(result, bucket, context.header)
|
|
160
|
+
if result.image_type.lower() == "rgb":
|
|
161
|
+
if data.ndim != 3 or data.shape[-1] != 3:
|
|
162
|
+
raise ValueError(f"an RGB result is (y, x, 3), not {data.shape}")
|
|
163
|
+
planes = np.clip(np.moveaxis(data, -1, 0), 0, 255).astype(np.uint16)
|
|
164
|
+
rgb = dataclasses.replace(result, data=planes[:, None])
|
|
165
|
+
image, next_image_index = _make_image(rgb, unit, next_image_index, app_name)
|
|
166
|
+
return [image], next_image_index
|
|
160
167
|
if data.ndim != 3 or data.shape[0] == 1:
|
|
161
168
|
image, next_image_index = _make_image(result, unit, next_image_index, app_name)
|
|
162
169
|
return [image], next_image_index
|
|
@@ -297,6 +304,7 @@ def _image_type(name: str) -> int:
|
|
|
297
304
|
"real": ismrmrd.IMTYPE_REAL,
|
|
298
305
|
"imaginary": ismrmrd.IMTYPE_IMAG,
|
|
299
306
|
"complex": ismrmrd.IMTYPE_COMPLEX,
|
|
307
|
+
"rgb": ismrmrd.IMTYPE_RGB,
|
|
300
308
|
}
|
|
301
309
|
try:
|
|
302
310
|
return types[name.lower()]
|
|
@@ -277,7 +277,7 @@ def exam_directory_name(exam_id: Hashable) -> str:
|
|
|
277
277
|
"""Return the name of an exam's directory under the exam root.
|
|
278
278
|
|
|
279
279
|
An identity :func:`resolve_exam_id` returns is named ``<source>-<value>``,
|
|
280
|
-
``exam-
|
|
280
|
+
``exam-42`` for the ``ExamID`` 42, so a design call can name the
|
|
281
281
|
directory of the exam it is made in from the exam's number. Any other
|
|
282
282
|
identity, and a value that is not a plain file name, is named by the
|
|
283
283
|
SHA-256 of its ``repr``.
|