aprict 0.0.24.dev1__tar.gz → 0.0.27__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 (161) hide show
  1. {aprict-0.0.24.dev1/src/aprict.egg-info → aprict-0.0.27}/PKG-INFO +1 -1
  2. {aprict-0.0.24.dev1 → aprict-0.0.27}/pyproject.toml +1 -0
  3. {aprict-0.0.24.dev1 → aprict-0.0.27}/setup.py +3 -0
  4. aprict-0.0.27/src/aprict/__init__.py +92 -0
  5. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cb/flatpanel.py +21 -7
  6. aprict-0.0.27/src/aprict/examples/__init__.py +41 -0
  7. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/examples/composite_human_sirt.py +2 -2
  8. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/examples/fan_beam_sirt.py +2 -2
  9. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/examples/helical_sirt.py +2 -2
  10. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/examples/trajtest_A_sirt.py +5 -5
  11. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/examples/triangle_exp_fb.py +3 -3
  12. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/phantoms/FORBILD_phantoms.py +56 -41
  13. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/phantoms/__init__.py +5 -1
  14. aprict-0.0.27/src/aprict/scripts/__init__.py +20 -0
  15. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/scripts/cli.py +2 -2
  16. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/scripts/project_cbfp.py +3 -3
  17. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/tests/cuda_kernels/test_project_cb.py +1 -1
  18. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/tests/cuda_kernels/test_project_cb_FORBILD_phantoms.py +1 -1
  19. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/tests/test_FORBILD_lungs_construction.py +1 -1
  20. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/version.py +1 -1
  21. aprict-0.0.27/src/aprict/volume/__init__.py +24 -0
  22. {aprict-0.0.24.dev1/src/aprict → aprict-0.0.27/src/aprict/volume}/volume.py +7 -7
  23. {aprict-0.0.24.dev1 → aprict-0.0.27/src/aprict.egg-info}/PKG-INFO +1 -1
  24. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict.egg-info/SOURCES.txt +5 -2
  25. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict.egg-info/entry_points.txt +1 -0
  26. aprict-0.0.24.dev1/src/aprict/__init__.py +0 -47
  27. {aprict-0.0.24.dev1 → aprict-0.0.27}/LICENSE.txt +0 -0
  28. {aprict-0.0.24.dev1 → aprict-0.0.27}/LICENSE_GPLv3.txt +0 -0
  29. {aprict-0.0.24.dev1 → aprict-0.0.27}/MANIFEST.in +0 -0
  30. {aprict-0.0.24.dev1 → aprict-0.0.27}/README.md +0 -0
  31. {aprict-0.0.24.dev1 → aprict-0.0.27}/setup.cfg +0 -0
  32. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cb/__init__.py +0 -0
  33. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cb/_unused_old_fbp.py +0 -0
  34. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cb/noop_filter.py +0 -0
  35. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cb/ramp_filter.py +0 -0
  36. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cb/ramp_filter_cpu.py +0 -0
  37. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/__init__.py +0 -0
  38. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/_generate_cusrc.py +0 -0
  39. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/dtype_cacher.py +0 -0
  40. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/header_injection.py +0 -0
  41. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/kern_structs.py +0 -0
  42. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/ptx_cacher.py +0 -0
  43. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/FORBILD_volumes.py +0 -0
  44. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/__init__.py +0 -0
  45. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/base.py +0 -0
  46. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/config_cb_backproject.py +0 -0
  47. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/config_cb_project.py +0 -0
  48. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/config_cb_project_FORBILD.py +0 -0
  49. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Box.cu +0 -0
  50. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_ClipAxisSpec.cu +0 -0
  51. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Cone.cu +0 -0
  52. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Cone_x.cu +0 -0
  53. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Cone_y.cu +0 -0
  54. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Cone_z.cu +0 -0
  55. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Cylinder.cu +0 -0
  56. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Cylinder_x.cu +0 -0
  57. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Cylinder_y.cu +0 -0
  58. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Cylinder_z.cu +0 -0
  59. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Ellipsoid.cu +0 -0
  60. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Ellipsoid_free.cu +0 -0
  61. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Ellipt_Cyl.cu +0 -0
  62. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Ellipt_Cyl_x.cu +0 -0
  63. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Ellipt_Cyl_y.cu +0 -0
  64. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Ellipt_Cyl_z.cu +0 -0
  65. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Shape.cu +0 -0
  66. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/FORBILD_Sphere.cu +0 -0
  67. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/cu/__init__.py +0 -0
  68. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/geometry.py +0 -0
  69. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/test_subdir/__init__.py +0 -0
  70. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/cuda/structs/test_subdir/test_config.py +0 -0
  71. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/.gitignore +0 -0
  72. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/abdomen/AbdomenPhantom.pha +0 -0
  73. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/abdomen/AbdomenPhantom_fixed.pha +0 -0
  74. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/abdomen/TableOfTissues +0 -0
  75. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/abdomen/Wirbel.pha +0 -0
  76. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_composite/Ribs.pha +0 -0
  77. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_composite/Shoulders.pha +0 -0
  78. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_composite/TableOfTissues +0 -0
  79. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_composite/Vertebra.pha +0 -0
  80. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_composite/part_01_hip.pha +0 -0
  81. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_composite/part_02_abdomen.pha +0 -0
  82. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_composite/part_03_thorax.pha +0 -0
  83. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_composite/part_04_head.pha +0 -0
  84. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_composite/part_05_jaw.pha +0 -0
  85. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_other/rock_canister_01.pha +0 -0
  86. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_other/rock_canister_01_cavities_1e5.pha +0 -0
  87. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/custom_other/unit_Cyl_z.pha +0 -0
  88. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/head/HeadPhantom.pha +0 -0
  89. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/head/TableOfTissues +0 -0
  90. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/hip/HipPhantom.pha +0 -0
  91. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/jaw/JawPhantom.pha +0 -0
  92. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/lungs/LungPhantom3Generations.pha +0 -0
  93. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/thorax/Ribs.pha +0 -0
  94. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/thorax/Shoulders.pha +0 -0
  95. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/thorax/TableOfTissues +0 -0
  96. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/thorax/ThoraxPhantom.pha +0 -0
  97. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/FORBILD/thorax/Vertebra.pha +0 -0
  98. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/README.txt +0 -0
  99. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/CB_backproject.cu +0 -0
  100. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/CB_backproject_sharedmem.cu +0 -0
  101. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/CB_project_sharedmem.cu +0 -0
  102. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/CB_project_texture_chunked.cu +0 -0
  103. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/FORBILD_volumes.h +0 -0
  104. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/base.h +0 -0
  105. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/config_cb_backproject.h +0 -0
  106. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/config_cb_project.h +0 -0
  107. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/config_cb_project_FORBILD.h +0 -0
  108. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/geometry.h +0 -0
  109. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/get_bboxes_FORBILD.cu +0 -0
  110. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/ramlak_convolve.cu +0 -0
  111. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/sample_FORBILD_volumes.cu +0 -0
  112. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/test_kernel.cu +0 -0
  113. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/test_subdir/test_config.h +0 -0
  114. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/data/cusrc/texture_operations.cu +0 -0
  115. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/examples/lungs_sirt.py +0 -0
  116. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/gbc/__init__.py +0 -0
  117. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/gbc/filters.py +0 -0
  118. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/gbc/weightinteg.py +0 -0
  119. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/image_view.py +0 -0
  120. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/iterators/__init__.py +0 -0
  121. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/iterators/landweber_vram.py +0 -0
  122. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/iterators/sirt_vram.py +0 -0
  123. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/__init__.py +0 -0
  124. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/argparse_tools.py +0 -0
  125. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/bboxes_FORBILD.py +0 -0
  126. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/click_tools.py +0 -0
  127. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/empty_context_manager.py +0 -0
  128. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/gpu_tools.py +0 -0
  129. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/import_tools.py +0 -0
  130. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/lds.py +0 -0
  131. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/ne_tools.py +0 -0
  132. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/ng_tools.py +0 -0
  133. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/np_tools.py +0 -0
  134. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/process_pha_file.py +0 -0
  135. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/sample_FORBILD.py +0 -0
  136. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/texture_tools/__init__.py +0 -0
  137. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/texture_tools/operations.py +0 -0
  138. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/lib/texture_tools/texture.py +0 -0
  139. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/liveplot.py +0 -0
  140. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/logtools/__init__.py +0 -0
  141. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/logtools/config.py +0 -0
  142. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/logtools/pbar.py +0 -0
  143. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/logtools/pbar_tqdm.py +0 -0
  144. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/logtools/rich_custombar.py +0 -0
  145. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/ramp_kernels.py +0 -0
  146. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/scripts/make_geometry_cone_cyl.py +0 -0
  147. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/scripts/make_geometry_fan_circ.py +0 -0
  148. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/scripts/neuroglance.py +0 -0
  149. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/scripts/recon_cbfp_cyl_fbp.py +0 -0
  150. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/scripts/recon_cbfp_cyl_gbc.py +0 -0
  151. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/scripts/recon_cbfp_landweber.py +0 -0
  152. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/tests/__init__.py +0 -0
  153. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/tests/cuda_kernels/__init__.py +0 -0
  154. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/tests/cuda_kernels/test_backproject_cb.py +0 -0
  155. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/tests/cuda_kernels/test_cusrc/__init__.py +0 -0
  156. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/tests/cuda_kernels/test_kernel_structs.py +0 -0
  157. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/tests/cuda_kernels/test_project_cb_FORBILD_shapes.py +0 -0
  158. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict/tests/test_volume.py +0 -0
  159. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict.egg-info/dependency_links.txt +0 -0
  160. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict.egg-info/requires.txt +0 -0
  161. {aprict-0.0.24.dev1 → aprict-0.0.27}/src/aprict.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aprict
3
- Version: 0.0.24.dev1
3
+ Version: 0.0.27
4
4
  Summary: Tools to simulate and reconstruct XCT transmission data.
5
5
  Author: Murdock Grewar
6
6
  Author-email: Murdock Grewar <murdock.grewar@anu.edu.au>
@@ -49,6 +49,7 @@ dev = [
49
49
  "bandit>=1.9.4",
50
50
  "build>=1.6.1",
51
51
  "ipython>=9.11.0",
52
+ "pdoc>=16.0.0",
52
53
  "pre-commit>=4.5.1",
53
54
  "pytest>=9.0.2",
54
55
  "pytest-dependency>=0.6.1",
@@ -55,6 +55,9 @@ setup(
55
55
  # package_data={my_module_name: ["data/"]},
56
56
  entry_points={
57
57
  "console_scripts": [
58
+ my_module_name + " = " + my_module_name + ".scripts.cli:main",
59
+ ]
60
+ + [
58
61
  my_module_name
59
62
  + "-"
60
63
  + f"{_filename_to_command_name(script_name):s}"
@@ -0,0 +1,92 @@
1
+ # Copyright (C) 2026 Murdock Grewar
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+
16
+ """
17
+ [![Static Badge](https://img.shields.io/badge/ORCiD-0000--0002--0015--8284-green?logo=orcid)](https://orcid.org/0000-0002-0015-8284)
18
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23632625.svg)](https://doi.org/10.5281/zenodo.23632625)
19
+ ![PyPI Version](https://img.shields.io/pypi/v/aprict)
20
+ [![Project Status: WIP – Initial development is in progress, but there has not yet been a stable, usable release suitable for the public.](https://www.repostatus.org/badges/latest/wip.svg)](https://www.repostatus.org/#wip)
21
+
22
+ `aprict` is a Python module and commandline program for simulating flat-panel transmission X-ray experiments.
23
+
24
+ Recommended import pattern
25
+ --
26
+
27
+ The recommended import pattern for this module is
28
+ ```python
29
+ import aprict
30
+ from aprict.cb import flatpanel as cbfp
31
+ ```
32
+
33
+ Main components
34
+ --
35
+
36
+ The main components of the end-user Python API are:
37
+ - [`aprict.FBVolume`](aprict/volume.html#FBVolume) - an attenuating volume defined in FORBILD format
38
+ - [`aprict.Volume`](aprict/volume.html#Volume) - an attenuating volume defined in voxelised format
39
+ - `aprict.cb.flatpanel` - a namespace for objects and functions applying to cone-beam imaging geometries
40
+
41
+ Examples
42
+ --
43
+
44
+ For examples of Python API usage, see `aprict.examples`.
45
+
46
+ Commandline interface
47
+ --
48
+
49
+ The entry point for the main commandline interface is the shell command `aprict`. This shell command should be available on `$PATH` if the module is installed in the current environment. All shell commands are self-documented:
50
+ ```bash
51
+ $ aprict --help
52
+ ```
53
+ """ # ruff: ignore[ambiguous-unicode-character-docstring, blank-lines-between-header-and-content, mismatched-section-underline-length, missing-blank-line-after-summary, missing-trailing-period]
54
+
55
+ # If we are just running the build script, then I don't want to initialise anything,
56
+ # because the imports fail because it hasn't built yet.
57
+
58
+ import os as _os
59
+
60
+ if _os.environ.get("APRICT_BUILDMODE", ""): # ruff: ignore[non-empty-init-module]
61
+ pass
62
+ else:
63
+ # Ensure that numexpr max threads is set to the number of logical cores before importing numexpr either directly or indirectly through other imports.
64
+ _nethreads_max_env = _os.environ.get("NUMEXPR_MAX_THREADS", None)
65
+ if _nethreads_max_env is None:
66
+ _os.environ["NUMEXPR_MAX_THREADS"] = str(_os.process_cpu_count())
67
+
68
+ del _os
69
+ from . import cb as cb
70
+ from . import image_view as imview
71
+ from . import iterators, lib, phantoms, volume
72
+ from .cuda import structs as dtypes
73
+ from .volume import FBVolume as FBVolume
74
+
75
+ FBVolume.__doc__ = "@private\nAn alias to aprict.volume.FBVolume" # Hide from pdoc documentation of this module
76
+ from .volume import Volume as Volume
77
+
78
+ Volume.__doc__ = "@private\nAn alias to aprict.volume.Volume" # Hide from pdoc documentation of this module
79
+
80
+ # Note that __all__ determines what's listed in the documentation page.
81
+ # So, I'm selecting only those parts which I want to be documented on the main doc page here.
82
+ __all__ = [
83
+ "FBVolume", # documented in aprict.volume
84
+ "Volume", # documented in aprict.volume
85
+ "cb",
86
+ "dtypes",
87
+ "imview",
88
+ "iterators",
89
+ "lib",
90
+ "phantoms",
91
+ "volume",
92
+ ]
@@ -15,7 +15,21 @@
15
15
 
16
16
  # flatpanel.py
17
17
 
18
- """End-user interfaces to the flat-panel cone-beam projection and backprojection CUDA code."""
18
+ """
19
+ End-user interfaces to the flat-panel cone-beam projection and backprojection CUDA code.
20
+
21
+ The main provided methods are
22
+ - `project` - used to generate projection data from a `aprict.volume.Volume` or `aprict.volume.FBVolume` object.
23
+ - `backproject` - used to generate backprojection data from a `aprict.volume.Volume` or `aprict.volume.FBVolume` object.
24
+
25
+ The main provided classes are
26
+ - `ProjGeom` - object to encode a flat-panel (back)projection geometry.
27
+ - `ProjectionSet` - object to hold a `ProjGeom` and associated projection data.
28
+ - `ConfigProject` - object to hold a collection of settings applied when computing projections with `project`.
29
+ - `ConfigBackproject` - object to hold a collection of settings applied when computing backprojections with `backproject`.
30
+
31
+ Note that the `ConfigBackproject` object allows for configuring weighted backprojections and the like. The `backproj_weighting_preset` attribute passed to its constructor can significantly influence the behaviour of the backprojection, since this value is passed to the CUDA kernel, which performs some internal logic depending on this value. Currently, the end user has limited control over what kind of weightings are applied, since adding new presets requires editing the CUDA kernel. The available presets will be documented at a later time. The default value of `0` corresponds to the adjoint of the forward projection.
32
+ """
19
33
 
20
34
  import dataclasses
21
35
  import functools
@@ -42,7 +56,7 @@ _delay_compile: bool = (
42
56
 
43
57
 
44
58
  def force_compile(*, log_stream: object | None = None) -> None:
45
- """Force the relevant CUDA kernels to compile."""
59
+ """Force the relevant CUDA kernels to compile, if they have not already."""
46
60
  _projection_module.compile(log_stream=log_stream)
47
61
  _backprojection_module.compile(log_stream=log_stream)
48
62
 
@@ -250,7 +264,7 @@ class ProjGeom: # ruff: ignore[eq-without-hash]
250
264
  tuple[float, float, float],
251
265
  tuple[float, float, float],
252
266
  ]:
253
- """Return a bounding box."""
267
+ """Return a bounding box like ((minx,miny,minz),(maxx,maxy,maxz))."""
254
268
  # Make a list of points such that the whole projection geometry
255
269
  # is contained in the convex hull. Then take the min x,y,z and max x,y,z
256
270
  # it = slice(None, None) if index_tuple is None else index_tuple
@@ -713,7 +727,7 @@ class ProjectionSet:
713
727
  tuple[float, float, float],
714
728
  tuple[float, float, float],
715
729
  ]:
716
- """Return a bounding box."""
730
+ """Return a bounding box like ((minx,miny,minz),(maxx,maxy,maxz))."""
717
731
  return self._proj_geom.get_bbox(index_tuple=index_tuple)
718
732
 
719
733
  @property
@@ -809,19 +823,19 @@ class ProjectionSet:
809
823
 
810
824
 
811
825
  class ConfigProject:
812
- """Configuration object for projections. Some options will have no effect if a Volume or FBVolume."""
826
+ """Configuration object for projections. This is to be passed to the `project` method. Some options will have no effect if applied improperly to a `Volume`/`FBVolume`."""
813
827
 
814
828
  _contents: np.dtype[structs.config_cb_project] # ty:ignore[invalid-type-arguments]
815
829
  _contents_fb: np.dtype[structs.config_cb_project_FORBILD] # ty:ignore[invalid-type-arguments]
816
830
 
817
831
  @property
818
832
  def contents(self) -> np.dtype[structs.config_cb_project]: # ty:ignore[invalid-type-arguments]
819
- """The configuration object underlying this object."""
833
+ """The configuration object underlying this object, when applied to `Volume`."""
820
834
  return self._contents.copy() # ty:ignore[unresolved-attribute]
821
835
 
822
836
  @property
823
837
  def contents_fb(self) -> np.dtype[structs.config_cb_project_FORBILD]: # ty:ignore[invalid-type-arguments]
824
- """The configuration object underlying this object."""
838
+ """The configuration object underlying this object, when applied to `FBVolume`."""
825
839
  return self._contents_fb.copy() # ty:ignore[unresolved-attribute]
826
840
 
827
841
  def __init__(
@@ -0,0 +1,41 @@
1
+ # Copyright (C) 2026 Murdock Grewar
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+
16
+ """
17
+ A submodule containing example scripts using the Python API.
18
+
19
+ Browse the `aprict` source code and navigate to this directory to see the examples.
20
+
21
+ Examples can be run with e.g. `python -m aprict.examples.EXAMPLE_NAME`.
22
+
23
+ """
24
+
25
+ from . import (
26
+ composite_human_sirt,
27
+ fan_beam_sirt,
28
+ helical_sirt,
29
+ lungs_sirt,
30
+ trajtest_A_sirt,
31
+ triangle_exp_fb,
32
+ )
33
+
34
+ __all__ = [
35
+ "composite_human_sirt",
36
+ "fan_beam_sirt",
37
+ "helical_sirt",
38
+ "lungs_sirt",
39
+ "trajtest_A_sirt",
40
+ "triangle_exp_fb",
41
+ ]
@@ -13,7 +13,7 @@
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
15
 
16
- """Simulate an example experiment with a helical scan."""
16
+ """Simulate an example experiment and SIRT reconstruction using the composite human phantom."""
17
17
 
18
18
  import itertools
19
19
  import math
@@ -174,7 +174,7 @@ def main() -> None: # ruff: ignore[complex-structure, undocumented-public-funct
174
174
  print("Voxel width (mm): ", voxwid_mm)
175
175
  print()
176
176
  print("Creating volume... ", end="", flush=True)
177
- vol: aprict.FBVolume = aprict.phantoms.FORBILD.CustomComposite
177
+ vol: aprict.FBVolume = aprict.phantoms.FORBILD.CustomComposite()
178
178
  if plot_volume:
179
179
  print("plotting volume... ", end="", flush=True)
180
180
  xs = np.linspace(-300, 300, num=601, endpoint=True)
@@ -13,7 +13,7 @@
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
15
 
16
- """Simulate an example experiment with a helical scan."""
16
+ """Simulate an example 2D fan-beam experiment and SIRT reconstruction."""
17
17
 
18
18
  import math
19
19
  import sys
@@ -99,7 +99,7 @@ def main() -> None: # ruff: ignore[undocumented-public-function]
99
99
 
100
100
  # Create the volume to be projected
101
101
  print("Voxel width (mm): ", voxwid_mm)
102
- vol: aprict.FBVolume = aprict.phantoms.FORBILD.HeadPhantom
102
+ vol: aprict.FBVolume = aprict.phantoms.FORBILD.HeadPhantom()
103
103
  xyz_min, xyz_max = vol.minxyz_maxxyz
104
104
  volwid_mm = 1.1 * 2 * max(map(abs, (*xyz_min[:2], *xyz_max[:2])))
105
105
 
@@ -13,7 +13,7 @@
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
15
 
16
- """Simulate an example experiment with a helical scan."""
16
+ """Simulate an example experiment and SIRT reconstruction with a helical scan."""
17
17
 
18
18
  import math
19
19
  import sys
@@ -106,7 +106,7 @@ def main() -> None: # ruff: ignore[undocumented-public-function]
106
106
 
107
107
  # Create the volume to be projected
108
108
  print("Voxel width (mm): ", voxwid_mm)
109
- vol: aprict.FBVolume = aprict.phantoms.FORBILD.HeadPhantom
109
+ vol: aprict.FBVolume = aprict.phantoms.FORBILD.HeadPhantom()
110
110
  volwid_mm = 250 # in the future, fetch from the phantom
111
111
  # Scale up the volume
112
112
  vol.scale_len(scale_phantom_size)
@@ -1,3 +1,4 @@
1
+ # ruff: ignore[invalid-module-name]
1
2
  # Copyright (C) 2026 Murdock Grewar
2
3
  #
3
4
  # This program is free software: you can redistribute it and/or modify
@@ -12,8 +13,7 @@
12
13
  #
13
14
  # You should have received a copy of the GNU General Public License
14
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
-
16
- """Simulate an example experiment with a helical scan."""
16
+ """Simulate an example experiment and SIRT reconstruction with a cylindrical scan."""
17
17
 
18
18
  import math
19
19
  import sys
@@ -106,7 +106,7 @@ def main() -> None: # ruff: ignore[undocumented-public-function]
106
106
 
107
107
  # Create the volume to be projected
108
108
  print("Voxel width (mm): ", voxwid_mm)
109
- vol: aprict.FBVolume = aprict.phantoms.FORBILD.HeadPhantom
109
+ vol: aprict.FBVolume = aprict.phantoms.FORBILD.HeadPhantom()
110
110
  volwid_mm = 275 # in the future, fetch from the phantom
111
111
  # Scale up the volume
112
112
  vol.scale_len(scale_phantom_size)
@@ -246,8 +246,8 @@ def main() -> None: # ruff: ignore[undocumented-public-function]
246
246
  _lp_process, lp_dispatcher = liveplot.start_live_plot_2d(
247
247
  title="Live plot",
248
248
  histogram_label="Attenuation coefficient",
249
- plotmin=0.0184 * voxwid_mm * (1 + default_plot_range_HU[0] / 1000),
250
- plotmax=0.0184 * voxwid_mm * (1 + default_plot_range_HU[1] / 1000),
249
+ plotmin=0.0184 * (1 + default_plot_range_HU[0] / 1000),
250
+ plotmax=0.0184 * (1 + default_plot_range_HU[1] / 1000),
251
251
  show=False,
252
252
  )
253
253
 
@@ -13,7 +13,7 @@
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
15
 
16
- """Simulate an example experiment with a triangular scanning apparatus."""
16
+ """Simulate an example experiment and Landweber reconstruction with a triangular scanning apparatus."""
17
17
 
18
18
  import itertools
19
19
  import math
@@ -243,8 +243,8 @@ def main() -> None: # ruff: ignore[undocumented-public-function]
243
243
 
244
244
  # Create the volume to be projected
245
245
  print("Voxel width (mm): ", voxwid_mm)
246
- # vol: aprict.FBVolume = aprict.phantoms.FORBILD.HeadPhantom
247
- vol: aprict.FBVolume = aprict.phantoms.FORBILD.CustomComposite
246
+ # vol: aprict.FBVolume = aprict.phantoms.FORBILD.HeadPhantom()
247
+ vol: aprict.FBVolume = aprict.phantoms.FORBILD.CustomComposite()
248
248
  volwid_mm = 300 # in the future, fetch from the phantom
249
249
  # Scale up the volume
250
250
  vol.scale_len(scale_phantom_size)
@@ -14,9 +14,10 @@
14
14
  # You should have received a copy of the GNU General Public License
15
15
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
 
17
- """Provides FORBILD phantoms from the files published by the Arbeitsgruppe Phantome."""
17
+ """Provides FORBILD phantoms from the files published by the Arbeitsgruppe Phantome, as well as others."""
18
18
 
19
19
  import dataclasses
20
+ import functools
20
21
  import itertools
21
22
  import math
22
23
  import pathlib
@@ -30,19 +31,23 @@ from ..cuda.structs import FORBILD_volumes as fv
30
31
  from ..lib import process_pha_file as ppf
31
32
  from ..volume import FBVolume
32
33
 
33
- path_to_FORBILD_src = pathlib.Path(str(data.__path__[0])).joinpath("FORBILD") # ruff: ignore[mixed-case-variable-in-global-scope]
34
+ _path_to_FORBILD_src = pathlib.Path(str(data.__path__[0])).joinpath("FORBILD") # ruff: ignore[mixed-case-variable-in-global-scope]
34
35
 
35
36
 
36
- # ruff: disable[invalid-function-name,missing-trailing-period]
37
+ # ruff: disable[non-imperative-mood,invalid-function-name]
37
38
 
38
39
 
39
- class _MetaPhantomContainer(type):
40
- @property
40
+ class PhantomContainer:
41
+ """A container for the phantom objects."""
42
+
43
+ @classmethod
44
+ @functools.cache
41
45
  def CustomComposite(cls) -> FBVolume:
46
+ """A custom phantom stitching together and slightly modifying the Hip, Abdomen, Thorax, Head and Jaw phantom."""
42
47
  hi, ab, th, he, ja = [
43
48
  FBVolume(
44
49
  ppf.convert_ph_file_to_shapes(
45
- path_to_FORBILD_src.joinpath("custom_composite/" + fn)
50
+ _path_to_FORBILD_src.joinpath("custom_composite/" + fn)
46
51
  )
47
52
  )
48
53
  for fn in (
@@ -105,12 +110,13 @@ class _MetaPhantomContainer(type):
105
110
  v = v.superimpose_onto(cavity)
106
111
  return v # ruff: ignore[unnecessary-assign]
107
112
 
108
- @property
113
+ @classmethod
114
+ @functools.cache
109
115
  def JawPhantom(cls) -> FBVolume:
110
- """The JawPhantom.txt"""
116
+ """The [Jaw phantom](https://www.dkfz.de/en/x-ray-imaging-and-computed-tomography/jaw-phantom)."""
111
117
  fbv = FBVolume(
112
118
  ppf.convert_ph_file_to_shapes(
113
- path_to_FORBILD_src.joinpath("jaw/JawPhantom.pha")
119
+ _path_to_FORBILD_src.joinpath("jaw/JawPhantom.pha")
114
120
  )
115
121
  )
116
122
  # Phantom is defined with centimeters as the unit of length.
@@ -118,12 +124,13 @@ class _MetaPhantomContainer(type):
118
124
  fbv.scale_len(10)
119
125
  return fbv
120
126
 
121
- @property
127
+ @classmethod
128
+ @functools.cache
122
129
  def HeadPhantom(cls) -> FBVolume:
123
- """HeadPhantom.pha"""
130
+ """The [Head phantom](https://www.dkfz.de/en/x-ray-imaging-and-computed-tomography/head-phantom)."""
124
131
  fbv = FBVolume(
125
132
  ppf.convert_ph_file_to_shapes(
126
- path_to_FORBILD_src.joinpath("head/HeadPhantom.pha")
133
+ _path_to_FORBILD_src.joinpath("head/HeadPhantom.pha")
127
134
  )
128
135
  )
129
136
  # Phantom is defined with centimeters as the unit of length.
@@ -131,12 +138,13 @@ class _MetaPhantomContainer(type):
131
138
  fbv.scale_len(10)
132
139
  return fbv
133
140
 
134
- @property
141
+ @classmethod
142
+ @functools.cache
135
143
  def HipPhantom(cls) -> FBVolume:
136
- """HipPhantom.pha"""
144
+ """The [Hip phantom](https://www.dkfz.de/en/x-ray-imaging-and-computed-tomography/hip-phantom)."""
137
145
  fbv = FBVolume(
138
146
  ppf.convert_ph_file_to_shapes(
139
- path_to_FORBILD_src.joinpath("hip/HipPhantom.pha")
147
+ _path_to_FORBILD_src.joinpath("hip/HipPhantom.pha")
140
148
  )
141
149
  )
142
150
  # Phantom is defined with centimeters as the unit of length.
@@ -144,13 +152,14 @@ class _MetaPhantomContainer(type):
144
152
  fbv.scale_len(10)
145
153
  return fbv
146
154
 
147
- @property
155
+ @classmethod
156
+ @functools.cache
148
157
  def AbdomenPhantom(cls) -> FBVolume:
149
- """Fixed AbdomenPhantom.txt"""
158
+ """Fixed [Abdomen phantom](https://www.dkfz.de/en/x-ray-imaging-and-computed-tomography/abdominal-phantom)."""
150
159
  # The AbdomenPhantom.pha file has a bug in it. Load a manually fixed version.
151
160
  fbv = FBVolume(
152
161
  ppf.convert_ph_file_to_shapes(
153
- path_to_FORBILD_src.joinpath(
162
+ _path_to_FORBILD_src.joinpath(
154
163
  "abdomen/AbdomenPhantom_fixed.pha"
155
164
  )
156
165
  )
@@ -160,13 +169,14 @@ class _MetaPhantomContainer(type):
160
169
  fbv.scale_len(10)
161
170
  return fbv
162
171
 
163
- @property
172
+ @classmethod
173
+ @functools.cache
164
174
  def LungPhantom3Generations(cls) -> FBVolume:
165
- """LungPhantom3Generations.pha"""
175
+ """The [Lung phantom](https://www.dkfz.de/en/x-ray-imaging-and-computed-tomography/lung-phantom) to 3 generations."""
166
176
  # DEV NOTE: make sure this phantom loads the reference file published by the Arbeitsgruppe Phantome. This is used in a unittest to ensure that the generation procedure for N generations matches in this case.
167
177
  fbv = FBVolume(
168
178
  ppf.convert_ph_file_to_shapes(
169
- path_to_FORBILD_src.joinpath(
179
+ _path_to_FORBILD_src.joinpath(
170
180
  "lungs/LungPhantom3Generations.pha"
171
181
  )
172
182
  )
@@ -175,12 +185,13 @@ class _MetaPhantomContainer(type):
175
185
  fbv.flip(axis="z")
176
186
  return fbv
177
187
 
178
- @property
188
+ @classmethod
189
+ @functools.cache
179
190
  def ThoraxPhantom(cls) -> FBVolume:
180
- """ThoraxPhantom.pha"""
191
+ """The [Thorax phantom](https://www.dkfz.de/en/x-ray-imaging-and-computed-tomography/thorax-phantom)."""
181
192
  fbv = FBVolume(
182
193
  ppf.convert_ph_file_to_shapes(
183
- path_to_FORBILD_src.joinpath("thorax/ThoraxPhantom.pha")
194
+ _path_to_FORBILD_src.joinpath("thorax/ThoraxPhantom.pha")
184
195
  )
185
196
  )
186
197
  # Phantom is defined with centimeters as the unit of length.
@@ -188,11 +199,13 @@ class _MetaPhantomContainer(type):
188
199
  fbv.scale_len(10)
189
200
  return fbv
190
201
 
191
- @property
202
+ @classmethod
203
+ @functools.cache
192
204
  def RockCanisterAl(cls) -> FBVolume:
205
+ """A phantom resembling a 6-millimeter-wide double-chambered tube of rocks."""
193
206
  fbv = FBVolume(
194
207
  ppf.convert_ph_file_to_shapes(
195
- path_to_FORBILD_src.joinpath(
208
+ _path_to_FORBILD_src.joinpath(
196
209
  "custom_other/rock_canister_01.pha"
197
210
  ),
198
211
  skip_preprocessing=True, # I know that this file doesn't require preprocessing
@@ -202,26 +215,30 @@ class _MetaPhantomContainer(type):
202
215
  fbv.multiply_attenuation(0.55)
203
216
  return fbv
204
217
 
205
- @property
218
+ @classmethod
219
+ @functools.cache
206
220
  def RockCanisterCavities1e5(cls) -> FBVolume:
221
+ """An appendage to the RockCanisterAl phantom which adds small cavities to the aluminium canister."""
207
222
  return FBVolume(
208
223
  ppf.convert_ph_file_to_shapes(
209
- path_to_FORBILD_src.joinpath(
224
+ _path_to_FORBILD_src.joinpath(
210
225
  "custom_other/rock_canister_01_cavities_1e5.pha"
211
226
  ),
212
227
  skip_preprocessing=True, # I know that this file doesn't require preprocessing
213
228
  )
214
229
  )
215
230
 
216
- @property
231
+ @classmethod
232
+ @functools.cache
217
233
  def RockCanisterAlWithHoles(cls) -> FBVolume:
234
+ """A phantom resembling a 6-millimeter-wide double-chambered tube of rocks, with small cavities inthe aluminium cylinder."""
218
235
  fbv = FBVolume(
219
236
  ppf.convert_ph_file_to_shapes(
220
- path_to_FORBILD_src.joinpath(
237
+ _path_to_FORBILD_src.joinpath(
221
238
  "custom_other/rock_canister_01.pha"
222
239
  ),
223
240
  append_files=(
224
- path_to_FORBILD_src.joinpath(
241
+ _path_to_FORBILD_src.joinpath(
225
242
  "custom_other/rock_canister_01_cavities_1e5.pha"
226
243
  ),
227
244
  ),
@@ -232,18 +249,16 @@ class _MetaPhantomContainer(type):
232
249
  fbv.multiply_attenuation(0.55)
233
250
  return fbv
234
251
 
235
- @property
252
+ @classmethod
253
+ @functools.cache
236
254
  def UnitCyl_z(cls) -> FBVolume:
255
+ """Unit z cylinder."""
237
256
  return FBVolume(
238
257
  ppf.convert_ph_file_to_shapes(
239
- path_to_FORBILD_src.joinpath("custom_other/unit_Cyl_z.pha")
258
+ _path_to_FORBILD_src.joinpath("custom_other/unit_Cyl_z.pha")
240
259
  )
241
260
  )
242
261
 
243
-
244
- class PhantomContainer(metaclass=_MetaPhantomContainer):
245
- """A container for the phantom objects."""
246
-
247
262
  @classmethod
248
263
  def _LungPhantom_phastring( # ruff: ignore[complex-structure]
249
264
  cls,
@@ -254,7 +269,7 @@ class PhantomContainer(metaclass=_MetaPhantomContainer):
254
269
  fix: bool
255
270
  | None = None, # Leave at None for default configuration. Turning this True will fix what appear to be errors in the original phantom. These errors are particularly noticeable with e.g. taper=True.
256
271
  ) -> str:
257
- """Generate the Lung phantom (by Marc Kachelrieß) up to generation n."""
272
+ """Generate the [Lung phantom](https://www.dkfz.de/en/x-ray-imaging-and-computed-tomography/lung-phantom) (by Markus Blank and Marc Kachelrieß) up to generation n."""
258
273
  if type(generation) is not int or generation < 2:
259
274
  msg = "'generation' must be an integer >=2"
260
275
  raise ValueError(msg)
@@ -534,7 +549,7 @@ class PhantomContainer(metaclass=_MetaPhantomContainer):
534
549
  fix: bool
535
550
  | None = None, # Leave at None for default configuration. Turning this True will fix what appear to be errors in the original phantom. These errors are particularly noticeable with e.g. taper=True.
536
551
  ) -> FBVolume:
537
- """Generate the Lung phantom (by Marc Kachelrieß) up to generation n."""
552
+ """Generate the [Lung phantom](https://www.dkfz.de/en/x-ray-imaging-and-computed-tomography/lung-phantom) (by Markus Blank and Marc Kachelrieß) up to generation n."""
538
553
  phastr: str = cls._LungPhantom_phastring(
539
554
  generation=generation,
540
555
  scale_factor=scale_factor,
@@ -657,7 +672,7 @@ class PhantomContainer(metaclass=_MetaPhantomContainer):
657
672
  randomise_parity: bool = False,
658
673
  seed: int | None = None,
659
674
  ) -> FBVolume:
660
- """Generate a disc-shaped resolution phantom."""
675
+ """Generate a disc-shaped resolution phantom (use as a 2D phantom with z=0)."""
661
676
  if generation < 1:
662
677
  msg = "Generation should be a positive integer."
663
678
  raise ValueError(msg)
@@ -996,4 +1011,4 @@ class PhantomContainer(metaclass=_MetaPhantomContainer):
996
1011
  return FBVolume(np.array(shapes, dtype=fv.Shape))
997
1012
 
998
1013
 
999
- # ruff: enable[invalid-function-name,missing-trailing-period]
1014
+ # ruff: enable[non-imperative-mood,invalid-function-name]
@@ -13,7 +13,11 @@
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
15
 
16
- """Phantom objects useful for simulations and testing."""
16
+ """
17
+ Phantom objects useful for simulations and testing.
18
+
19
+ These can be loaded with e.g. `aprict.phantoms.FORBILD.HeadPhantom()`.
20
+ """
17
21
 
18
22
  from .FORBILD_phantoms import (
19
23
  PhantomContainer as FORBILD, # ruff: ignore[camelcase-imported-as-constant]
@@ -0,0 +1,20 @@
1
+ # Copyright (C) 2026 Murdock Grewar
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+
16
+ """
17
+ Scripts to use `aprict` with a commandline interface.
18
+
19
+ The recommended entry point is `aprict.scripts.cli`, which is a wrapper for the other scirpts. When `aprict` is installed in the current environment, this can be called from the shell with `aprict-cli`.
20
+ """
@@ -13,7 +13,7 @@
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
15
 
16
- """aprict-cli: the main command-line interface to aprict."""
16
+ """The main command-line interface to aprict."""
17
17
 
18
18
  import click_extra as ce
19
19
 
@@ -36,7 +36,7 @@ _cs = {
36
36
  }
37
37
 
38
38
 
39
- @ce.group(name="aprict-cli", params=None, help=_progdesc, context_settings=_cs)
39
+ @ce.group(name="aprict", params=None, help=_progdesc, context_settings=_cs)
40
40
  @ce.version_option(version=version) # add --version from click_extra
41
41
  @ce.tree_option() # add --tree option from click_extra
42
42
  # not including the man_option because it includes incorrect information, like possible exit codes etc.