simind-python-connector 1.0.1__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.
Files changed (201) hide show
  1. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/MANIFEST.in +0 -2
  2. {simind_python_connector-1.0.1/simind_python_connector.egg-info → simind_python_connector-3.0.0}/PKG-INFO +10 -5
  3. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/README.md +4 -2
  4. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/api.rst +32 -12
  5. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/backends.rst +0 -28
  6. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/changelog.rst +80 -0
  7. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/conf.py +2 -2
  8. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/04_custom_config.py +4 -39
  9. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0/docs}/examples/06_schneider_density_conversion.py +1 -20
  10. simind_python_connector-3.0.0/docs/examples/09_mc_scatter_osem.py +89 -0
  11. simind_python_connector-3.0.0/docs/examples/10_mc_scatter_cil.py +103 -0
  12. simind_python_connector-3.0.0/docs/examples/11_residual_correction.py +154 -0
  13. simind_python_connector-3.0.0/docs/examples/12_phantoms.py +79 -0
  14. simind_python_connector-3.0.0/docs/examples/_mc_scatter_common.py +199 -0
  15. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples.rst +30 -0
  16. simind_python_connector-3.0.0/docs/geometry.rst +135 -0
  17. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/index.rst +16 -3
  18. simind_python_connector-3.0.0/docs/normalisation.rst +86 -0
  19. simind_python_connector-3.0.0/docs/phantoms.rst +122 -0
  20. simind_python_connector-3.0.0/docs/reconstruction.rst +266 -0
  21. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/testing.rst +7 -18
  22. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/04_custom_config.py +4 -39
  23. {simind_python_connector-1.0.1/docs → simind_python_connector-3.0.0}/examples/06_schneider_density_conversion.py +1 -20
  24. simind_python_connector-3.0.0/examples/09_mc_scatter_osem.py +89 -0
  25. simind_python_connector-3.0.0/examples/10_mc_scatter_cil.py +103 -0
  26. simind_python_connector-3.0.0/examples/11_residual_correction.py +154 -0
  27. simind_python_connector-3.0.0/examples/12_phantoms.py +79 -0
  28. simind_python_connector-3.0.0/examples/_mc_scatter_common.py +199 -0
  29. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/pyproject.toml +26 -5
  30. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/__init__.py +3 -3
  31. simind_python_connector-3.0.0/simind_python_connector/builders/_native.py +86 -0
  32. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/builders/acquisition_builder.py +94 -106
  33. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/builders/image_builder.py +31 -78
  34. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/configs/__init__.py +10 -4
  35. simind_python_connector-3.0.0/simind_python_connector/connectors/__init__.py +41 -0
  36. simind_python_connector-3.0.0/simind_python_connector/connectors/_native_adaptor.py +354 -0
  37. simind_python_connector-3.0.0/simind_python_connector/connectors/python_connector.py +970 -0
  38. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/connectors/pytomography_adaptor.py +31 -23
  39. simind_python_connector-3.0.0/simind_python_connector/connectors/sirf_adaptor.py +43 -0
  40. simind_python_connector-3.0.0/simind_python_connector/connectors/stir_adaptor.py +45 -0
  41. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/converters/__init__.py +2 -2
  42. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/converters/attenuation.py +41 -45
  43. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/converters/simind_to_stir.py +28 -338
  44. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/core/config.py +272 -82
  45. simind_python_connector-3.0.0/simind_python_connector/core/executor.py +117 -0
  46. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/core/types.py +5 -24
  47. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/data/__init__.py +3 -3
  48. simind_python_connector-3.0.0/simind_python_connector/data/bone.atn +178 -0
  49. simind_python_connector-3.0.0/simind_python_connector/data/h2o.atn +84 -0
  50. simind_python_connector-3.0.0/simind_python_connector/normalisation.py +90 -0
  51. simind_python_connector-3.0.0/simind_python_connector/phantoms.py +386 -0
  52. simind_python_connector-3.0.0/simind_python_connector/recon/__init__.py +41 -0
  53. simind_python_connector-3.0.0/simind_python_connector/recon/cil.py +185 -0
  54. simind_python_connector-3.0.0/simind_python_connector/recon/corrections.py +108 -0
  55. simind_python_connector-3.0.0/simind_python_connector/recon/diagnostics.py +41 -0
  56. simind_python_connector-3.0.0/simind_python_connector/recon/osem.py +59 -0
  57. simind_python_connector-3.0.0/simind_python_connector/recon/projector.py +112 -0
  58. simind_python_connector-3.0.0/simind_python_connector/recon/updates.py +88 -0
  59. simind_python_connector-3.0.0/simind_python_connector/utils/__init__.py +45 -0
  60. simind_python_connector-3.0.0/simind_python_connector/utils/interfile.py +659 -0
  61. simind_python_connector-3.0.0/simind_python_connector/utils/simind_utils.py +81 -0
  62. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0/simind_python_connector.egg-info}/PKG-INFO +10 -5
  63. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector.egg-info/SOURCES.txt +62 -24
  64. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector.egg-info/requires.txt +4 -0
  65. simind_python_connector-3.0.0/tests/conftest.py +36 -0
  66. simind_python_connector-3.0.0/tests/recon/__init__.py +0 -0
  67. simind_python_connector-3.0.0/tests/recon/conftest.py +138 -0
  68. simind_python_connector-3.0.0/tests/recon/fakes.py +93 -0
  69. simind_python_connector-3.0.0/tests/recon/test_cil_functions.py +46 -0
  70. simind_python_connector-3.0.0/tests/recon/test_cil_sirf.py +229 -0
  71. simind_python_connector-3.0.0/tests/recon/test_corrections.py +71 -0
  72. simind_python_connector-3.0.0/tests/recon/test_diagnostics.py +60 -0
  73. simind_python_connector-3.0.0/tests/recon/test_import_boundary.py +90 -0
  74. simind_python_connector-3.0.0/tests/recon/test_osem_sirf.py +113 -0
  75. simind_python_connector-3.0.0/tests/recon/test_projector.py +153 -0
  76. simind_python_connector-3.0.0/tests/recon/test_residual.py +77 -0
  77. simind_python_connector-3.0.0/tests/recon/test_residual_cil.py +52 -0
  78. simind_python_connector-3.0.0/tests/recon/test_residual_sirf.py +87 -0
  79. simind_python_connector-3.0.0/tests/recon/test_updates.py +146 -0
  80. simind_python_connector-3.0.0/tests/test_acquisition_builder_unit.py +210 -0
  81. simind_python_connector-3.0.0/tests/test_attenuation_utils.py +68 -0
  82. simind_python_connector-3.0.0/tests/test_builders_lifetime.py +59 -0
  83. simind_python_connector-3.0.0/tests/test_builders_native.py +148 -0
  84. simind_python_connector-3.0.0/tests/test_configure_phantom.py +376 -0
  85. simind_python_connector-3.0.0/tests/test_connector_backend_separation.py +96 -0
  86. simind_python_connector-3.0.0/tests/test_container_scripts.py +497 -0
  87. simind_python_connector-3.0.0/tests/test_converter_golden.py +128 -0
  88. simind_python_connector-3.0.0/tests/test_dicom_builder.py +157 -0
  89. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_examples_backend_separation.py +17 -0
  90. simind_python_connector-3.0.0/tests/test_executor.py +278 -0
  91. simind_python_connector-3.0.0/tests/test_ground_truth_sirf.py +38 -0
  92. simind_python_connector-3.0.0/tests/test_image_builder_unit.py +71 -0
  93. simind_python_connector-3.0.0/tests/test_import_side_effects.py +55 -0
  94. simind_python_connector-3.0.0/tests/test_interfile.py +1178 -0
  95. simind_python_connector-3.0.0/tests/test_legacy_surface_policy.py +20 -0
  96. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_marker_policy.py +35 -11
  97. simind_python_connector-3.0.0/tests/test_measured_geometry_simind.py +208 -0
  98. simind_python_connector-3.0.0/tests/test_native_adaptors.py +764 -0
  99. simind_python_connector-3.0.0/tests/test_nema_phantom.py +95 -0
  100. simind_python_connector-3.0.0/tests/test_normalisation.py +98 -0
  101. simind_python_connector-3.0.0/tests/test_packaging_resources.py +113 -0
  102. simind_python_connector-3.0.0/tests/test_phantoms.py +102 -0
  103. simind_python_connector-3.0.0/tests/test_phantoms_simind.py +246 -0
  104. simind_python_connector-3.0.0/tests/test_python_connector.py +1434 -0
  105. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_pytomography_adaptor.py +177 -2
  106. simind_python_connector-3.0.0/tests/test_runtime_switches.py +175 -0
  107. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_schneider_density.py +3 -0
  108. simind_python_connector-3.0.0/tests/test_simind_mpi.py +29 -0
  109. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_simind_to_stir_converter.py +63 -40
  110. simind_python_connector-3.0.0/tests/test_simulation_config.py +208 -0
  111. simind_python_connector-3.0.0/tests/test_template_geometry_sirf.py +285 -0
  112. simind_python_connector-3.0.0/tests/test_utils_small.py +68 -0
  113. simind_python_connector-3.0.0/tests/test_voxelise.py +130 -0
  114. simind_python_connector-1.0.1/docs/connector_modernization_plan.rst +0 -45
  115. simind_python_connector-1.0.1/docs/geometry.rst +0 -63
  116. simind_python_connector-1.0.1/requirements-dev.txt +0 -23
  117. simind_python_connector-1.0.1/requirements.txt +0 -10
  118. simind_python_connector-1.0.1/simind_python_connector/backends/__init__.py +0 -480
  119. simind_python_connector-1.0.1/simind_python_connector/backends/base.py +0 -387
  120. simind_python_connector-1.0.1/simind_python_connector/backends/sirf_backend.py +0 -309
  121. simind_python_connector-1.0.1/simind_python_connector/backends/stir_backend.py +0 -395
  122. simind_python_connector-1.0.1/simind_python_connector/connectors/__init__.py +0 -24
  123. simind_python_connector-1.0.1/simind_python_connector/connectors/_spacing.py +0 -69
  124. simind_python_connector-1.0.1/simind_python_connector/connectors/python_connector.py +0 -355
  125. simind_python_connector-1.0.1/simind_python_connector/connectors/sirf_adaptor.py +0 -164
  126. simind_python_connector-1.0.1/simind_python_connector/connectors/stir_adaptor.py +0 -164
  127. simind_python_connector-1.0.1/simind_python_connector/converters/dicom_to_stir.py +0 -3
  128. simind_python_connector-1.0.1/simind_python_connector/core/executor.py +0 -96
  129. simind_python_connector-1.0.1/simind_python_connector/data/bone.atn +0 -187
  130. simind_python_connector-1.0.1/simind_python_connector/data/h2o.atn +0 -92
  131. simind_python_connector-1.0.1/simind_python_connector/utils/__init__.py +0 -120
  132. simind_python_connector-1.0.1/simind_python_connector/utils/backend_access.py +0 -121
  133. simind_python_connector-1.0.1/simind_python_connector/utils/import_helpers.py +0 -74
  134. simind_python_connector-1.0.1/simind_python_connector/utils/interfile_numpy.py +0 -195
  135. simind_python_connector-1.0.1/simind_python_connector/utils/interfile_parser.py +0 -175
  136. simind_python_connector-1.0.1/simind_python_connector/utils/io_utils.py +0 -14
  137. simind_python_connector-1.0.1/simind_python_connector/utils/simind_utils.py +0 -70
  138. simind_python_connector-1.0.1/simind_python_connector/utils/sirf_stir_utils.py +0 -194
  139. simind_python_connector-1.0.1/simind_python_connector/utils/stir_utils.py +0 -485
  140. simind_python_connector-1.0.1/tests/conftest.py +0 -128
  141. simind_python_connector-1.0.1/tests/test_acquisition_builder_unit.py +0 -152
  142. simind_python_connector-1.0.1/tests/test_arithmetic_operations.py +0 -106
  143. simind_python_connector-1.0.1/tests/test_backends.py +0 -289
  144. simind_python_connector-1.0.1/tests/test_connector_backend_separation.py +0 -42
  145. simind_python_connector-1.0.1/tests/test_image_builder_unit.py +0 -90
  146. simind_python_connector-1.0.1/tests/test_interfile_numpy.py +0 -171
  147. simind_python_connector-1.0.1/tests/test_interfile_parser.py +0 -41
  148. simind_python_connector-1.0.1/tests/test_native_adaptors.py +0 -389
  149. simind_python_connector-1.0.1/tests/test_python_connector.py +0 -370
  150. simind_python_connector-1.0.1/tests/test_simulation_config.py +0 -89
  151. simind_python_connector-1.0.1/tests/test_sirf_stir_utils.py +0 -56
  152. simind_python_connector-1.0.1/tests/test_stir_utils_backend_choice_unit.py +0 -78
  153. simind_python_connector-1.0.1/tests/test_utils.py +0 -134
  154. simind_python_connector-1.0.1/tests/test_utils_small.py +0 -53
  155. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/LICENSE +0 -0
  156. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/contributing.rst +0 -0
  157. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/01_basic_simulation.py +0 -0
  158. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/02_runtime_switch_comparison.py +0 -0
  159. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/03_multi_window.py +0 -0
  160. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/05_scattwin_vs_penetrate_comparison.py +0 -0
  161. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/07A_stir_adaptor_osem.py +0 -0
  162. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/07B_sirf_adaptor_osem.py +0 -0
  163. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/07C_pytomography_adaptor_osem.py +0 -0
  164. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/08A_stir_adaptor_from_dicom.py +0 -0
  165. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/08B_sirf_adaptor_from_dicom.py +0 -0
  166. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/08C_pytomography_adaptor_from_dicom.py +0 -0
  167. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/examples/_python_connector_helpers.py +0 -0
  168. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/installation.rst +0 -0
  169. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/intro.rst +0 -0
  170. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/docs/usage.rst +0 -0
  171. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/01_basic_simulation.py +0 -0
  172. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/02_runtime_switch_comparison.py +0 -0
  173. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/03_multi_window.py +0 -0
  174. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/05_scattwin_vs_penetrate_comparison.py +0 -0
  175. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/07A_stir_adaptor_osem.py +0 -0
  176. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/07B_sirf_adaptor_osem.py +0 -0
  177. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/07C_pytomography_adaptor_osem.py +0 -0
  178. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/08A_stir_adaptor_from_dicom.py +0 -0
  179. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/08B_sirf_adaptor_from_dicom.py +0 -0
  180. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/08C_pytomography_adaptor_from_dicom.py +0 -0
  181. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/examples/_python_connector_helpers.py +0 -0
  182. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/setup.cfg +0 -0
  183. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/builders/__init__.py +0 -0
  184. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/configs/AnyScan.yaml +0 -0
  185. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/configs/Discovery670.yaml +0 -0
  186. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/configs/Example.yaml +0 -0
  187. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/configs/MLD001_SCAN0.yaml +0 -0
  188. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/configs/input.smc +0 -0
  189. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/connectors/base.py +0 -0
  190. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/core/__init__.py +0 -0
  191. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector/data/Schneider2000.json +0 -0
  192. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector.egg-info/dependency_links.txt +0 -0
  193. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/simind_python_connector.egg-info/top_level.txt +0 -0
  194. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/__init__.py +0 -0
  195. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_connectors_base.py +0 -0
  196. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_container_library_isolation.py +0 -0
  197. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_example_config_profile.py +0 -0
  198. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_geometry_isolation_forward_projection.py +0 -0
  199. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_integration.py +0 -0
  200. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_osem_geometry_diagnostics.py +0 -0
  201. {simind_python_connector-1.0.1 → simind_python_connector-3.0.0}/tests/test_package_identity.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: 1.0.1
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
- Requires-Python: >=3.9
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
  [![Tests](https://github.com/samdporter/simind-python-connector/workflows/Tests/badge.svg)](https://github.com/samdporter/simind-python-connector/actions)
49
52
  [![Documentation Status](https://readthedocs.org/projects/simind-python-connector/badge/?version=latest)](https://simind-python-connector.readthedocs.io/en/latest/?badge=latest)
50
53
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
51
- [![Python Version](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/downloads/)
54
+ [![Python Version](https://img.shields.io/badge/python-3.10%2B-blue.svg)](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
- **Important**: As of November 2025, the STIR conda package (v6.3.0) requires NumPy < 2.0 due to binary compatibility issues with NumPy 2.x. The package was compiled against NumPy 1.x and will crash with memory errors if NumPy 2.x is installed. This should be resolved in future STIR releases.
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
  [![Tests](https://github.com/samdporter/simind-python-connector/workflows/Tests/badge.svg)](https://github.com/samdporter/simind-python-connector/actions)
6
6
  [![Documentation Status](https://readthedocs.org/projects/simind-python-connector/badge/?version=latest)](https://simind-python-connector.readthedocs.io/en/latest/?badge=latest)
7
7
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
8
- [![Python Version](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/downloads/)
8
+ [![Python Version](https://img.shields.io/badge/python-3.10%2B-blue.svg)](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
- **Important**: As of November 2025, the STIR conda package (v6.3.0) requires NumPy < 2.0 due to binary compatibility issues with NumPy 2.x. The package was compiled against NumPy 1.x and will crash with memory errors if NumPy 2.x is installed. This should be resolved in future STIR releases.
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.dicom_to_stir
63
+ .. automodule:: simind_python_connector.converters.simind_to_stir
64
64
  :members:
65
65
  :undoc-members:
66
66
  :show-inheritance:
67
67
 
68
- .. automodule:: simind_python_connector.converters.simind_to_stir
68
+ Normalisation
69
+ -------------
70
+
71
+ .. automodule:: simind_python_connector.normalisation
69
72
  :members:
70
73
  :undoc-members:
71
74
  :show-inheritance:
72
75
 
73
- Utilities
74
- ---------
76
+ Reconstruction with SIMIND corrections
77
+ --------------------------------------
75
78
 
76
- .. automodule:: simind_python_connector.utils.stir_utils
79
+ .. automodule:: simind_python_connector.recon.updates
77
80
  :members:
78
- :undoc-members:
79
- :show-inheritance:
80
81
 
81
- .. automodule:: simind_python_connector.utils.simind_utils
82
+ .. automodule:: simind_python_connector.recon.projector
82
83
  :members:
83
- :undoc-members:
84
- :show-inheritance:
85
84
 
86
- .. automodule:: simind_python_connector.utils.io_utils
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.interfile_numpy
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,86 @@ 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
+
38
+ 2.0.0 - 2026-10-09
39
+ ------------------
40
+
41
+ Breaking Changes
42
+ ~~~~~~~~~~~~~~~~
43
+
44
+ - ``STIRSPECTAcquisitionDataBuilder`` no longer flips projection data along the
45
+ last axis.
46
+ - Runtime-operator switches passed to ``run()`` apply to that run only. They
47
+ are no longer kept on the connector for later runs.
48
+ - Each run deletes earlier outputs that share the output prefix before SIMIND
49
+ starts.
50
+ - The STIR backend needs ``stirextra`` as well as ``stir``.
51
+ - STIR/SIRF adaptors take the z voxel spacing from a different axis (see
52
+ Fixed). Results change for anisotropic voxels.
53
+ - Invalid inputs now raise ``ValueError``: empty, non-finite or negative source
54
+ and attenuation maps, array shapes that do not match the header, and
55
+ ``output_prefix`` values that contain a path. Energy-window validation raises
56
+ ``ValueError`` instead of ``AssertionError``.
57
+
58
+ Fixed
59
+ ~~~~~
60
+
61
+ - The packaged ``configs/input.smc`` is now included in the wheel. SMC parsing
62
+ handles fixed-width fields and checks section counts.
63
+ - STIR/SIRF adaptors read the z voxel spacing from the correct axis:
64
+ ``voxel_sizes()`` is ``(z, y, x)``, and raw ``get_grid_spacing()`` is
65
+ ``(unused, z, y, x)``.
66
+ - Voxel-map dimension indices 76, 77, 78, 79, 81 and 82 are set correctly.
67
+ - The executor resolves ``SIMIND_BIN`` and accepts executable paths that
68
+ contain spaces. The connector no longer changes the process working directory.
69
+ - Runtime switches apply to one run only. Output prefixes cannot escape the
70
+ output directory. Stale outputs are removed, and ``.win``, ``.smi`` and
71
+ ``.dmi`` inputs are kept.
72
+ - Energy-window validation raises ``ValueError`` instead of failing an
73
+ ``assert``.
74
+ - The Interfile loader honours data offsets, strips quoted values and rejects
75
+ truncated or oversized payloads. The SIMIND-to-STIR converter keeps data-file
76
+ lines and applies the radius scale factor.
77
+ - Attenuation utilities handle the ``rho*1000`` selector and STIR ``#`` header
78
+ keys, and reject unknown attenuation types.
79
+ - Image and acquisition builders validate array shapes, split multi-energy data
80
+ deterministically and no longer flip images. The DICOM builder handles missing
81
+ timing information and 2D pixel data.
82
+ - Backend adaptors are imported lazily, so the core package imports without
83
+ STIR, SIRF or PyTomography.
84
+
85
+ Removed
86
+ ~~~~~~~
87
+
88
+ - The legacy ``scripts/simulation.py``.
89
+
10
90
  1.0.1 - 2026-04-16
11
91
  ------------------
12
92
 
@@ -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 = "1.0.1"
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"
@@ -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.add_argument(
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.add_argument(
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()