simind-python-connector 1.1.2__tar.gz → 1.2.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.
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/MANIFEST.in +0 -4
- {simind_python_connector-1.1.2/simind_python_connector.egg-info → simind_python_connector-1.2.0}/PKG-INFO +4 -1
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/README.md +3 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docker/README.md +3 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docker/compose.yaml +4 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docker/constraints.txt +2 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docker/python/Dockerfile +1 -1
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docker/pytomography/Dockerfile +2 -3
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docker/sirf/Dockerfile +2 -1
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docker/stir/Dockerfile +2 -1
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/changelog.rst +58 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/conf.py +5 -8
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/contributing.rst +21 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/01_basic_simulation.py +2 -1
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/02_runtime_switch_comparison.py +1 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/03_multi_window.py +1 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/05_scattwin_vs_penetrate_comparison.py +6 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/07A_stir_adaptor_osem.py +1 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0/docs}/examples/07B_sirf_adaptor_osem.py +1 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/07C_pytomography_adaptor_osem.py +1 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/installation.rst +10 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/testing.rst +21 -54
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/usage.rst +31 -12
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/01_basic_simulation.py +2 -1
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/02_runtime_switch_comparison.py +1 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/03_multi_window.py +1 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/05_scattwin_vs_penetrate_comparison.py +6 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/07A_stir_adaptor_osem.py +1 -0
- {simind_python_connector-1.1.2/docs → simind_python_connector-1.2.0}/examples/07B_sirf_adaptor_osem.py +1 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/07C_pytomography_adaptor_osem.py +1 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/pyproject.toml +6 -4
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/scripts/release.sh +28 -20
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/scripts/run_container_examples.sh +2 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/scripts/run_container_validation.sh +4 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/__init__.py +2 -11
- simind_python_connector-1.2.0/simind_python_connector/_version.py +3 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/backends/__init__.py +30 -28
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/backends/base.py +7 -52
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/backends/sirf_backend.py +19 -23
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/backends/stir_backend.py +38 -29
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/builders/__init__.py +2 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/builders/acquisition_builder.py +8 -25
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/builders/image_builder.py +4 -4
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/configs/__init__.py +1 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/connectors/_spacing.py +4 -16
- simind_python_connector-1.2.0/simind_python_connector/connectors/base.py +73 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/connectors/python_connector.py +40 -25
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/connectors/pytomography_adaptor.py +28 -37
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/connectors/sirf_adaptor.py +10 -24
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/connectors/stir_adaptor.py +13 -24
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/converters/attenuation.py +1 -10
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/converters/simind_to_stir.py +32 -32
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/core/config.py +1 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/core/executor.py +9 -10
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/utils/__init__.py +7 -17
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/utils/backend_access.py +4 -4
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/utils/import_helpers.py +4 -5
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/utils/interfile_numpy.py +11 -4
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/utils/interfile_parser.py +9 -10
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/utils/simind_utils.py +0 -7
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/utils/sirf_stir_utils.py +11 -11
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/utils/stir_utils.py +12 -18
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0/simind_python_connector.egg-info}/PKG-INFO +4 -1
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector.egg-info/SOURCES.txt +2 -0
- simind_python_connector-1.2.0/tests/conftest.py +47 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_acquisition_builder_unit.py +0 -11
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_adaptor_release_simind.py +44 -35
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_anisotropic_voxels_simind.py +1 -1
- simind_python_connector-1.2.0/tests/test_arithmetic_operations.py +84 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_attenuation_utils.py +5 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_backends.py +18 -183
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_connector_backend_separation.py +12 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_container_scripts.py +6 -12
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_dicom_builder.py +18 -4
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_energy_window_filename_simind.py +1 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_executor.py +0 -9
- simind_python_connector-1.2.0/tests/test_integration.py +33 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_interfile_numpy.py +3 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_native_adaptors.py +99 -105
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_native_geometry_real.py +4 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_non_square_slices_simind.py +2 -1
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_packaging_resources.py +12 -3
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_python_connector.py +31 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_pytomography_adaptor.py +23 -21
- simind_python_connector-1.2.0/tests/test_release_versioning.py +71 -0
- simind_python_connector-1.2.0/tests/test_schneider_density.py +104 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_simind_to_stir_converter.py +0 -43
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_simulation_config.py +8 -44
- simind_python_connector-1.2.0/tests/test_single_window_simind.py +49 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_stir_backend_arithmetic.py +18 -0
- simind_python_connector-1.2.0/tests/test_utils.py +99 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_utils_small.py +4 -6
- simind_python_connector-1.1.2/simind_python_connector/connectors/base.py +0 -40
- simind_python_connector-1.1.2/tests/conftest.py +0 -100
- simind_python_connector-1.1.2/tests/test_arithmetic_operations.py +0 -106
- simind_python_connector-1.1.2/tests/test_integration.py +0 -38
- simind_python_connector-1.1.2/tests/test_schneider_density.py +0 -303
- simind_python_connector-1.1.2/tests/test_single_window_simind.py +0 -84
- simind_python_connector-1.1.2/tests/test_utils.py +0 -129
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/.dockerignore +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/LICENSE +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docker/import_guard/sitecustomize.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docker/python/install_mpich_compat.sh +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/_static/.gitkeep +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/api.rst +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/backends.rst +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/connector_modernization_plan.rst +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/04_custom_config.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/06_schneider_density_conversion.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/08A_stir_adaptor_from_dicom.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/08B_sirf_adaptor_from_dicom.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/08C_pytomography_adaptor_from_dicom.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/_python_connector_helpers.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples.rst +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/geometry.rst +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/index.rst +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/intro.rst +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/04_custom_config.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/06_schneider_density_conversion.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/08A_stir_adaptor_from_dicom.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/08B_sirf_adaptor_from_dicom.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/08C_pytomography_adaptor_from_dicom.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/_python_connector_helpers.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/run_all_examples.sh +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/scripts/fix.sh +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/scripts/run_all_examples.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/setup.cfg +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/configs/AnyScan.yaml +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/configs/Discovery670.yaml +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/configs/Example.yaml +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/configs/MLD001_SCAN0.yaml +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/configs/input.smc +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/connectors/__init__.py +2 -2
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/converters/__init__.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/converters/dicom_to_stir.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/core/__init__.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/core/types.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/data/Schneider2000.json +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/data/__init__.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/data/bone.atn +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/data/h2o.atn +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/utils/geometry_phantom.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector/utils/io_utils.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector.egg-info/dependency_links.txt +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector.egg-info/requires.txt +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/simind_python_connector.egg-info/top_level.txt +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/__init__.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/fixtures/minimal_variable_sections.smc +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_container_library_isolation.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_image_builder_unit.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_interfile_parser.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_patch_release_simind.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_sirf_stir_utils.py +0 -0
- {simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/tests/test_stir_utils_backend_choice_unit.py +0 -0
|
@@ -11,12 +11,8 @@ recursive-include tests/fixtures *.smc
|
|
|
11
11
|
recursive-include examples *.py *.sh
|
|
12
12
|
recursive-include scripts *.py *.sh
|
|
13
13
|
recursive-include docker Dockerfile *.md *.txt *.yaml *.yml *.py *.sh
|
|
14
|
-
exclude AGENTS.md
|
|
15
|
-
exclude opencode.jsonc
|
|
16
|
-
exclude CLAUDE.md
|
|
17
14
|
exclude simind_manual.pdf
|
|
18
15
|
prune simind
|
|
19
|
-
prune docs/superpowers
|
|
20
16
|
prune docs/_build
|
|
21
17
|
prune docs/_generated
|
|
22
18
|
global-exclude __pycache__
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simind-python-connector
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Python SIMIND Monte Carlo connector with STIR/SIRF/PyTomography adaptors
|
|
5
5
|
Author-email: Sam Porter <sam.porter.18@ucl.ac.uk>, Rebecca Gillen <rebecca.gillen.18@ucl.ac.uk>, "Efstathios (Stahis) Varzakis" <efstathios.varzakis.22@ucl.ac.uk>
|
|
6
6
|
Maintainer-email: Sam Porter <sam.porter.18@ucl.ac.uk>
|
|
@@ -61,6 +61,9 @@ University.
|
|
|
61
61
|
SIMIND is **not distributed** with this package. You must separately obtain and
|
|
62
62
|
install a licensed SIMIND installation.
|
|
63
63
|
|
|
64
|
+
**Supported SIMIND version:** SIMIND V8.0. SIMIND V9.0 is not supported yet;
|
|
65
|
+
V9 support will follow in a later release.
|
|
66
|
+
|
|
64
67
|
## Quick Links
|
|
65
68
|
- [Full Documentation](https://simind-python-connector.readthedocs.io/)
|
|
66
69
|
- [Installation](https://simind-python-connector.readthedocs.io/en/latest/installation.html)
|
|
@@ -19,6 +19,9 @@ University.
|
|
|
19
19
|
SIMIND is **not distributed** with this package. You must separately obtain and
|
|
20
20
|
install a licensed SIMIND installation.
|
|
21
21
|
|
|
22
|
+
**Supported SIMIND version:** SIMIND V8.0. SIMIND V9.0 is not supported yet;
|
|
23
|
+
V9 support will follow in a later release.
|
|
24
|
+
|
|
22
25
|
## Quick Links
|
|
23
26
|
- [Full Documentation](https://simind-python-connector.readthedocs.io/)
|
|
24
27
|
- [Installation](https://simind-python-connector.readthedocs.io/en/latest/installation.html)
|
|
@@ -74,6 +74,9 @@ Services
|
|
|
74
74
|
Notes
|
|
75
75
|
-----
|
|
76
76
|
|
|
77
|
+
- The container scripts run the `python` service as the invoking host user
|
|
78
|
+
(`HOST_UID`/`HOST_GID`); direct `docker compose run python` runs as root.
|
|
79
|
+
The SIRF-based services always run as uid 1000 (`jovyan`).
|
|
77
80
|
- The SIRF container build arg is `SIRF_BASE_IMAGE`.
|
|
78
81
|
- The STIR container build arg is `STIR_BASE_IMAGE`.
|
|
79
82
|
- Install SIMIND by following the official installation instructions on the SIMIND website.
|
|
@@ -4,8 +4,12 @@ services:
|
|
|
4
4
|
context: ..
|
|
5
5
|
dockerfile: docker/python/Dockerfile
|
|
6
6
|
image: simind-python-connector/python:dev
|
|
7
|
+
# The container scripts run this service as the invoking host user so its
|
|
8
|
+
# outputs in the shared mount stay writable; direct use runs as root.
|
|
9
|
+
user: "${HOST_UID:-0}:${HOST_GID:-0}"
|
|
7
10
|
working_dir: /workspace
|
|
8
11
|
environment:
|
|
12
|
+
HOME: /tmp
|
|
9
13
|
SIMIND_CONNECTOR_BACKEND: python
|
|
10
14
|
SIMIND_ROOT: /workspace/simind
|
|
11
15
|
SIMIND_BIN: ${SIMIND_BIN:-/workspace/simind/simind}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
# NumPy is capped below 2.x: the STIR/SIRF binaries in the synerbi/sirf base
|
|
3
3
|
# images are compiled against NumPy 1.x and crash with NumPy 2 (see README
|
|
4
4
|
# "NumPy ABI" notes).
|
|
5
|
+
# Backend installs also resolve the base image's imagecodecs and tifffile so
|
|
6
|
+
# their NumPy requirements stay compatible with this cap.
|
|
5
7
|
numpy<2.0
|
|
6
8
|
pytest==8.4.2
|
|
@@ -16,7 +16,7 @@ ENV PATH=${SIMIND_ROOT}/bin:${SIMIND_ROOT}:${PATH}
|
|
|
16
16
|
# MPICH runtime for SIMIND's MPI binary; the compat script exposes the library
|
|
17
17
|
# names that binary was built against. See docker/python/install_mpich_compat.sh.
|
|
18
18
|
RUN apt-get update \
|
|
19
|
-
&& apt-get install -y --no-install-recommends mpich \
|
|
19
|
+
&& apt-get install -y --no-install-recommends git mpich \
|
|
20
20
|
&& rm -rf /var/lib/apt/lists/*
|
|
21
21
|
|
|
22
22
|
COPY docker/python/install_mpich_compat.sh /usr/local/bin/install_mpich_compat.sh
|
{simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docker/pytomography/Dockerfile
RENAMED
|
@@ -21,9 +21,8 @@ COPY --chown=1000:100 . /workspace
|
|
|
21
21
|
|
|
22
22
|
RUN python -m pip install --upgrade pip \
|
|
23
23
|
&& pip install --index-url https://download.pytorch.org/whl/cpu torch \
|
|
24
|
-
&& pip install
|
|
25
|
-
|
|
26
|
-
&& pip install --constraint /workspace/docker/constraints.txt -e ".[dev,examples]" \
|
|
24
|
+
&& pip install --constraint /workspace/docker/constraints.txt \
|
|
25
|
+
-e ".[dev,examples]" pytomography imagecodecs tifffile \
|
|
27
26
|
&& python - <<'PY'
|
|
28
27
|
import importlib
|
|
29
28
|
for module in ("torch", "pytomography", "pytest"):
|
|
@@ -20,7 +20,8 @@ WORKDIR /workspace
|
|
|
20
20
|
COPY --chown=1000:100 . /workspace
|
|
21
21
|
|
|
22
22
|
RUN python -m pip install --upgrade pip \
|
|
23
|
-
&& pip install --constraint /workspace/docker/constraints.txt
|
|
23
|
+
&& pip install --constraint /workspace/docker/constraints.txt \
|
|
24
|
+
-e ".[dev,examples]" imagecodecs tifffile \
|
|
24
25
|
&& python - <<'PY'
|
|
25
26
|
import importlib
|
|
26
27
|
for module in ("sirf.STIR", "pytest"):
|
|
@@ -20,7 +20,8 @@ WORKDIR /workspace
|
|
|
20
20
|
COPY --chown=1000:100 . /workspace
|
|
21
21
|
|
|
22
22
|
RUN python -m pip install --upgrade pip \
|
|
23
|
-
&& pip install --constraint /workspace/docker/constraints.txt
|
|
23
|
+
&& pip install --constraint /workspace/docker/constraints.txt \
|
|
24
|
+
-e ".[dev,examples]" imagecodecs tifffile \
|
|
24
25
|
&& python - <<'PY'
|
|
25
26
|
import stir # noqa: F401
|
|
26
27
|
import pytest # noqa: F401
|
|
@@ -7,6 +7,64 @@ All notable changes to this project are documented in this file.
|
|
|
7
7
|
|
|
8
8
|
The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_, and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
|
|
9
9
|
|
|
10
|
+
1.2.0 - 2026-10-16
|
|
11
|
+
------------------
|
|
12
|
+
|
|
13
|
+
Changed
|
|
14
|
+
~~~~~~~
|
|
15
|
+
|
|
16
|
+
- **Breaking:** without the ``CA`` runtime switch, SCATTWIN runs return only
|
|
17
|
+
the total projection. The energy-window file now holds exactly the requested
|
|
18
|
+
windows; 1.1.x appended a scatter-order-1 line when every order was 0, which
|
|
19
|
+
made SIMIND also write ``sca``, ``air`` and a duplicate ``sca_w2``. Code that
|
|
20
|
+
reads ``outputs["sca_w1"]`` or ``get_scatter_output()`` needs
|
|
21
|
+
``add_runtime_switch("CA", 1)``.
|
|
22
|
+
- Internal tidy-up with no behaviour change: type hints use ``X | None`` and
|
|
23
|
+
built-in generics, ``__all__`` lists are sorted, and redundant ``pass``
|
|
24
|
+
statements are removed.
|
|
25
|
+
|
|
26
|
+
Added
|
|
27
|
+
~~~~~
|
|
28
|
+
|
|
29
|
+
- The ``CA`` runtime switch is accepted (``add_runtime_switch("CA", n)``). It
|
|
30
|
+
selects the SCATTWIN projections SIMIND V8 writes: without it only ``tot``;
|
|
31
|
+
``1`` adds ``sca`` and ``air``; ``2`` adds ``pri``, ``sca`` and ``air``.
|
|
32
|
+
- A SCATTWIN run without the ``CA`` switch, and with every scatter order 0,
|
|
33
|
+
issues a ``UserWarning`` saying that only total projections will be written.
|
|
34
|
+
- ``get_primary_output()`` returns the primary projection written with
|
|
35
|
+
``CA`` = 2.
|
|
36
|
+
- ``get_scatter_output()`` and ``get_primary_output()`` return the total minus
|
|
37
|
+
the other component when only that one was written, and warn and return
|
|
38
|
+
``None`` when neither was.
|
|
39
|
+
|
|
40
|
+
Fixed
|
|
41
|
+
~~~~~
|
|
42
|
+
|
|
43
|
+
- ``number - x`` on SIRF image and acquisition wrappers returned wrong values.
|
|
44
|
+
- ``StirImageData`` arithmetic raised ``TypeError`` on STIR 6.2, and
|
|
45
|
+
``create_simple_phantom()`` and ``create_attenuation_map()`` failed there.
|
|
46
|
+
- ``StirAcquisitionData.get_info()`` returns STIR's parameter text instead of
|
|
47
|
+
the SWIG object's address.
|
|
48
|
+
- ``from simind_python_connector.utils import *`` raised ``AttributeError``.
|
|
49
|
+
- Interfile data with a partial trailing pixel is rejected instead of the extra
|
|
50
|
+
bytes being ignored.
|
|
51
|
+
- The DICOM acquisition builder no longer prints debug lines, and its warnings
|
|
52
|
+
name the missing ``AcquisitionDate`` and ``AcquisitionTime`` fields.
|
|
53
|
+
|
|
54
|
+
Deprecated
|
|
55
|
+
~~~~~~~~~~
|
|
56
|
+
|
|
57
|
+
- STIR 6.2 and earlier, which have no image arithmetic. ``StirImageData``
|
|
58
|
+
computes it in NumPy there and issues a ``DeprecationWarning``; support will
|
|
59
|
+
be removed in a future release.
|
|
60
|
+
|
|
61
|
+
Notes
|
|
62
|
+
~~~~~
|
|
63
|
+
|
|
64
|
+
- This release supports SIMIND V8.0. SIMIND V9.0 is not supported yet: it
|
|
65
|
+
changes several output formats and behaviours the connector relies on, so
|
|
66
|
+
V9 support will follow in a later release.
|
|
67
|
+
|
|
10
68
|
1.1.2 - 2026-10-15
|
|
11
69
|
------------------
|
|
12
70
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
5
|
from datetime import datetime
|
|
6
|
-
from
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from runpy import run_path
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
# Add the package to the path
|
|
@@ -13,13 +14,9 @@ sys.path.insert(0, os.path.abspath(".."))
|
|
|
13
14
|
project = "simind-python-connector"
|
|
14
15
|
copyright = f"{datetime.now().year}, Sam Porter, Efstathios Varzakis"
|
|
15
16
|
author = "Sam Porter, Efstathios Varzakis"
|
|
16
|
-
release =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
release = importlib_metadata.version(dist_name)
|
|
20
|
-
break
|
|
21
|
-
except importlib_metadata.PackageNotFoundError:
|
|
22
|
-
continue
|
|
17
|
+
release = run_path(
|
|
18
|
+
str(Path(__file__).resolve().parents[1] / "simind_python_connector/_version.py")
|
|
19
|
+
)["__version__"]
|
|
23
20
|
version = ".".join(release.split(".")[:2])
|
|
24
21
|
|
|
25
22
|
# General configuration
|
|
@@ -44,3 +44,24 @@ If you make changes that affect the documentation:
|
|
|
44
44
|
.. code-block:: bash
|
|
45
45
|
|
|
46
46
|
sphinx-build -b html docs docs/_build/html
|
|
47
|
+
|
|
48
|
+
Preparing a Release
|
|
49
|
+
-------------------
|
|
50
|
+
|
|
51
|
+
The version is defined once in ``simind_python_connector/_version.py``.
|
|
52
|
+
Package builds, ``simind_python_connector.__version__``, documentation and the
|
|
53
|
+
publishing workflow all read it directly.
|
|
54
|
+
|
|
55
|
+
Write the release notes for the next version in ``CHANGELOG.md`` and
|
|
56
|
+
``docs/changelog.rst``, then run:
|
|
57
|
+
|
|
58
|
+
.. code-block:: bash
|
|
59
|
+
|
|
60
|
+
bash scripts/release.sh patch
|
|
61
|
+
|
|
62
|
+
Use ``minor``, ``major`` or an exact version such as ``1.2.0`` instead of
|
|
63
|
+
``patch`` when appropriate. The script updates the shared version and the
|
|
64
|
+
Zenodo and citation metadata, including the citation release date, then creates
|
|
65
|
+
a local release commit and tag. Review your working tree first; the script also
|
|
66
|
+
commits the release notes. It prints the commands for pushing and publishing.
|
|
67
|
+
No other version values need editing by hand.
|
{simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/01_basic_simulation.py
RENAMED
|
@@ -48,10 +48,11 @@ def main() -> None:
|
|
|
48
48
|
connector.add_config_value(53, 0)
|
|
49
49
|
connector.set_energy_windows([126.0], [154.0], [0])
|
|
50
50
|
add_standard_runtime(connector, photon_multiplier=1, seed=12345, nuclide="tc99m")
|
|
51
|
+
connector.add_runtime_switch("CA", 1) # also write scatter and air projections
|
|
51
52
|
|
|
52
53
|
outputs = connector.run()
|
|
53
54
|
total = outputs["tot_w1"].projection
|
|
54
|
-
scatter = outputs
|
|
55
|
+
scatter = outputs["sca_w1"].projection
|
|
55
56
|
primary = np.clip(total - scatter, a_min=0.0, a_max=None)
|
|
56
57
|
|
|
57
58
|
np.save(output_dir / "total.npy", total)
|
|
@@ -47,6 +47,7 @@ def _run_case(
|
|
|
47
47
|
connector.add_config_value(53, 0)
|
|
48
48
|
connector.set_energy_windows([75.0], [225.0], [0])
|
|
49
49
|
add_standard_runtime(connector, photon_multiplier=1, seed=seed)
|
|
50
|
+
connector.add_runtime_switch("CA", 0) # total projections only
|
|
50
51
|
outputs = connector.run()
|
|
51
52
|
return outputs["tot_w1"].projection
|
|
52
53
|
|
{simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/docs/examples/03_multi_window.py
RENAMED
|
@@ -51,6 +51,7 @@ def main() -> None:
|
|
|
51
51
|
connector.set_energy_windows(lowers, uppers, orders)
|
|
52
52
|
connector.add_config_value(1, 208.0)
|
|
53
53
|
add_standard_runtime(connector, photon_multiplier=1, seed=12345, nuclide="lu177")
|
|
54
|
+
connector.add_runtime_switch("CA", 0) # total projections only
|
|
54
55
|
|
|
55
56
|
outputs = connector.run()
|
|
56
57
|
|
|
@@ -47,6 +47,10 @@ def _run_case(
|
|
|
47
47
|
connector.add_config_value(53, 1)
|
|
48
48
|
connector.set_energy_windows([75.0], [225.0], [0])
|
|
49
49
|
add_standard_runtime(connector, photon_multiplier=1, seed=12345)
|
|
50
|
+
# CA = 1 makes SCATTWIN write scatter and air projections; PENETRATE would
|
|
51
|
+
# drop its per-component outputs with it.
|
|
52
|
+
if scoring_routine == 1:
|
|
53
|
+
connector.add_runtime_switch("CA", 1)
|
|
50
54
|
|
|
51
55
|
results = connector.run()
|
|
52
56
|
return {key: value.projection for key, value in results.items()}
|
|
@@ -401,8 +405,8 @@ def main() -> None:
|
|
|
401
405
|
)
|
|
402
406
|
pen_outputs = _run_case(pen_dir, "pen_case01", source, mu_map, scoring_routine=4)
|
|
403
407
|
|
|
404
|
-
scatt_total = scatt_outputs
|
|
405
|
-
scatt_scatter = scatt_outputs
|
|
408
|
+
scatt_total = scatt_outputs["tot_w1"]
|
|
409
|
+
scatt_scatter = scatt_outputs["sca_w1"]
|
|
406
410
|
scatt_primary = np.clip(scatt_total - scatt_scatter, a_min=0.0, a_max=None)
|
|
407
411
|
scatt_primary_sum = float(scatt_primary.sum())
|
|
408
412
|
scatt_scatter_sum = float(scatt_scatter.sum())
|
|
@@ -177,6 +177,7 @@ def main() -> None:
|
|
|
177
177
|
adaptor.add_runtime_switch("CC", "ma-megp")
|
|
178
178
|
adaptor.add_runtime_switch("NN", 1)
|
|
179
179
|
adaptor.add_runtime_switch("RR", 12345)
|
|
180
|
+
adaptor.add_runtime_switch("CA", 0) # total projections only
|
|
180
181
|
adaptor.add_config_value(1, 140.0)
|
|
181
182
|
adaptor.add_config_value(19, 2)
|
|
182
183
|
adaptor.add_config_value(53, 0)
|
|
@@ -159,6 +159,7 @@ def main() -> None:
|
|
|
159
159
|
adaptor.add_runtime_switch("CC", "ma-megp")
|
|
160
160
|
adaptor.add_runtime_switch("NN", 1)
|
|
161
161
|
adaptor.add_runtime_switch("RR", 12345)
|
|
162
|
+
adaptor.add_runtime_switch("CA", 0) # total projections only
|
|
162
163
|
adaptor.add_config_value(1, 140.0)
|
|
163
164
|
adaptor.add_config_value(19, 2)
|
|
164
165
|
adaptor.add_config_value(53, 0)
|
|
@@ -127,6 +127,7 @@ def main() -> None:
|
|
|
127
127
|
adaptor.add_runtime_switch("CC", "ma-megp")
|
|
128
128
|
adaptor.add_runtime_switch("NN", 1)
|
|
129
129
|
adaptor.add_runtime_switch("RR", 12345)
|
|
130
|
+
adaptor.add_runtime_switch("CA", 0) # total projections only
|
|
130
131
|
adaptor.add_config_value(1, 140.0)
|
|
131
132
|
adaptor.add_config_value(19, 2)
|
|
132
133
|
adaptor.add_config_value(53, 0)
|
|
@@ -65,6 +65,16 @@ maintained by** the SIMIND project or Lund University.
|
|
|
65
65
|
SIMIND is **not** distributed with this package (or on PyPI) and must be
|
|
66
66
|
installed separately.
|
|
67
67
|
|
|
68
|
+
Supported SIMIND Versions
|
|
69
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
70
|
+
|
|
71
|
+
This release supports and is tested with **SIMIND V8.0**.
|
|
72
|
+
|
|
73
|
+
**SIMIND V9.0 is not supported yet.** V9 changes several output formats and
|
|
74
|
+
behaviours the connector relies on, so runs can fail or return incorrect
|
|
75
|
+
projections. V9 support will follow in a later release; until then, use
|
|
76
|
+
SIMIND V8.0.
|
|
77
|
+
|
|
68
78
|
Use the official SIMIND resources for installation and manual/reference
|
|
69
79
|
documentation:
|
|
70
80
|
|
|
@@ -29,14 +29,15 @@ Automatic Dependency Detection
|
|
|
29
29
|
|
|
30
30
|
The test suite automatically detects available dependencies:
|
|
31
31
|
|
|
32
|
-
* **SIRF detection**: Attempts to ``import sirf``
|
|
32
|
+
* **SIRF detection**: Attempts to ``import sirf.STIR``
|
|
33
33
|
* **STIR detection**: Attempts to ``import stir``, then imports the STIR
|
|
34
34
|
conversion helpers the way the package itself does (``stir.extra`` preferred,
|
|
35
35
|
the legacy ``stirextra`` module only as a fallback), so a broken
|
|
36
36
|
``stir.extra`` dependency is reported as unavailable instead of being masked
|
|
37
37
|
by the legacy module
|
|
38
38
|
* **PyTomography detection**: Attempts to ``import pytomography``
|
|
39
|
-
* **SIMIND detection**:
|
|
39
|
+
* **SIMIND detection**: Uses ``$SIMIND_BIN`` when set, otherwise looks for
|
|
40
|
+
``simind`` on ``PATH``
|
|
40
41
|
* **CI detection**: Checks ``CI`` or ``GITHUB_ACTIONS`` environment variables
|
|
41
42
|
|
|
42
43
|
Tests requiring unavailable dependencies are automatically skipped with informative messages.
|
|
@@ -118,17 +119,6 @@ the official SIMIND site and manual:
|
|
|
118
119
|
The container suite includes ``tests/test_container_library_isolation.py``,
|
|
119
120
|
which asserts that each container can import only its target backend library.
|
|
120
121
|
|
|
121
|
-
Alternative CI Configuration
|
|
122
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
123
|
-
|
|
124
|
-
The dependency-exclusion selection lives in ``.github/workflows/tests.yml`` so it
|
|
125
|
-
applies to CI only; the default ``pytest`` run keeps every available test.
|
|
126
|
-
|
|
127
|
-
.. code-block:: bash
|
|
128
|
-
|
|
129
|
-
# Run only the CI-friendly selection locally
|
|
130
|
-
pytest -m "not integration and not requires_sirf and not requires_stir and not requires_simind and not requires_pytomography and not requires_cil and not requires_setr and not ci_skip"
|
|
131
|
-
|
|
132
122
|
Test Categories
|
|
133
123
|
---------------
|
|
134
124
|
|
|
@@ -140,8 +130,8 @@ The default CI job runs the tests that avoid heavyweight dependencies. These foc
|
|
|
140
130
|
* **Conversion maths** – ``tests/test_schneider_density.py`` exercises the HU-to-density pipelines.
|
|
141
131
|
* **Configuration & builders** – ``tests/test_simulation_config.py`` and ``tests/test_acquisition_builder_unit.py`` validate YAML/SMC handling plus Interfile header generation without a SIRF runtime.
|
|
142
132
|
* **Connector behavior** – ``tests/test_python_connector.py`` and ``tests/test_connector_backend_separation.py`` cover the connector-first API without requiring reconstruction packages.
|
|
143
|
-
* **Utility helpers** – ``tests/
|
|
144
|
-
* **Backend
|
|
133
|
+
* **Utility helpers** – ``tests/test_utils_small.py``, ``tests/test_interfile_parser.py``, and ``tests/test_interfile_numpy.py`` cover file parsing and small helper functions.
|
|
134
|
+
* **Backend dispatch** – ``tests/test_backends.py`` covers backend detection and dispatch with stand-in backends.
|
|
145
135
|
|
|
146
136
|
Backend-Dependent Suites
|
|
147
137
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
@@ -149,15 +139,16 @@ Backend-Dependent Suites
|
|
|
149
139
|
Tests that construct real STIR/SIRF/PyTomography objects carry dependency
|
|
150
140
|
markers and are skipped when those packages are unavailable. These include:
|
|
151
141
|
|
|
152
|
-
* ``tests/
|
|
142
|
+
* ``tests/test_native_geometry_real.py`` for native STIR/SIRF image geometry.
|
|
143
|
+
* ``tests/test_utils.py`` for phantom, image and acquisition helpers on SIRF and STIR.
|
|
153
144
|
* ``tests/test_pytomography_adaptor.py`` for PyTomography tensor and output adaptation.
|
|
154
|
-
* ``tests/test_arithmetic_operations.py`` and ``tests/
|
|
145
|
+
* ``tests/test_arithmetic_operations.py`` and ``tests/test_stir_backend_arithmetic.py`` for arithmetic on real backend objects.
|
|
155
146
|
|
|
156
147
|
SIMIND and Container Diagnostics
|
|
157
148
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
158
149
|
|
|
159
|
-
SIMIND-dependent tests use ``requires_simind`` and are skipped unless
|
|
160
|
-
|
|
150
|
+
SIMIND-dependent tests use ``requires_simind`` and are skipped unless SIMIND
|
|
151
|
+
is found. Container and geometry diagnostics include:
|
|
161
152
|
|
|
162
153
|
* ``tests/test_integration.py`` for full workflow checks.
|
|
163
154
|
* ``tests/test_container_library_isolation.py`` for backend container import isolation.
|
|
@@ -168,13 +159,6 @@ latter two are provided by ``docker/python/Dockerfile``, which installs MPICH
|
|
|
168
159
|
and exposes the ``libmpi.so.12``/``libmpifort.so.12`` names SIMIND links
|
|
169
160
|
against. They never run in GitHub CI because the SIMIND binary is not tracked.
|
|
170
161
|
|
|
171
|
-
Integration Test
|
|
172
|
-
~~~~~~~~~~~~~~~~
|
|
173
|
-
|
|
174
|
-
``tests/test_integration.py`` orchestrates a full example run and needs
|
|
175
|
-
external runtime dependencies. It is marked with dependency markers so it is
|
|
176
|
-
skipped in lightweight CI environments.
|
|
177
|
-
|
|
178
162
|
Configuration Files
|
|
179
163
|
-------------------
|
|
180
164
|
|
|
@@ -195,34 +179,19 @@ tests/conftest.py
|
|
|
195
179
|
Adding New Tests
|
|
196
180
|
----------------
|
|
197
181
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
import pytest
|
|
203
|
-
|
|
204
|
-
@pytest.mark.unit
|
|
205
|
-
def test_pure_python_logic():
|
|
206
|
-
"""Test that doesn't need external dependencies."""
|
|
207
|
-
assert True
|
|
182
|
+
Use ``unit`` for isolated behavior and ``integration`` for workflows involving
|
|
183
|
+
external systems. Add the relevant dependency markers whenever a test needs a
|
|
184
|
+
reconstruction library or SIMIND. The distribution build check runs once in
|
|
185
|
+
the CI build job, separately from the unit test matrix.
|
|
208
186
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
# ... test code
|
|
187
|
+
Assert observable results: array values and orientation, saved file contents,
|
|
188
|
+
metadata or a useful failure. Stub external I/O at the boundary when needed.
|
|
189
|
+
Tests that only check whether a function exists, repeat its implementation or
|
|
190
|
+
assert private storage details do not establish that a workflow works.
|
|
214
191
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
# ... test code that runs simind
|
|
219
|
-
|
|
220
|
-
@pytest.mark.requires_pytomography
|
|
221
|
-
def test_pytomography_path():
|
|
222
|
-
"""Test that uses PyTomography APIs."""
|
|
223
|
-
# ... test code that imports pytomography
|
|
224
|
-
|
|
225
|
-
This ensures your tests will be properly categorized and run in the appropriate environments.
|
|
192
|
+
SIMIND geometry comparisons use Flag 8 set to false for a repeatable initial
|
|
193
|
+
random state. Choose photon statistics to support the numerical tolerance;
|
|
194
|
+
setting ``RR`` alone does not make V8 simulations reproducible.
|
|
226
195
|
|
|
227
196
|
Continuous Integration
|
|
228
197
|
----------------------
|
|
@@ -234,5 +203,3 @@ GitHub Actions is used to run tests automatically. The CI workflow:
|
|
|
234
203
|
3. **Executes CI-friendly tests** using dependency markers
|
|
235
204
|
4. **Generates coverage reports** for the tested code
|
|
236
205
|
5. **Builds and validates the package**
|
|
237
|
-
|
|
238
|
-
This approach ensures reliable CI while maintaining comprehensive test coverage for local development.
|
|
@@ -61,12 +61,10 @@ SPECT header remains. Measured on a real SIMIND V8.0 run, 49 characters is the
|
|
|
61
61
|
exact maximum prefix for ``{prefix}_tot_w1.a00``; a 50-character prefix
|
|
62
62
|
truncates it. The 47-character cap is a conservative policy with a small margin
|
|
63
63
|
below that measured boundary, not an engine-measured limit. The longest
|
|
64
|
-
engine-written name adds a ``_tot_w{N}.a00`` suffix
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
uses the 60-character buffer exactly. To stay inside that budget, at most 99
|
|
69
|
-
energy windows are accepted; a larger set raises ``ValueError``.
|
|
64
|
+
engine-written name adds a ``_tot_w{N}.a00`` suffix. With at most 99 energy
|
|
65
|
+
windows this suffix is 12 characters long, leaving a margin inside the
|
|
66
|
+
60-character buffer. Window files contain exactly the requested windows;
|
|
67
|
+
more than 99 windows raises ``ValueError``.
|
|
70
68
|
|
|
71
69
|
``RuntimeOperator`` carries per-run switches, an orbit file and an optional
|
|
72
70
|
timeout in seconds. A run that exceeds the timeout stops and raises
|
|
@@ -116,6 +114,11 @@ supported by the Interfile connector. LIST_MODE (2) and FORCED_COLLIMATION (3)
|
|
|
116
114
|
write outputs the connector cannot read, so they are rejected at preflight;
|
|
117
115
|
they remain available through lower-level use of the package.
|
|
118
116
|
|
|
117
|
+
For repeatable diagnostic runs on SIMIND V8, set
|
|
118
|
+
``connector.get_config().set_flag(8, False)`` to reuse the same initial random
|
|
119
|
+
state. The bundled configurations enable Flag 8 for independent simulations.
|
|
120
|
+
The ``RR`` switch alone does not make repeated runs reproducible.
|
|
121
|
+
|
|
119
122
|
A literal 1x1x1 voxel phantom is rejected (SIMIND does not support it), so pad
|
|
120
123
|
the source and mu map to at least two voxels in one dimension. A non-zero
|
|
121
124
|
source that ``quantization_scale`` rounds to all zeros is also rejected;
|
|
@@ -136,12 +139,28 @@ Adaptor Workflows
|
|
|
136
139
|
Use adaptors when you want connector-managed SIMIND execution plus native
|
|
137
140
|
objects for a target reconstruction package.
|
|
138
141
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
``
|
|
142
|
+
Enabling ``keep_all_views_in_cache`` in SIRF/STIR can cause memory errors on
|
|
143
|
+
large acquisitions. Disable it if view caching exhausts available memory.
|
|
144
|
+
|
|
145
|
+
With the SCATTWIN scoring routine, SIMIND V8 writes only the total projection
|
|
146
|
+
unless the ``CA`` runtime switch asks for more: ``CA`` = 1 adds scatter
|
|
147
|
+
(``sca``) and air (``air``) projections, ``CA`` = 2 adds primary (``pri``),
|
|
148
|
+
scatter and air projections. A SCATTWIN run without ``CA`` issues a
|
|
149
|
+
``UserWarning``; set ``CA`` = 0 to keep total-only output without it.
|
|
150
|
+
|
|
151
|
+
Keep energy-window scatter orders at 0 unless you need SIMIND's per-order
|
|
152
|
+
behaviour. On V8, a window with scatter order above 0 produces only
|
|
153
|
+
``sca_wN`` (no ``tot_wN``), and its presence makes SIMIND also write ``sca``
|
|
154
|
+
and ``air`` for the order-0 windows whatever ``CA`` is set to.
|
|
155
|
+
|
|
156
|
+
.. code-block:: python
|
|
157
|
+
|
|
158
|
+
adaptor.add_runtime_switch("CA", 1)
|
|
159
|
+
|
|
160
|
+
``get_scatter_output()`` and ``get_primary_output()`` return the written
|
|
161
|
+
projection, or the total minus the other one when only that was written
|
|
162
|
+
(``tot = pri + sca``). When neither was written they warn and return ``None``.
|
|
163
|
+
Before a successful run they raise ``RuntimeError``.
|
|
145
164
|
|
|
146
165
|
STIR adaptor
|
|
147
166
|
~~~~~~~~~~~~
|
{simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/01_basic_simulation.py
RENAMED
|
@@ -48,10 +48,11 @@ def main() -> None:
|
|
|
48
48
|
connector.add_config_value(53, 0)
|
|
49
49
|
connector.set_energy_windows([126.0], [154.0], [0])
|
|
50
50
|
add_standard_runtime(connector, photon_multiplier=1, seed=12345, nuclide="tc99m")
|
|
51
|
+
connector.add_runtime_switch("CA", 1) # also write scatter and air projections
|
|
51
52
|
|
|
52
53
|
outputs = connector.run()
|
|
53
54
|
total = outputs["tot_w1"].projection
|
|
54
|
-
scatter = outputs
|
|
55
|
+
scatter = outputs["sca_w1"].projection
|
|
55
56
|
primary = np.clip(total - scatter, a_min=0.0, a_max=None)
|
|
56
57
|
|
|
57
58
|
np.save(output_dir / "total.npy", total)
|
|
@@ -47,6 +47,7 @@ def _run_case(
|
|
|
47
47
|
connector.add_config_value(53, 0)
|
|
48
48
|
connector.set_energy_windows([75.0], [225.0], [0])
|
|
49
49
|
add_standard_runtime(connector, photon_multiplier=1, seed=seed)
|
|
50
|
+
connector.add_runtime_switch("CA", 0) # total projections only
|
|
50
51
|
outputs = connector.run()
|
|
51
52
|
return outputs["tot_w1"].projection
|
|
52
53
|
|
|
@@ -51,6 +51,7 @@ def main() -> None:
|
|
|
51
51
|
connector.set_energy_windows(lowers, uppers, orders)
|
|
52
52
|
connector.add_config_value(1, 208.0)
|
|
53
53
|
add_standard_runtime(connector, photon_multiplier=1, seed=12345, nuclide="lu177")
|
|
54
|
+
connector.add_runtime_switch("CA", 0) # total projections only
|
|
54
55
|
|
|
55
56
|
outputs = connector.run()
|
|
56
57
|
|
|
@@ -47,6 +47,10 @@ def _run_case(
|
|
|
47
47
|
connector.add_config_value(53, 1)
|
|
48
48
|
connector.set_energy_windows([75.0], [225.0], [0])
|
|
49
49
|
add_standard_runtime(connector, photon_multiplier=1, seed=12345)
|
|
50
|
+
# CA = 1 makes SCATTWIN write scatter and air projections; PENETRATE would
|
|
51
|
+
# drop its per-component outputs with it.
|
|
52
|
+
if scoring_routine == 1:
|
|
53
|
+
connector.add_runtime_switch("CA", 1)
|
|
50
54
|
|
|
51
55
|
results = connector.run()
|
|
52
56
|
return {key: value.projection for key, value in results.items()}
|
|
@@ -401,8 +405,8 @@ def main() -> None:
|
|
|
401
405
|
)
|
|
402
406
|
pen_outputs = _run_case(pen_dir, "pen_case01", source, mu_map, scoring_routine=4)
|
|
403
407
|
|
|
404
|
-
scatt_total = scatt_outputs
|
|
405
|
-
scatt_scatter = scatt_outputs
|
|
408
|
+
scatt_total = scatt_outputs["tot_w1"]
|
|
409
|
+
scatt_scatter = scatt_outputs["sca_w1"]
|
|
406
410
|
scatt_primary = np.clip(scatt_total - scatt_scatter, a_min=0.0, a_max=None)
|
|
407
411
|
scatt_primary_sum = float(scatt_primary.sum())
|
|
408
412
|
scatt_scatter_sum = float(scatt_scatter.sum())
|
{simind_python_connector-1.1.2 → simind_python_connector-1.2.0}/examples/07A_stir_adaptor_osem.py
RENAMED
|
@@ -177,6 +177,7 @@ def main() -> None:
|
|
|
177
177
|
adaptor.add_runtime_switch("CC", "ma-megp")
|
|
178
178
|
adaptor.add_runtime_switch("NN", 1)
|
|
179
179
|
adaptor.add_runtime_switch("RR", 12345)
|
|
180
|
+
adaptor.add_runtime_switch("CA", 0) # total projections only
|
|
180
181
|
adaptor.add_config_value(1, 140.0)
|
|
181
182
|
adaptor.add_config_value(19, 2)
|
|
182
183
|
adaptor.add_config_value(53, 0)
|
|
@@ -159,6 +159,7 @@ def main() -> None:
|
|
|
159
159
|
adaptor.add_runtime_switch("CC", "ma-megp")
|
|
160
160
|
adaptor.add_runtime_switch("NN", 1)
|
|
161
161
|
adaptor.add_runtime_switch("RR", 12345)
|
|
162
|
+
adaptor.add_runtime_switch("CA", 0) # total projections only
|
|
162
163
|
adaptor.add_config_value(1, 140.0)
|
|
163
164
|
adaptor.add_config_value(19, 2)
|
|
164
165
|
adaptor.add_config_value(53, 0)
|
|
@@ -127,6 +127,7 @@ def main() -> None:
|
|
|
127
127
|
adaptor.add_runtime_switch("CC", "ma-megp")
|
|
128
128
|
adaptor.add_runtime_switch("NN", 1)
|
|
129
129
|
adaptor.add_runtime_switch("RR", 12345)
|
|
130
|
+
adaptor.add_runtime_switch("CA", 0) # total projections only
|
|
130
131
|
adaptor.add_config_value(1, 140.0)
|
|
131
132
|
adaptor.add_config_value(19, 2)
|
|
132
133
|
adaptor.add_config_value(53, 0)
|