simind-python-connector 2.0.0__tar.gz → 3.0.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-2.0.0 → simind_python_connector-3.0.0}/MANIFEST.in +0 -2
- {simind_python_connector-2.0.0/simind_python_connector.egg-info → simind_python_connector-3.0.0}/PKG-INFO +10 -5
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/README.md +4 -2
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/api.rst +32 -12
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/backends.rst +0 -28
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/changelog.rst +28 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/conf.py +2 -2
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/04_custom_config.py +4 -39
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0/docs}/examples/06_schneider_density_conversion.py +1 -20
- simind_python_connector-3.0.0/docs/examples/09_mc_scatter_osem.py +89 -0
- simind_python_connector-3.0.0/docs/examples/10_mc_scatter_cil.py +103 -0
- simind_python_connector-3.0.0/docs/examples/11_residual_correction.py +154 -0
- simind_python_connector-3.0.0/docs/examples/12_phantoms.py +79 -0
- simind_python_connector-3.0.0/docs/examples/_mc_scatter_common.py +199 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples.rst +30 -0
- simind_python_connector-3.0.0/docs/geometry.rst +135 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/index.rst +16 -3
- simind_python_connector-3.0.0/docs/normalisation.rst +86 -0
- simind_python_connector-3.0.0/docs/phantoms.rst +122 -0
- simind_python_connector-3.0.0/docs/reconstruction.rst +266 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/testing.rst +7 -18
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/04_custom_config.py +4 -39
- {simind_python_connector-2.0.0/docs → simind_python_connector-3.0.0}/examples/06_schneider_density_conversion.py +1 -20
- simind_python_connector-3.0.0/examples/09_mc_scatter_osem.py +89 -0
- simind_python_connector-3.0.0/examples/10_mc_scatter_cil.py +103 -0
- simind_python_connector-3.0.0/examples/11_residual_correction.py +154 -0
- simind_python_connector-3.0.0/examples/12_phantoms.py +79 -0
- simind_python_connector-3.0.0/examples/_mc_scatter_common.py +199 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/pyproject.toml +26 -5
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/__init__.py +3 -3
- simind_python_connector-3.0.0/simind_python_connector/builders/_native.py +86 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/builders/acquisition_builder.py +21 -81
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/builders/image_builder.py +13 -72
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/configs/__init__.py +10 -4
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/connectors/__init__.py +0 -2
- simind_python_connector-3.0.0/simind_python_connector/connectors/_native_adaptor.py +354 -0
- simind_python_connector-3.0.0/simind_python_connector/connectors/python_connector.py +970 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/connectors/pytomography_adaptor.py +26 -23
- simind_python_connector-3.0.0/simind_python_connector/connectors/sirf_adaptor.py +43 -0
- simind_python_connector-3.0.0/simind_python_connector/connectors/stir_adaptor.py +45 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/converters/__init__.py +2 -2
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/converters/attenuation.py +42 -48
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/converters/simind_to_stir.py +16 -328
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/core/config.py +65 -25
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/core/executor.py +42 -50
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/core/types.py +5 -24
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/data/__init__.py +3 -3
- simind_python_connector-3.0.0/simind_python_connector/data/bone.atn +178 -0
- simind_python_connector-3.0.0/simind_python_connector/data/h2o.atn +84 -0
- simind_python_connector-3.0.0/simind_python_connector/normalisation.py +90 -0
- simind_python_connector-3.0.0/simind_python_connector/phantoms.py +386 -0
- simind_python_connector-3.0.0/simind_python_connector/recon/__init__.py +41 -0
- simind_python_connector-3.0.0/simind_python_connector/recon/cil.py +185 -0
- simind_python_connector-3.0.0/simind_python_connector/recon/corrections.py +108 -0
- simind_python_connector-3.0.0/simind_python_connector/recon/diagnostics.py +41 -0
- simind_python_connector-3.0.0/simind_python_connector/recon/osem.py +59 -0
- simind_python_connector-3.0.0/simind_python_connector/recon/projector.py +112 -0
- simind_python_connector-3.0.0/simind_python_connector/recon/updates.py +88 -0
- simind_python_connector-3.0.0/simind_python_connector/utils/__init__.py +45 -0
- simind_python_connector-3.0.0/simind_python_connector/utils/interfile.py +659 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/utils/simind_utils.py +4 -32
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0/simind_python_connector.egg-info}/PKG-INFO +10 -5
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector.egg-info/SOURCES.txt +56 -24
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector.egg-info/requires.txt +4 -0
- simind_python_connector-3.0.0/tests/conftest.py +36 -0
- simind_python_connector-3.0.0/tests/recon/__init__.py +0 -0
- simind_python_connector-3.0.0/tests/recon/conftest.py +138 -0
- simind_python_connector-3.0.0/tests/recon/fakes.py +93 -0
- simind_python_connector-3.0.0/tests/recon/test_cil_functions.py +46 -0
- simind_python_connector-3.0.0/tests/recon/test_cil_sirf.py +229 -0
- simind_python_connector-3.0.0/tests/recon/test_corrections.py +71 -0
- simind_python_connector-3.0.0/tests/recon/test_diagnostics.py +60 -0
- simind_python_connector-3.0.0/tests/recon/test_import_boundary.py +90 -0
- simind_python_connector-3.0.0/tests/recon/test_osem_sirf.py +113 -0
- simind_python_connector-3.0.0/tests/recon/test_projector.py +153 -0
- simind_python_connector-3.0.0/tests/recon/test_residual.py +77 -0
- simind_python_connector-3.0.0/tests/recon/test_residual_cil.py +52 -0
- simind_python_connector-3.0.0/tests/recon/test_residual_sirf.py +87 -0
- simind_python_connector-3.0.0/tests/recon/test_updates.py +146 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_acquisition_builder_unit.py +23 -40
- simind_python_connector-3.0.0/tests/test_attenuation_utils.py +68 -0
- simind_python_connector-3.0.0/tests/test_builders_lifetime.py +59 -0
- simind_python_connector-3.0.0/tests/test_builders_native.py +148 -0
- simind_python_connector-3.0.0/tests/test_configure_phantom.py +376 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_connector_backend_separation.py +0 -22
- simind_python_connector-3.0.0/tests/test_container_scripts.py +497 -0
- simind_python_connector-3.0.0/tests/test_converter_golden.py +128 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_dicom_builder.py +4 -3
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_examples_backend_separation.py +17 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_executor.py +68 -7
- simind_python_connector-3.0.0/tests/test_ground_truth_sirf.py +38 -0
- simind_python_connector-3.0.0/tests/test_image_builder_unit.py +71 -0
- simind_python_connector-3.0.0/tests/test_import_side_effects.py +55 -0
- simind_python_connector-3.0.0/tests/test_interfile.py +1178 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_marker_policy.py +2 -23
- simind_python_connector-3.0.0/tests/test_measured_geometry_simind.py +208 -0
- simind_python_connector-3.0.0/tests/test_native_adaptors.py +764 -0
- simind_python_connector-3.0.0/tests/test_nema_phantom.py +95 -0
- simind_python_connector-3.0.0/tests/test_normalisation.py +98 -0
- simind_python_connector-3.0.0/tests/test_phantoms.py +102 -0
- simind_python_connector-3.0.0/tests/test_phantoms_simind.py +246 -0
- simind_python_connector-3.0.0/tests/test_python_connector.py +1434 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_pytomography_adaptor.py +92 -2
- simind_python_connector-3.0.0/tests/test_runtime_switches.py +175 -0
- simind_python_connector-3.0.0/tests/test_simind_mpi.py +29 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_simind_to_stir_converter.py +22 -31
- simind_python_connector-3.0.0/tests/test_template_geometry_sirf.py +285 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_utils_small.py +1 -29
- simind_python_connector-3.0.0/tests/test_voxelise.py +130 -0
- simind_python_connector-2.0.0/docs/connector_modernization_plan.rst +0 -45
- simind_python_connector-2.0.0/docs/geometry.rst +0 -64
- simind_python_connector-2.0.0/requirements-dev.txt +0 -23
- simind_python_connector-2.0.0/requirements.txt +0 -10
- simind_python_connector-2.0.0/simind_python_connector/backends/__init__.py +0 -487
- simind_python_connector-2.0.0/simind_python_connector/backends/base.py +0 -387
- simind_python_connector-2.0.0/simind_python_connector/backends/sirf_backend.py +0 -309
- simind_python_connector-2.0.0/simind_python_connector/backends/stir_backend.py +0 -395
- simind_python_connector-2.0.0/simind_python_connector/connectors/_spacing.py +0 -75
- simind_python_connector-2.0.0/simind_python_connector/connectors/python_connector.py +0 -447
- simind_python_connector-2.0.0/simind_python_connector/connectors/sirf_adaptor.py +0 -167
- simind_python_connector-2.0.0/simind_python_connector/connectors/stir_adaptor.py +0 -167
- simind_python_connector-2.0.0/simind_python_connector/converters/dicom_to_stir.py +0 -3
- simind_python_connector-2.0.0/simind_python_connector/data/bone.atn +0 -187
- simind_python_connector-2.0.0/simind_python_connector/data/h2o.atn +0 -92
- simind_python_connector-2.0.0/simind_python_connector/utils/__init__.py +0 -120
- simind_python_connector-2.0.0/simind_python_connector/utils/backend_access.py +0 -121
- simind_python_connector-2.0.0/simind_python_connector/utils/import_helpers.py +0 -78
- simind_python_connector-2.0.0/simind_python_connector/utils/interfile_numpy.py +0 -205
- simind_python_connector-2.0.0/simind_python_connector/utils/interfile_parser.py +0 -177
- simind_python_connector-2.0.0/simind_python_connector/utils/io_utils.py +0 -14
- simind_python_connector-2.0.0/simind_python_connector/utils/sirf_stir_utils.py +0 -194
- simind_python_connector-2.0.0/simind_python_connector/utils/stir_utils.py +0 -490
- simind_python_connector-2.0.0/tests/conftest.py +0 -128
- simind_python_connector-2.0.0/tests/test_arithmetic_operations.py +0 -106
- simind_python_connector-2.0.0/tests/test_attenuation_utils.py +0 -116
- simind_python_connector-2.0.0/tests/test_backends.py +0 -367
- simind_python_connector-2.0.0/tests/test_container_scripts.py +0 -290
- simind_python_connector-2.0.0/tests/test_image_builder_unit.py +0 -113
- simind_python_connector-2.0.0/tests/test_interfile_numpy.py +0 -295
- simind_python_connector-2.0.0/tests/test_interfile_parser.py +0 -41
- simind_python_connector-2.0.0/tests/test_native_adaptors.py +0 -485
- simind_python_connector-2.0.0/tests/test_python_connector.py +0 -615
- simind_python_connector-2.0.0/tests/test_sirf_stir_utils.py +0 -56
- simind_python_connector-2.0.0/tests/test_stir_utils_backend_choice_unit.py +0 -78
- simind_python_connector-2.0.0/tests/test_utils.py +0 -134
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/LICENSE +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/contributing.rst +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/01_basic_simulation.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/02_runtime_switch_comparison.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/03_multi_window.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/05_scattwin_vs_penetrate_comparison.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/07A_stir_adaptor_osem.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/07B_sirf_adaptor_osem.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/07C_pytomography_adaptor_osem.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/08A_stir_adaptor_from_dicom.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/08B_sirf_adaptor_from_dicom.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/08C_pytomography_adaptor_from_dicom.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/_python_connector_helpers.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/installation.rst +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/intro.rst +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/usage.rst +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/01_basic_simulation.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/02_runtime_switch_comparison.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/03_multi_window.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/05_scattwin_vs_penetrate_comparison.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/07A_stir_adaptor_osem.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/07B_sirf_adaptor_osem.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/07C_pytomography_adaptor_osem.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/08A_stir_adaptor_from_dicom.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/08B_sirf_adaptor_from_dicom.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/08C_pytomography_adaptor_from_dicom.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/examples/_python_connector_helpers.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/setup.cfg +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/builders/__init__.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/configs/AnyScan.yaml +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/configs/Discovery670.yaml +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/configs/Example.yaml +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/configs/MLD001_SCAN0.yaml +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/configs/input.smc +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/connectors/base.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/core/__init__.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector/data/Schneider2000.json +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector.egg-info/dependency_links.txt +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/simind_python_connector.egg-info/top_level.txt +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/__init__.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_connectors_base.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_container_library_isolation.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_example_config_profile.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_geometry_isolation_forward_projection.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_integration.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_legacy_surface_policy.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_osem_geometry_diagnostics.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_package_identity.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_packaging_resources.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_schneider_density.py +0 -0
- {simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/tests/test_simulation_config.py +0 -0
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
include README.md
|
|
2
2
|
include LICENSE
|
|
3
|
-
include requirements.txt
|
|
4
|
-
include requirements-dev.txt
|
|
5
3
|
recursive-include simind_python_connector/data *.atn
|
|
6
4
|
recursive-include simind_python_connector/data *.json
|
|
7
5
|
recursive-include simind_python_connector/configs *.smc *.yaml
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simind-python-connector
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.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>
|
|
@@ -15,11 +15,11 @@ Classifier: Development Status :: 4 - Beta
|
|
|
15
15
|
Classifier: Intended Audience :: Science/Research
|
|
16
16
|
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
17
17
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
-
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
25
|
Requires-Dist: numpy>=1.20.0
|
|
@@ -29,6 +29,7 @@ Provides-Extra: dev
|
|
|
29
29
|
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
30
30
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
31
31
|
Requires-Dist: pytest-mock; extra == "dev"
|
|
32
|
+
Requires-Dist: scipy; extra == "dev"
|
|
32
33
|
Requires-Dist: ruff; extra == "dev"
|
|
33
34
|
Requires-Dist: sphinx; extra == "dev"
|
|
34
35
|
Requires-Dist: sphinx-rtd-theme; extra == "dev"
|
|
@@ -39,6 +40,8 @@ Requires-Dist: build; extra == "dev"
|
|
|
39
40
|
Requires-Dist: twine; extra == "dev"
|
|
40
41
|
Provides-Extra: examples
|
|
41
42
|
Requires-Dist: matplotlib>=3.0.0; extra == "examples"
|
|
43
|
+
Provides-Extra: recon
|
|
44
|
+
Requires-Dist: scipy; extra == "recon"
|
|
42
45
|
Dynamic: license-file
|
|
43
46
|
|
|
44
47
|
# simind-python-connector
|
|
@@ -48,7 +51,7 @@ Python SIMIND Monte Carlo Connector.
|
|
|
48
51
|
[](https://github.com/samdporter/simind-python-connector/actions)
|
|
49
52
|
[](https://simind-python-connector.readthedocs.io/en/latest/?badge=latest)
|
|
50
53
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
51
|
-
[](https://www.python.org/downloads/)
|
|
52
55
|
|
|
53
56
|
A Python toolkit that lets you run SIMIND from Python and use the outputs in
|
|
54
57
|
common reconstruction ecosystems (STIR, SIRF, PyTomography).
|
|
@@ -66,6 +69,7 @@ install a licensed SIMIND installation.
|
|
|
66
69
|
- [Full Documentation](https://simind-python-connector.readthedocs.io/)
|
|
67
70
|
- [Installation](https://simind-python-connector.readthedocs.io/en/latest/installation.html)
|
|
68
71
|
- [Backend Support](https://simind-python-connector.readthedocs.io/en/latest/backends.html) - adaptor dependency matrix
|
|
72
|
+
- [Reconstruction with SIMIND corrections](https://simind-python-connector.readthedocs.io/en/latest/reconstruction.html)
|
|
69
73
|
|
|
70
74
|
## What This Package Does
|
|
71
75
|
1. Runs SIMIND from Python with a minimal, explicit API.
|
|
@@ -75,6 +79,7 @@ install a licensed SIMIND installation.
|
|
|
75
79
|
- **Connector-first API** - `SimindPythonConnector` for direct SIMIND execution from Python
|
|
76
80
|
- **Package Adaptors** - STIR/SIRF/PyTomography adaptors for reconstruction workflows
|
|
77
81
|
- **Native reconstruction workflows** - Use STIR/SIRF/PyTomography reconstruction tools with generated SIMIND data
|
|
82
|
+
- **Reconstruction with SIMIND corrections (optional)** - `simind_python_connector.recon`: Monte Carlo scatter and Fu & Qi residual correction in SIRF OSEM and CIL algorithms
|
|
78
83
|
- **Dual scoring support** - SCATTWIN and PENETRATE
|
|
79
84
|
- **DICOM builders** - DICOM-driven setup utilities for scanner/input preparation
|
|
80
85
|
- **Advanced Schneider2000 density conversion** - 44-segment HU-to-density mapping
|
|
@@ -116,7 +121,7 @@ Install from conda:
|
|
|
116
121
|
conda install -c conda-forge stir "numpy<2.0"
|
|
117
122
|
```
|
|
118
123
|
|
|
119
|
-
**
|
|
124
|
+
**Note**: If STIR from conda-forge fails with NumPy binary-compatibility errors, install `numpy<2`.
|
|
120
125
|
|
|
121
126
|
Or build from source:
|
|
122
127
|
```bash
|
|
@@ -5,7 +5,7 @@ Python SIMIND Monte Carlo Connector.
|
|
|
5
5
|
[](https://github.com/samdporter/simind-python-connector/actions)
|
|
6
6
|
[](https://simind-python-connector.readthedocs.io/en/latest/?badge=latest)
|
|
7
7
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
8
|
-
[](https://www.python.org/downloads/)
|
|
9
9
|
|
|
10
10
|
A Python toolkit that lets you run SIMIND from Python and use the outputs in
|
|
11
11
|
common reconstruction ecosystems (STIR, SIRF, PyTomography).
|
|
@@ -23,6 +23,7 @@ install a licensed SIMIND installation.
|
|
|
23
23
|
- [Full Documentation](https://simind-python-connector.readthedocs.io/)
|
|
24
24
|
- [Installation](https://simind-python-connector.readthedocs.io/en/latest/installation.html)
|
|
25
25
|
- [Backend Support](https://simind-python-connector.readthedocs.io/en/latest/backends.html) - adaptor dependency matrix
|
|
26
|
+
- [Reconstruction with SIMIND corrections](https://simind-python-connector.readthedocs.io/en/latest/reconstruction.html)
|
|
26
27
|
|
|
27
28
|
## What This Package Does
|
|
28
29
|
1. Runs SIMIND from Python with a minimal, explicit API.
|
|
@@ -32,6 +33,7 @@ install a licensed SIMIND installation.
|
|
|
32
33
|
- **Connector-first API** - `SimindPythonConnector` for direct SIMIND execution from Python
|
|
33
34
|
- **Package Adaptors** - STIR/SIRF/PyTomography adaptors for reconstruction workflows
|
|
34
35
|
- **Native reconstruction workflows** - Use STIR/SIRF/PyTomography reconstruction tools with generated SIMIND data
|
|
36
|
+
- **Reconstruction with SIMIND corrections (optional)** - `simind_python_connector.recon`: Monte Carlo scatter and Fu & Qi residual correction in SIRF OSEM and CIL algorithms
|
|
35
37
|
- **Dual scoring support** - SCATTWIN and PENETRATE
|
|
36
38
|
- **DICOM builders** - DICOM-driven setup utilities for scanner/input preparation
|
|
37
39
|
- **Advanced Schneider2000 density conversion** - 44-segment HU-to-density mapping
|
|
@@ -73,7 +75,7 @@ Install from conda:
|
|
|
73
75
|
conda install -c conda-forge stir "numpy<2.0"
|
|
74
76
|
```
|
|
75
77
|
|
|
76
|
-
**
|
|
78
|
+
**Note**: If STIR from conda-forge fails with NumPy binary-compatibility errors, install `numpy<2`.
|
|
77
79
|
|
|
78
80
|
Or build from source:
|
|
79
81
|
```bash
|
|
@@ -60,35 +60,55 @@ Converters
|
|
|
60
60
|
:undoc-members:
|
|
61
61
|
:show-inheritance:
|
|
62
62
|
|
|
63
|
-
.. automodule:: simind_python_connector.converters.
|
|
63
|
+
.. automodule:: simind_python_connector.converters.simind_to_stir
|
|
64
64
|
:members:
|
|
65
65
|
:undoc-members:
|
|
66
66
|
:show-inheritance:
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
Normalisation
|
|
69
|
+
-------------
|
|
70
|
+
|
|
71
|
+
.. automodule:: simind_python_connector.normalisation
|
|
69
72
|
:members:
|
|
70
73
|
:undoc-members:
|
|
71
74
|
:show-inheritance:
|
|
72
75
|
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
Reconstruction with SIMIND corrections
|
|
77
|
+
--------------------------------------
|
|
75
78
|
|
|
76
|
-
.. automodule:: simind_python_connector.
|
|
79
|
+
.. automodule:: simind_python_connector.recon.updates
|
|
77
80
|
:members:
|
|
78
|
-
:undoc-members:
|
|
79
|
-
:show-inheritance:
|
|
80
81
|
|
|
81
|
-
.. automodule:: simind_python_connector.
|
|
82
|
+
.. automodule:: simind_python_connector.recon.projector
|
|
82
83
|
:members:
|
|
83
|
-
:undoc-members:
|
|
84
|
-
:show-inheritance:
|
|
85
84
|
|
|
86
|
-
.. automodule:: simind_python_connector.
|
|
85
|
+
.. automodule:: simind_python_connector.recon.corrections
|
|
86
|
+
:members:
|
|
87
|
+
|
|
88
|
+
.. automodule:: simind_python_connector.recon.cil
|
|
89
|
+
:members:
|
|
90
|
+
|
|
91
|
+
.. automodule:: simind_python_connector.recon.osem
|
|
92
|
+
:members:
|
|
93
|
+
|
|
94
|
+
.. automodule:: simind_python_connector.recon.diagnostics
|
|
95
|
+
:members:
|
|
96
|
+
|
|
97
|
+
Phantoms
|
|
98
|
+
--------
|
|
99
|
+
|
|
100
|
+
.. automodule:: simind_python_connector.phantoms
|
|
101
|
+
:members:
|
|
102
|
+
|
|
103
|
+
Utilities
|
|
104
|
+
---------
|
|
105
|
+
|
|
106
|
+
.. automodule:: simind_python_connector.utils.simind_utils
|
|
87
107
|
:members:
|
|
88
108
|
:undoc-members:
|
|
89
109
|
:show-inheritance:
|
|
90
110
|
|
|
91
|
-
.. automodule:: simind_python_connector.utils.
|
|
111
|
+
.. automodule:: simind_python_connector.utils.interfile
|
|
92
112
|
:members:
|
|
93
113
|
:undoc-members:
|
|
94
114
|
:show-inheritance:
|
|
@@ -26,31 +26,3 @@ The adaptors are responsible for converting input/output object types across
|
|
|
26
26
|
package boundaries. Reconstruction-system objects (for example, a PyTomography
|
|
27
27
|
system matrix) should be created directly in the target package.
|
|
28
28
|
|
|
29
|
-
Backend Abstraction Module
|
|
30
|
-
--------------------------
|
|
31
|
-
|
|
32
|
-
The ``simind_python_connector.backends`` module provides optional helper APIs for
|
|
33
|
-
working with SIRF/STIR image and acquisition wrapper objects.
|
|
34
|
-
|
|
35
|
-
Quick example:
|
|
36
|
-
|
|
37
|
-
.. code-block:: python
|
|
38
|
-
|
|
39
|
-
from simind_python_connector.backends import get_backend, set_backend
|
|
40
|
-
|
|
41
|
-
backend = get_backend() # auto-detect: "sirf" or "stir"
|
|
42
|
-
print(f"Using backend: {backend}")
|
|
43
|
-
|
|
44
|
-
# Optional explicit override
|
|
45
|
-
set_backend("stir")
|
|
46
|
-
|
|
47
|
-
Main helper functions include:
|
|
48
|
-
|
|
49
|
-
- ``get_backend()``
|
|
50
|
-
- ``set_backend(backend)``
|
|
51
|
-
- ``reset_backend()``
|
|
52
|
-
- ``create_image_data(...)``
|
|
53
|
-
- ``create_acquisition_data(...)``
|
|
54
|
-
- ``unwrap(...)``
|
|
55
|
-
|
|
56
|
-
These helpers are independent from the connector/adaptor execution API.
|
|
@@ -7,6 +7,34 @@ 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
|
+
3.0.0 - 2026-10-09
|
|
11
|
+
------------------
|
|
12
|
+
|
|
13
|
+
Breaking Changes
|
|
14
|
+
~~~~~~~~~~~~~~~~
|
|
15
|
+
|
|
16
|
+
- Python 3.10 or newer is required.
|
|
17
|
+
- Removed the backend wrappers and legacy Interfile and STIR utility modules.
|
|
18
|
+
Use the native adaptors and ``simind_python_connector.utils.interfile``.
|
|
19
|
+
- Photon-history scaling and runtime switches now reject invalid values.
|
|
20
|
+
|
|
21
|
+
Added
|
|
22
|
+
~~~~~
|
|
23
|
+
|
|
24
|
+
- Measured acquisition geometry, activity scaling, anisotropic voxel maps and
|
|
25
|
+
SIMIND MPI execution.
|
|
26
|
+
- Analytic and library phantoms, voxelisation and native adaptor ground truth.
|
|
27
|
+
- Optional SIMIND scatter and residual corrections for SIRF and CIL workflows.
|
|
28
|
+
|
|
29
|
+
Fixed
|
|
30
|
+
~~~~~
|
|
31
|
+
|
|
32
|
+
- PyTomography image-axis conversions reverse z slices to match its SIMIND
|
|
33
|
+
reader. Source and attenuation maps now agree with native tensor slice order.
|
|
34
|
+
- Added asymmetric real-reader regressions and a sparse two-view SIMIND smoke
|
|
35
|
+
test for axial source placement.
|
|
36
|
+
- Consolidated Interfile parsing and geometry handling to follow STIR semantics.
|
|
37
|
+
|
|
10
38
|
2.0.0 - 2026-10-09
|
|
11
39
|
------------------
|
|
12
40
|
|
|
@@ -13,7 +13,7 @@ sys.path.insert(0, os.path.abspath(".."))
|
|
|
13
13
|
project = "simind-python-connector"
|
|
14
14
|
copyright = f"{datetime.now().year}, Sam Porter, Efstathios Varzakis"
|
|
15
15
|
author = "Sam Porter, Efstathios Varzakis"
|
|
16
|
-
release = "
|
|
16
|
+
release = "3.0.0"
|
|
17
17
|
for dist_name in ("simind-python-connector",):
|
|
18
18
|
try:
|
|
19
19
|
release = importlib_metadata.version(dist_name)
|
|
@@ -38,7 +38,7 @@ source_suffix = {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
templates_path = ["_templates"]
|
|
41
|
-
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|
41
|
+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "superpowers/**"]
|
|
42
42
|
|
|
43
43
|
# Options for HTML output
|
|
44
44
|
html_theme = "sphinx_rtd_theme"
|
{simind_python_connector-2.0.0 → simind_python_connector-3.0.0}/docs/examples/04_custom_config.py
RENAMED
|
@@ -12,13 +12,6 @@ from pathlib import Path
|
|
|
12
12
|
from simind_python_connector import SimulationConfig, configs
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
try:
|
|
16
|
-
from simind_python_connector.backends import get_backend, set_backend
|
|
17
|
-
except ImportError: # backend libraries intentionally absent in core container
|
|
18
|
-
get_backend = None
|
|
19
|
-
set_backend = None
|
|
20
|
-
|
|
21
|
-
|
|
22
15
|
TEMPLATE_PATH = configs.get("input.smc") # Path to a template configuration file
|
|
23
16
|
|
|
24
17
|
|
|
@@ -172,6 +165,9 @@ def demonstrate_new_api_usage():
|
|
|
172
165
|
|
|
173
166
|
# Configure runtime/config switches and run
|
|
174
167
|
connector.add_runtime_switch('NN', 10)
|
|
168
|
+
connector.configure_phantom(phantom) # or configure_voxel_phantom(...)
|
|
169
|
+
# A configuration-defined phantom also works: without configure_phantom()
|
|
170
|
+
# the connector warns and runs the phantom from Index 14/15.
|
|
175
171
|
outputs = connector.run()
|
|
176
172
|
"""
|
|
177
173
|
)
|
|
@@ -193,36 +189,5 @@ if __name__ == "__main__":
|
|
|
193
189
|
description="Create and manage custom SIMIND configurations",
|
|
194
190
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
195
191
|
)
|
|
196
|
-
parser.
|
|
197
|
-
"--backend",
|
|
198
|
-
type=str,
|
|
199
|
-
choices=["sirf", "stir"],
|
|
200
|
-
help=(
|
|
201
|
-
"Force a specific backend (sirf or stir). "
|
|
202
|
-
"If not specified, auto-detection is used."
|
|
203
|
-
),
|
|
204
|
-
)
|
|
205
|
-
args = parser.parse_args()
|
|
206
|
-
|
|
207
|
-
# Set backend if specified and backend layer is available.
|
|
208
|
-
if args.backend:
|
|
209
|
-
if set_backend is None:
|
|
210
|
-
print(
|
|
211
|
-
f"Backend '{args.backend}' requested, "
|
|
212
|
-
"but backend libraries are not installed."
|
|
213
|
-
)
|
|
214
|
-
else:
|
|
215
|
-
set_backend(args.backend)
|
|
216
|
-
|
|
217
|
-
# Print backend status (core config workflow does not require one).
|
|
218
|
-
print(f"\n{'=' * 60}")
|
|
219
|
-
if get_backend is None:
|
|
220
|
-
print("Using backend: NONE (core configuration mode)")
|
|
221
|
-
else:
|
|
222
|
-
try:
|
|
223
|
-
print(f"Using backend: {get_backend().upper()}")
|
|
224
|
-
except ImportError:
|
|
225
|
-
print("Using backend: NONE (backend libraries unavailable)")
|
|
226
|
-
print(f"{'=' * 60}\n")
|
|
227
|
-
|
|
192
|
+
parser.parse_args()
|
|
228
193
|
main()
|
|
@@ -299,24 +299,5 @@ if __name__ == "__main__":
|
|
|
299
299
|
description="Demonstrate Schneider density conversion functionality",
|
|
300
300
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
301
301
|
)
|
|
302
|
-
parser.
|
|
303
|
-
"--backend",
|
|
304
|
-
type=str,
|
|
305
|
-
choices=["sirf", "stir"],
|
|
306
|
-
help=(
|
|
307
|
-
"Force a specific backend (sirf or stir). "
|
|
308
|
-
"Note: This example doesn't use backends, but the argument is "
|
|
309
|
-
"provided for consistency."
|
|
310
|
-
),
|
|
311
|
-
)
|
|
312
|
-
args = parser.parse_args()
|
|
313
|
-
|
|
314
|
-
# This example does not use backend implementations directly, but accepts
|
|
315
|
-
# the argument for consistency with the rest of the examples.
|
|
316
|
-
if args.backend:
|
|
317
|
-
print(
|
|
318
|
-
f"Note: Backend argument '{args.backend}' "
|
|
319
|
-
"specified but not used in this example."
|
|
320
|
-
)
|
|
321
|
-
|
|
302
|
+
parser.parse_args()
|
|
322
303
|
main()
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
MC scatter in the forward model with SIRF OSEM.
|
|
4
|
+
|
|
5
|
+
1. Simulate "measured" data with SIMIND (PENETRATE, known activity) in a
|
|
6
|
+
template geometry and add Poisson noise.
|
|
7
|
+
2. Reconstruct it with OSEM twice: without scatter correction, and with a
|
|
8
|
+
SIMIND scatter estimate (all events minus the geometric primary, scaled to
|
|
9
|
+
the fast model) refreshed every 2 epochs.
|
|
10
|
+
3. Print the hot-sphere contrast error of both against the truth.
|
|
11
|
+
|
|
12
|
+
Tiny on purpose: 32^3 voxels, 30 views, NN = 1. Needs SIRF and SIMIND.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import shutil
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
from _mc_scatter_common import (
|
|
21
|
+
contrast_error,
|
|
22
|
+
fast_model_factory,
|
|
23
|
+
image,
|
|
24
|
+
phantom,
|
|
25
|
+
print_updates,
|
|
26
|
+
scatter_updater,
|
|
27
|
+
simulate_measured,
|
|
28
|
+
template,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
from simind_python_connector.recon import AdditiveUpdater, UpdateSchedule
|
|
32
|
+
from simind_python_connector.recon.osem import run_osem_with_corrections
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
NUM_SUBSETS = 5
|
|
36
|
+
EPOCHS_PER_UPDATE = 2
|
|
37
|
+
NUM_UPDATES = 3
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def main() -> None:
|
|
41
|
+
if shutil.which("simind") is None:
|
|
42
|
+
raise RuntimeError("SIMIND executable not found in PATH.")
|
|
43
|
+
output_dir = Path("output/mc_scatter_osem")
|
|
44
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
|
|
46
|
+
activity, mu = phantom()
|
|
47
|
+
activity_image, mu_image = image(activity), image(mu)
|
|
48
|
+
template_data = template(output_dir)
|
|
49
|
+
measured = simulate_measured(output_dir, template_data, activity_image, mu_image)
|
|
50
|
+
|
|
51
|
+
make_model = fast_model_factory(mu_image)
|
|
52
|
+
full_model = make_model()
|
|
53
|
+
full_model.set_up(measured, activity_image)
|
|
54
|
+
initial = activity_image.get_uniform_copy(1.0)
|
|
55
|
+
subiterations = EPOCHS_PER_UPDATE * NUM_SUBSETS
|
|
56
|
+
|
|
57
|
+
# One pass with the same number of subiterations and a zero additive term;
|
|
58
|
+
# with num_updates=0 the updater never asks for an estimate.
|
|
59
|
+
baseline = run_osem_with_corrections(
|
|
60
|
+
measured,
|
|
61
|
+
make_model,
|
|
62
|
+
initial,
|
|
63
|
+
AdditiveUpdater(None, UpdateSchedule(every=1), measured.get_uniform_copy(0)),
|
|
64
|
+
NUM_SUBSETS,
|
|
65
|
+
subiterations_per_update=subiterations * (NUM_UPDATES + 1),
|
|
66
|
+
num_updates=0,
|
|
67
|
+
)
|
|
68
|
+
updater = scatter_updater(
|
|
69
|
+
output_dir, template_data, mu_image, measured, full_model, subiterations
|
|
70
|
+
)
|
|
71
|
+
corrected = run_osem_with_corrections(
|
|
72
|
+
measured,
|
|
73
|
+
make_model,
|
|
74
|
+
initial,
|
|
75
|
+
updater,
|
|
76
|
+
NUM_SUBSETS,
|
|
77
|
+
subiterations_per_update=subiterations,
|
|
78
|
+
num_updates=NUM_UPDATES,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
print_updates(updater)
|
|
82
|
+
before = contrast_error(baseline, activity)
|
|
83
|
+
after = contrast_error(corrected, activity)
|
|
84
|
+
print(f"hot-sphere contrast error, no scatter correction: {before:.1%}")
|
|
85
|
+
print(f"hot-sphere contrast error, SIMIND scatter: {after:.1%}")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
main()
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
MC scatter in the forward model with CIL.
|
|
4
|
+
|
|
5
|
+
The same data as example 09, reconstructed with CIL's ISTA over subset
|
|
6
|
+
Kullback-Leibler objectives. The AdaptiveSensitivity preconditioner with a
|
|
7
|
+
unit step makes each ISTA step an MLEM update. A CorrectionCallback refreshes
|
|
8
|
+
the SIMIND scatter estimate every 10 iterations and swaps it into the
|
|
9
|
+
objectives. Installed CIL calls back at iteration 0 before the first update,
|
|
10
|
+
then after later updates. Passing stop_at=ITERATIONS (an exclusive bound)
|
|
11
|
+
records refreshes at 10, 20 and 30 only, each consumed by a later iteration.
|
|
12
|
+
|
|
13
|
+
Tiny on purpose: 32^3 voxels, 30 views, NN = 1. Needs SIRF, CIL and SIMIND.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import shutil
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
from _mc_scatter_common import (
|
|
22
|
+
contrast_error,
|
|
23
|
+
fast_model_factory,
|
|
24
|
+
image,
|
|
25
|
+
phantom,
|
|
26
|
+
print_updates,
|
|
27
|
+
scatter_updater,
|
|
28
|
+
simulate_measured,
|
|
29
|
+
template,
|
|
30
|
+
)
|
|
31
|
+
from cil.optimisation.algorithms import ISTA
|
|
32
|
+
from cil.optimisation.functions import IndicatorBox, SumFunction
|
|
33
|
+
from cil.optimisation.utilities import AdaptiveSensitivity
|
|
34
|
+
|
|
35
|
+
from simind_python_connector.recon.cil import (
|
|
36
|
+
CorrectionCallback,
|
|
37
|
+
build_subset_objectives,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
NUM_SUBSETS = 5
|
|
42
|
+
ITERATIONS = 40
|
|
43
|
+
UPDATE_EVERY = 10
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _ista(objectives, initial, full_model, callbacks):
|
|
47
|
+
algorithm = ISTA(
|
|
48
|
+
initial=initial,
|
|
49
|
+
f=SumFunction(*objectives.functions),
|
|
50
|
+
g=IndicatorBox(lower=0),
|
|
51
|
+
step_size=1.0,
|
|
52
|
+
preconditioner=AdaptiveSensitivity(full_model, max_iterations=ITERATIONS + 1),
|
|
53
|
+
)
|
|
54
|
+
algorithm.run(ITERATIONS, callbacks=callbacks)
|
|
55
|
+
return algorithm.solution
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def main() -> None:
|
|
59
|
+
if shutil.which("simind") is None:
|
|
60
|
+
raise RuntimeError("SIMIND executable not found in PATH.")
|
|
61
|
+
output_dir = Path("output/mc_scatter_cil")
|
|
62
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
63
|
+
|
|
64
|
+
activity, mu = phantom()
|
|
65
|
+
activity_image, mu_image = image(activity), image(mu)
|
|
66
|
+
template_data = template(output_dir)
|
|
67
|
+
measured = simulate_measured(output_dir, template_data, activity_image, mu_image)
|
|
68
|
+
|
|
69
|
+
make_model = fast_model_factory(mu_image)
|
|
70
|
+
full_model = make_model()
|
|
71
|
+
full_model.set_up(measured, activity_image)
|
|
72
|
+
initial = activity_image.get_uniform_copy(1.0)
|
|
73
|
+
zero = measured.get_uniform_copy(0)
|
|
74
|
+
|
|
75
|
+
baseline_objectives = build_subset_objectives(
|
|
76
|
+
measured, zero, make_model, NUM_SUBSETS, initial
|
|
77
|
+
)
|
|
78
|
+
baseline = _ista(baseline_objectives, initial, full_model, callbacks=[])
|
|
79
|
+
|
|
80
|
+
objectives = build_subset_objectives(
|
|
81
|
+
measured, zero, make_model, NUM_SUBSETS, initial
|
|
82
|
+
)
|
|
83
|
+
updater = scatter_updater(
|
|
84
|
+
output_dir,
|
|
85
|
+
template_data,
|
|
86
|
+
mu_image,
|
|
87
|
+
measured,
|
|
88
|
+
full_model,
|
|
89
|
+
UPDATE_EVERY,
|
|
90
|
+
stop_at=ITERATIONS,
|
|
91
|
+
)
|
|
92
|
+
callback = CorrectionCallback(updater, objectives)
|
|
93
|
+
corrected = _ista(objectives, initial, full_model, callbacks=[callback])
|
|
94
|
+
|
|
95
|
+
print_updates(updater)
|
|
96
|
+
before = contrast_error(baseline, activity)
|
|
97
|
+
after = contrast_error(corrected, activity)
|
|
98
|
+
print(f"hot-sphere contrast error, no scatter correction: {before:.1%}")
|
|
99
|
+
print(f"hot-sphere contrast error, SIMIND scatter: {after:.1%}")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == "__main__":
|
|
103
|
+
main()
|