aprict 0.0.23__tar.gz → 0.0.24.dev1__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.
- {aprict-0.0.23/src/aprict.egg-info → aprict-0.0.24.dev1}/PKG-INFO +19 -12
- {aprict-0.0.23 → aprict-0.0.24.dev1}/README.md +18 -11
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cb/flatpanel.py +6 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/ne_tools.py +4 -1
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/logtools/pbar.py +5 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/scripts/recon_cbfp_cyl_fbp.py +7 -6
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/scripts/recon_cbfp_cyl_gbc.py +72 -25
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/scripts/recon_cbfp_landweber.py +1 -1
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/version.py +1 -1
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/volume.py +15 -2
- {aprict-0.0.23 → aprict-0.0.24.dev1/src/aprict.egg-info}/PKG-INFO +19 -12
- {aprict-0.0.23 → aprict-0.0.24.dev1}/LICENSE.txt +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/LICENSE_GPLv3.txt +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/MANIFEST.in +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/pyproject.toml +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/setup.cfg +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/setup.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cb/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cb/_unused_old_fbp.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cb/noop_filter.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cb/ramp_filter.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cb/ramp_filter_cpu.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/_generate_cusrc.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/dtype_cacher.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/header_injection.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/kern_structs.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/ptx_cacher.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/FORBILD_volumes.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/base.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/config_cb_backproject.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/config_cb_project.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/config_cb_project_FORBILD.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Box.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_ClipAxisSpec.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Cone.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Cone_x.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Cone_y.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Cone_z.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Cylinder.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Cylinder_x.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Cylinder_y.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Cylinder_z.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Ellipsoid.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Ellipsoid_free.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Ellipt_Cyl.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Ellipt_Cyl_x.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Ellipt_Cyl_y.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Ellipt_Cyl_z.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Shape.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/FORBILD_Sphere.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/cu/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/geometry.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/test_subdir/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/cuda/structs/test_subdir/test_config.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/.gitignore +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/abdomen/AbdomenPhantom.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/abdomen/AbdomenPhantom_fixed.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/abdomen/TableOfTissues +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/abdomen/Wirbel.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_composite/Ribs.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_composite/Shoulders.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_composite/TableOfTissues +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_composite/Vertebra.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_composite/part_01_hip.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_composite/part_02_abdomen.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_composite/part_03_thorax.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_composite/part_04_head.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_composite/part_05_jaw.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_other/rock_canister_01.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_other/rock_canister_01_cavities_1e5.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/custom_other/unit_Cyl_z.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/head/HeadPhantom.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/head/TableOfTissues +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/hip/HipPhantom.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/jaw/JawPhantom.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/lungs/LungPhantom3Generations.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/thorax/Ribs.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/thorax/Shoulders.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/thorax/TableOfTissues +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/thorax/ThoraxPhantom.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/FORBILD/thorax/Vertebra.pha +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/README.txt +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/CB_backproject.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/CB_backproject_sharedmem.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/CB_project_sharedmem.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/CB_project_texture_chunked.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/FORBILD_volumes.h +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/base.h +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/config_cb_backproject.h +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/config_cb_project.h +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/config_cb_project_FORBILD.h +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/geometry.h +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/get_bboxes_FORBILD.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/ramlak_convolve.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/sample_FORBILD_volumes.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/test_kernel.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/test_subdir/test_config.h +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/data/cusrc/texture_operations.cu +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/examples/composite_human_sirt.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/examples/fan_beam_sirt.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/examples/helical_sirt.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/examples/lungs_sirt.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/examples/trajtest_A_sirt.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/examples/triangle_exp_fb.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/gbc/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/gbc/filters.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/gbc/weightinteg.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/image_view.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/iterators/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/iterators/landweber_vram.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/iterators/sirt_vram.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/argparse_tools.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/bboxes_FORBILD.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/click_tools.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/empty_context_manager.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/gpu_tools.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/import_tools.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/lds.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/ng_tools.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/np_tools.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/process_pha_file.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/sample_FORBILD.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/texture_tools/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/texture_tools/operations.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/lib/texture_tools/texture.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/liveplot.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/logtools/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/logtools/config.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/logtools/pbar_tqdm.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/logtools/rich_custombar.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/phantoms/FORBILD_phantoms.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/phantoms/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/ramp_kernels.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/scripts/cli.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/scripts/make_geometry_cone_cyl.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/scripts/make_geometry_fan_circ.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/scripts/neuroglance.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/scripts/project_cbfp.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/tests/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/tests/cuda_kernels/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/tests/cuda_kernels/test_backproject_cb.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/tests/cuda_kernels/test_cusrc/__init__.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/tests/cuda_kernels/test_kernel_structs.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/tests/cuda_kernels/test_project_cb.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/tests/cuda_kernels/test_project_cb_FORBILD_phantoms.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/tests/cuda_kernels/test_project_cb_FORBILD_shapes.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/tests/test_FORBILD_lungs_construction.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict/tests/test_volume.py +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict.egg-info/SOURCES.txt +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict.egg-info/dependency_links.txt +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict.egg-info/entry_points.txt +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/src/aprict.egg-info/requires.txt +0 -0
- {aprict-0.0.23 → aprict-0.0.24.dev1}/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.
|
|
3
|
+
Version: 0.0.24.dev1
|
|
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>
|
|
@@ -36,6 +36,10 @@ Requires-Dist: neuroglancer>=2.41.0; extra == "gui"
|
|
|
36
36
|
Dynamic: author
|
|
37
37
|
Dynamic: license-file
|
|
38
38
|
|
|
39
|
+
[](https://orcid.org/0000-0002-0015-8284)
|
|
40
|
+
[](https://doi.org/10.5281/zenodo.23632625)
|
|
41
|
+

|
|
42
|
+
[](https://www.repostatus.org/#wip)
|
|
39
43
|
<details open><summary><h1>About</h1></summary>
|
|
40
44
|
|
|
41
45
|
Description
|
|
@@ -71,8 +75,7 @@ Known limitations
|
|
|
71
75
|
* Volume size is limited by CUDA texture limit. For example, a `(2400,2400,4800)` volume can be reconstructed, but not a `(30000,30000,1)` volume, due to a volume of this size not fitting within a single CUDA texture
|
|
72
76
|
* The FORBILD shape `Tetrahedron` is not yet implemented, and no primitive shape is permitted to have more than 3 clipping planes applied, due to internal limitations. All other FORBILD phantoms should be supported.
|
|
73
77
|
* Only one GPU is utilised by this module, at the present time. There is no defined behaviour for which GPU will be chosen.
|
|
74
|
-
* Not fully optimised
|
|
75
|
-
* the GBC reconstruction script assumes that the whole volume (or more) can fit in RAM. This limitation may be lifted in the future. (Note: a present workaround is to create a large swapfile on disk, since swap space is treated as RAM when the physical RAM is exhausted.)
|
|
78
|
+
* Not fully optimised
|
|
76
79
|
* CPU and GPU work not completely asynchronous: due to unresolved bugs, various asynchronous GPU operations have been disabled. This may not have much impact on large reconstructions, but could result in poor GPU utilisation for smaller reconstructions.
|
|
77
80
|
* No smart batching of (back)projections: smarter code would analyse the geometry of projections, and batch together (back)projections that involve similar regions of the volume. Currently, the code does not do any kind of clever batching like this, and so the (back)projection code is not as performant as it could be.
|
|
78
81
|
|
|
@@ -99,7 +102,7 @@ You can install `aprict` like you would any python package, using `pip install`.
|
|
|
99
102
|
Example installation using `uv`:
|
|
100
103
|
```bash
|
|
101
104
|
$ uv venv -p 3.14
|
|
102
|
-
$ uv pip install aprict[gui]==0.0.
|
|
105
|
+
$ uv pip install aprict[gui]==0.0.24
|
|
103
106
|
$ source .venv/bin/activate
|
|
104
107
|
```
|
|
105
108
|
You should now have several executables available on `$PATH`. Try `aprict-cli --help` to see the polished commandline interface.
|
|
@@ -118,11 +121,11 @@ Activate the environment:
|
|
|
118
121
|
```bash
|
|
119
122
|
source .venv/bin/activate
|
|
120
123
|
```
|
|
121
|
-
Now, try the shell command `aprict-cli --help`. Here is the output as at `v0.0.
|
|
124
|
+
Now, try the shell command `aprict-cli --help`. Here is the output as at `v0.0.24`:
|
|
122
125
|
```
|
|
123
126
|
Usage: aprict-cli [OPTIONS] COMMAND [ARGS]...
|
|
124
127
|
|
|
125
|
-
Entry point for aprict
|
|
128
|
+
Entry point for CLI interface to aprict version 0.0.24
|
|
126
129
|
|
|
127
130
|
Options:
|
|
128
131
|
--version Show the version and exit.
|
|
@@ -170,8 +173,8 @@ aprict-cli project cbfp \
|
|
|
170
173
|
--output projs \
|
|
171
174
|
--plot-mode PYQTGRAPH
|
|
172
175
|
````
|
|
173
|
-
(Time on my machine: ~2 minutes,
|
|
174
|
-
The option `--plot-mode PYQTGRAPH` will display a plot window of the projection data after it is created. (This will not be available if the module was not installed with the `[gui]` option.)
|
|
176
|
+
(Time on my machine: ~2 minutes, 56 seconds)
|
|
177
|
+
The options `--ssu 3 --ssv 3` indicate that the line attenuation for each detector pixel is to be calculated as the average of a 3-by-3 grid of exact line integrals. This kind of improved accuracy is necessary for some phantoms, including this one, if using a large detector pixel size. The option `--plot-mode PYQTGRAPH` will display a plot window of the projection data after it is created. (This will not be available if the module was not installed with the `[gui]` option.)
|
|
175
178
|
|
|
176
179
|
Now, let's reconstruct with three different algorithms:
|
|
177
180
|
1. Global Backprojection-Convolution (GBC)
|
|
@@ -186,10 +189,14 @@ aprict-cli recon gbc-cone-cyl \
|
|
|
186
189
|
--voxwid 0.5 \
|
|
187
190
|
--volshape '(525,525,525)' \
|
|
188
191
|
--alg GREWAR \
|
|
192
|
+
--f1 1.2 \
|
|
193
|
+
--f2 6 \
|
|
194
|
+
--n 9 \
|
|
195
|
+
--eps 1e-9 \
|
|
189
196
|
--output recon_gbc \
|
|
190
197
|
--plot-mode PYQTGRAPH
|
|
191
198
|
```
|
|
192
|
-
(Time on my machine: ~
|
|
199
|
+
(Time on my machine: ~39 seconds)
|
|
193
200
|
|
|
194
201
|
To perform an FBP reconstruction, we do:
|
|
195
202
|
```bash
|
|
@@ -202,7 +209,7 @@ aprict-cli recon fbp-cone-cyl \
|
|
|
202
209
|
--output recon_fbp \
|
|
203
210
|
--plot-mode PYQTGRAPH
|
|
204
211
|
```
|
|
205
|
-
(Time on my machine: ~
|
|
212
|
+
(Time on my machine: ~19 seconds)
|
|
206
213
|
|
|
207
214
|
To perform an FBP-VM reconstruction, we change `--alg` to `NOOGREWAR`:
|
|
208
215
|
```bash
|
|
@@ -215,7 +222,7 @@ aprict-cli recon fbp-cone-cyl \
|
|
|
215
222
|
--output recon_fbp-vw \
|
|
216
223
|
--plot-mode PYQTGRAPH
|
|
217
224
|
```
|
|
218
|
-
(Time on my machine: ~
|
|
225
|
+
(Time on my machine: ~26 seconds)
|
|
219
226
|
|
|
220
227
|
|
|
221
228
|
</details>
|
|
@@ -253,7 +260,7 @@ aprict-cli project cbfp \
|
|
|
253
260
|
--output projs \
|
|
254
261
|
--plot-mode PYQTGRAPH
|
|
255
262
|
````
|
|
256
|
-
(Time on my machine: ~1 minute,
|
|
263
|
+
(Time on my machine: ~1 minute, 48 seconds)
|
|
257
264
|
The option `--plot-mode PYQTGRAPH` will display a plot window of the projection data (a sinogram) after it is created. (This will not be available if the module was not installed with the `[gui]` option.)
|
|
258
265
|
|
|
259
266
|
You will find a copy of the `ROCK_CAN` phantom in the output directory `projs`, beside the projection data. The phantom is always copied to the output directory, to ensure a good record of the inputs to the simulation.
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
[](https://orcid.org/0000-0002-0015-8284)
|
|
2
|
+
[](https://doi.org/10.5281/zenodo.23632625)
|
|
3
|
+

|
|
4
|
+
[](https://www.repostatus.org/#wip)
|
|
1
5
|
<details open><summary><h1>About</h1></summary>
|
|
2
6
|
|
|
3
7
|
Description
|
|
@@ -33,8 +37,7 @@ Known limitations
|
|
|
33
37
|
* Volume size is limited by CUDA texture limit. For example, a `(2400,2400,4800)` volume can be reconstructed, but not a `(30000,30000,1)` volume, due to a volume of this size not fitting within a single CUDA texture
|
|
34
38
|
* The FORBILD shape `Tetrahedron` is not yet implemented, and no primitive shape is permitted to have more than 3 clipping planes applied, due to internal limitations. All other FORBILD phantoms should be supported.
|
|
35
39
|
* Only one GPU is utilised by this module, at the present time. There is no defined behaviour for which GPU will be chosen.
|
|
36
|
-
* Not fully optimised
|
|
37
|
-
* the GBC reconstruction script assumes that the whole volume (or more) can fit in RAM. This limitation may be lifted in the future. (Note: a present workaround is to create a large swapfile on disk, since swap space is treated as RAM when the physical RAM is exhausted.)
|
|
40
|
+
* Not fully optimised
|
|
38
41
|
* CPU and GPU work not completely asynchronous: due to unresolved bugs, various asynchronous GPU operations have been disabled. This may not have much impact on large reconstructions, but could result in poor GPU utilisation for smaller reconstructions.
|
|
39
42
|
* No smart batching of (back)projections: smarter code would analyse the geometry of projections, and batch together (back)projections that involve similar regions of the volume. Currently, the code does not do any kind of clever batching like this, and so the (back)projection code is not as performant as it could be.
|
|
40
43
|
|
|
@@ -61,7 +64,7 @@ You can install `aprict` like you would any python package, using `pip install`.
|
|
|
61
64
|
Example installation using `uv`:
|
|
62
65
|
```bash
|
|
63
66
|
$ uv venv -p 3.14
|
|
64
|
-
$ uv pip install aprict[gui]==0.0.
|
|
67
|
+
$ uv pip install aprict[gui]==0.0.24
|
|
65
68
|
$ source .venv/bin/activate
|
|
66
69
|
```
|
|
67
70
|
You should now have several executables available on `$PATH`. Try `aprict-cli --help` to see the polished commandline interface.
|
|
@@ -80,11 +83,11 @@ Activate the environment:
|
|
|
80
83
|
```bash
|
|
81
84
|
source .venv/bin/activate
|
|
82
85
|
```
|
|
83
|
-
Now, try the shell command `aprict-cli --help`. Here is the output as at `v0.0.
|
|
86
|
+
Now, try the shell command `aprict-cli --help`. Here is the output as at `v0.0.24`:
|
|
84
87
|
```
|
|
85
88
|
Usage: aprict-cli [OPTIONS] COMMAND [ARGS]...
|
|
86
89
|
|
|
87
|
-
Entry point for aprict
|
|
90
|
+
Entry point for CLI interface to aprict version 0.0.24
|
|
88
91
|
|
|
89
92
|
Options:
|
|
90
93
|
--version Show the version and exit.
|
|
@@ -132,8 +135,8 @@ aprict-cli project cbfp \
|
|
|
132
135
|
--output projs \
|
|
133
136
|
--plot-mode PYQTGRAPH
|
|
134
137
|
````
|
|
135
|
-
(Time on my machine: ~2 minutes,
|
|
136
|
-
The option `--plot-mode PYQTGRAPH` will display a plot window of the projection data after it is created. (This will not be available if the module was not installed with the `[gui]` option.)
|
|
138
|
+
(Time on my machine: ~2 minutes, 56 seconds)
|
|
139
|
+
The options `--ssu 3 --ssv 3` indicate that the line attenuation for each detector pixel is to be calculated as the average of a 3-by-3 grid of exact line integrals. This kind of improved accuracy is necessary for some phantoms, including this one, if using a large detector pixel size. The option `--plot-mode PYQTGRAPH` will display a plot window of the projection data after it is created. (This will not be available if the module was not installed with the `[gui]` option.)
|
|
137
140
|
|
|
138
141
|
Now, let's reconstruct with three different algorithms:
|
|
139
142
|
1. Global Backprojection-Convolution (GBC)
|
|
@@ -148,10 +151,14 @@ aprict-cli recon gbc-cone-cyl \
|
|
|
148
151
|
--voxwid 0.5 \
|
|
149
152
|
--volshape '(525,525,525)' \
|
|
150
153
|
--alg GREWAR \
|
|
154
|
+
--f1 1.2 \
|
|
155
|
+
--f2 6 \
|
|
156
|
+
--n 9 \
|
|
157
|
+
--eps 1e-9 \
|
|
151
158
|
--output recon_gbc \
|
|
152
159
|
--plot-mode PYQTGRAPH
|
|
153
160
|
```
|
|
154
|
-
(Time on my machine: ~
|
|
161
|
+
(Time on my machine: ~39 seconds)
|
|
155
162
|
|
|
156
163
|
To perform an FBP reconstruction, we do:
|
|
157
164
|
```bash
|
|
@@ -164,7 +171,7 @@ aprict-cli recon fbp-cone-cyl \
|
|
|
164
171
|
--output recon_fbp \
|
|
165
172
|
--plot-mode PYQTGRAPH
|
|
166
173
|
```
|
|
167
|
-
(Time on my machine: ~
|
|
174
|
+
(Time on my machine: ~19 seconds)
|
|
168
175
|
|
|
169
176
|
To perform an FBP-VM reconstruction, we change `--alg` to `NOOGREWAR`:
|
|
170
177
|
```bash
|
|
@@ -177,7 +184,7 @@ aprict-cli recon fbp-cone-cyl \
|
|
|
177
184
|
--output recon_fbp-vw \
|
|
178
185
|
--plot-mode PYQTGRAPH
|
|
179
186
|
```
|
|
180
|
-
(Time on my machine: ~
|
|
187
|
+
(Time on my machine: ~26 seconds)
|
|
181
188
|
|
|
182
189
|
|
|
183
190
|
</details>
|
|
@@ -215,7 +222,7 @@ aprict-cli project cbfp \
|
|
|
215
222
|
--output projs \
|
|
216
223
|
--plot-mode PYQTGRAPH
|
|
217
224
|
````
|
|
218
|
-
(Time on my machine: ~1 minute,
|
|
225
|
+
(Time on my machine: ~1 minute, 48 seconds)
|
|
219
226
|
The option `--plot-mode PYQTGRAPH` will display a plot window of the projection data (a sinogram) after it is created. (This will not be available if the module was not installed with the `[gui]` option.)
|
|
220
227
|
|
|
221
228
|
You will find a copy of the `ROCK_CAN` phantom in the output directory `projs`, beside the projection data. The phantom is always copied to the output directory, to ensure a good record of the inputs to the simulation.
|
|
@@ -33,6 +33,7 @@ import numpy.typing as npt # ruff: ignore[unused-import]
|
|
|
33
33
|
from .. import logtools
|
|
34
34
|
from ..cuda import header_injection, structs
|
|
35
35
|
from ..cuda.kern_structs import _np_dtype_to_c_type
|
|
36
|
+
from ..lib import gpu_tools
|
|
36
37
|
from ..volume import FBVolume, Volume
|
|
37
38
|
|
|
38
39
|
_delay_compile: bool = (
|
|
@@ -801,6 +802,11 @@ class ProjectionSet:
|
|
|
801
802
|
)
|
|
802
803
|
return ProjectionSet(self._proj_geom, data=cp.zeros_like(self._data))
|
|
803
804
|
|
|
805
|
+
def __del__(self) -> None: # ruff: ignore[undocumented-magic-method]
|
|
806
|
+
# HOTFIX to work around a pinned-memory leak in CuPy
|
|
807
|
+
# Unfortunately, this reduces GPU utilisation.
|
|
808
|
+
gpu_tools.clear_pinned_cache()
|
|
809
|
+
|
|
804
810
|
|
|
805
811
|
class ConfigProject:
|
|
806
812
|
"""Configuration object for projections. Some options will have no effect if a Volume or FBVolume."""
|
|
@@ -162,12 +162,15 @@ def downbin( # ruff: ignore[complex-structure]
|
|
|
162
162
|
return xnew
|
|
163
163
|
|
|
164
164
|
|
|
165
|
-
def save(path: pathlib.Path, arr: np.ndarray) -> None:
|
|
165
|
+
def save(path: pathlib.Path, arr: np.ndarray, flush: bool = True) -> None:
|
|
166
166
|
"""Save an array to a path in a faster manner than np.save."""
|
|
167
167
|
mm: np.memmap = np.lib.format.open_memmap(
|
|
168
168
|
path, shape=arr.shape, dtype=arr.dtype, mode="w+"
|
|
169
169
|
)
|
|
170
170
|
ne.evaluate("x", out=mm, local_dict={"x": arr})
|
|
171
|
+
if flush:
|
|
172
|
+
# Write changes to disk now.
|
|
173
|
+
mm.flush()
|
|
171
174
|
|
|
172
175
|
|
|
173
176
|
class NETHREADS(enum.Enum):
|
|
@@ -140,6 +140,11 @@ class ProgressBar:
|
|
|
140
140
|
speed_estimate_period=86400, # period in seconds
|
|
141
141
|
)
|
|
142
142
|
|
|
143
|
+
@property
|
|
144
|
+
def maxval(self) -> int | float:
|
|
145
|
+
"""Maximum value of the progress bar."""
|
|
146
|
+
return self._maxval
|
|
147
|
+
|
|
143
148
|
def __enter__(self) -> ProgressBar: # ruff: ignore[undocumented-magic-method]
|
|
144
149
|
if self._enable:
|
|
145
150
|
self._cm.__enter__()
|
|
@@ -872,7 +872,7 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
872
872
|
if logger is not None:
|
|
873
873
|
msg = f"Saving full volume to '{savepath}'..."
|
|
874
874
|
logger.debug(msg)
|
|
875
|
-
lib.ne_tools.save(savepath, x)
|
|
875
|
+
lib.ne_tools.save(savepath, x, flush=True)
|
|
876
876
|
if logger is not None:
|
|
877
877
|
msg = "Full volume now saved to disk."
|
|
878
878
|
logger.debug(msg)
|
|
@@ -1139,16 +1139,17 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
1139
1139
|
logger.debug(msg)
|
|
1140
1140
|
if vol is not None:
|
|
1141
1141
|
# Not efficient. Can't copy from CUDAArray directly to the chunk because it's not C-contiguous.
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1142
|
+
vol.as_numpy(
|
|
1143
|
+
out=vol_np[..., sl_vol], allow_indirect_copy=True
|
|
1144
|
+
)
|
|
1145
|
+
del vol
|
|
1146
|
+
lib.gpu_tools.clear_cache()
|
|
1146
1147
|
else:
|
|
1147
1148
|
msg = "No need to transfer volume chunk from GPU. No work performed."
|
|
1148
1149
|
logger.debug(msg)
|
|
1150
|
+
del vol
|
|
1149
1151
|
|
|
1150
1152
|
# Free some memory
|
|
1151
|
-
del vol
|
|
1152
1153
|
lib.gpu_tools.clear_cache()
|
|
1153
1154
|
lib.gpu_tools.clear_pinned_cache()
|
|
1154
1155
|
|
|
@@ -294,6 +294,12 @@ _progdesc = "Perform an FBP reconstruction from cylindrical flat-panel cone-beam
|
|
|
294
294
|
default=8080,
|
|
295
295
|
help="Port to use for serving things via a web interface, if applicable.",
|
|
296
296
|
),
|
|
297
|
+
ce.option(
|
|
298
|
+
"--memmap-vols",
|
|
299
|
+
type=lib.click_tools.BoolArgType(),
|
|
300
|
+
default=True,
|
|
301
|
+
help="Memory-map volumes, rather than keeping them in RAM.",
|
|
302
|
+
),
|
|
297
303
|
)
|
|
298
304
|
@ce.option_group(
|
|
299
305
|
"resource options",
|
|
@@ -317,6 +323,10 @@ def validate_args(args: types.SimpleNamespace) -> None:
|
|
|
317
323
|
msg = f"Output path '{args.output!s}' already exists."
|
|
318
324
|
raise ce.UsageError(msg)
|
|
319
325
|
|
|
326
|
+
if args.output is None and args.memmap_vols:
|
|
327
|
+
msg = "Cannot use --memmap-vols True while --output is not specified."
|
|
328
|
+
raise ce.UsageError(msg)
|
|
329
|
+
|
|
320
330
|
# If outputting intermediates, then the user must also specify the --output directory
|
|
321
331
|
if args.output_intermediates and not args.output:
|
|
322
332
|
msg = "Cannot output intermediate tomograms when no output directory was specified. Specify an output directory with --output path/to/new/dir"
|
|
@@ -903,9 +913,20 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
903
913
|
|
|
904
914
|
msg = "Allocating and zeroing the backprojection arrays..."
|
|
905
915
|
logger.info(msg)
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
916
|
+
if args.memmap_vols:
|
|
917
|
+
assert path_output is not None # ensured by validate_args(...)
|
|
918
|
+
# These are temporary arrays which may be overwritten during filtration.
|
|
919
|
+
savepath = path_output.joinpath("tmp_backproj" + ".npy")
|
|
920
|
+
vol_np = np.lib.format.open_memmap(
|
|
921
|
+
savepath, shape=padded_volshape, dtype=vol_dtype, mode="w+"
|
|
922
|
+
)
|
|
923
|
+
savepath = path_output.joinpath("tmp_backproj" + "_mini" + ".npy")
|
|
924
|
+
volmini_np = np.lib.format.open_memmap(
|
|
925
|
+
savepath, shape=padded_volshape_mini, dtype=vol_dtype, mode="w+"
|
|
926
|
+
)
|
|
927
|
+
else:
|
|
928
|
+
vol_np = np.empty(padded_volshape, dtype=vol_dtype)
|
|
929
|
+
volmini_np = np.empty(padded_volshape_mini, dtype=vol_dtype)
|
|
909
930
|
lib.ne_tools.set_array_to_constant_pbar(
|
|
910
931
|
vol_np,
|
|
911
932
|
const=0,
|
|
@@ -923,11 +944,18 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
923
944
|
pbar_persist=False,
|
|
924
945
|
)
|
|
925
946
|
|
|
947
|
+
# Convert the progress display ta more intuitive set of units using the progratio.
|
|
948
|
+
# The displayed progress will correspond to bytes in the padded backprojection.
|
|
949
|
+
progratio: float = (
|
|
950
|
+
math.prod(padded_volshape)
|
|
951
|
+
* np.dtype(vol_dtype).itemsize
|
|
952
|
+
/ bytes_cumsum[-1]
|
|
953
|
+
)
|
|
926
954
|
curr_slice: slice | None = None
|
|
927
955
|
logger.info("Beginning reconstruction...")
|
|
928
956
|
with logtools.ProgressBar(
|
|
929
957
|
desc="Backproj.:",
|
|
930
|
-
maxval=
|
|
958
|
+
maxval=math.ceil(bytes_cumsum[-1] * progratio),
|
|
931
959
|
logger=logger,
|
|
932
960
|
persist=True,
|
|
933
961
|
unit_is_bytes=True,
|
|
@@ -1042,7 +1070,8 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
1042
1070
|
prog_evs_bytes.append(
|
|
1043
1071
|
(
|
|
1044
1072
|
ev,
|
|
1045
|
-
|
|
1073
|
+
progratio
|
|
1074
|
+
* (
|
|
1046
1075
|
(
|
|
1047
1076
|
(sl.stop - sl.start)
|
|
1048
1077
|
/ tot_num_nonskipped_projs
|
|
@@ -1075,8 +1104,6 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
1075
1104
|
if tot_num_nonskipped_projs == 0:
|
|
1076
1105
|
msg = "No need to transfer volume chunk from GPU. No work performed."
|
|
1077
1106
|
logger.debug(msg)
|
|
1078
|
-
del vol_weightsum
|
|
1079
|
-
del minivol_weightsum
|
|
1080
1107
|
else:
|
|
1081
1108
|
# Normalise to the correct weighting.
|
|
1082
1109
|
# This will multiply both a numerator and a divisor by the same amount.
|
|
@@ -1120,33 +1147,36 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
1120
1147
|
minivol.divide_softzero(minivol_weightsum, eps=args.eps)
|
|
1121
1148
|
del vol_weightsum
|
|
1122
1149
|
del minivol_weightsum
|
|
1150
|
+
lib.gpu_tools.clear_cache()
|
|
1151
|
+
lib.gpu_tools.clear_pinned_cache()
|
|
1123
1152
|
|
|
1124
1153
|
# Save the backprojections into the arrays
|
|
1125
1154
|
msg = "Transferring backprojected volume chunk from GPU..."
|
|
1126
1155
|
logger.debug(msg)
|
|
1156
|
+
# Copy minivol.
|
|
1157
|
+
# Not efficient. Can't copy from CUDAArray directly to the chunk because it's not C-contiguous.
|
|
1158
|
+
minivol.as_numpy(
|
|
1159
|
+
out=volmini_np[..., sl_minivol], allow_indirect_copy=True
|
|
1160
|
+
)
|
|
1161
|
+
del minivol
|
|
1162
|
+
lib.gpu_tools.clear_cache()
|
|
1163
|
+
# Copy vol.
|
|
1127
1164
|
if vol is not None:
|
|
1128
1165
|
# Not efficient. Can't copy from CUDAArray directly to the chunk because it's not C-contiguous.
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
ans = minivol.as_numpy()
|
|
1135
|
-
lib.ne_tools.fastcopy(src=ans, dst=volmini_np[..., sl_minivol])
|
|
1136
|
-
del ans # allow the memory to be freed
|
|
1137
|
-
lib.gpu_tools.clear_pinned_cache()
|
|
1138
|
-
|
|
1139
|
-
# Free some memory
|
|
1140
|
-
del vol, minivol
|
|
1141
|
-
lib.gpu_tools.clear_pinned_cache()
|
|
1142
|
-
lib.gpu_tools.clear_cache()
|
|
1166
|
+
vol.as_numpy(
|
|
1167
|
+
out=vol_np[..., sl_vol], allow_indirect_copy=True
|
|
1168
|
+
)
|
|
1169
|
+
del vol
|
|
1170
|
+
lib.gpu_tools.clear_cache()
|
|
1143
1171
|
|
|
1144
|
-
pbar.update_to(
|
|
1172
|
+
pbar.update_to(pbar.maxval)
|
|
1145
1173
|
|
|
1146
1174
|
msg = "Filtering volumes..."
|
|
1147
1175
|
logger.info(msg)
|
|
1148
1176
|
with rich_console.status(msg, spinner="dots"):
|
|
1149
1177
|
# Filter the mini recon first.
|
|
1178
|
+
msg = "Filtering padded minivol..."
|
|
1179
|
+
logger.debug(msg)
|
|
1150
1180
|
minivol_voxwid = args.voxwid * args.n
|
|
1151
1181
|
ndarray_container = lib.np_tools.NDArrayContainer(array=volmini_np)
|
|
1152
1182
|
minivol_padded_filtered_np = gbc.filters.ramp_filter_conebeam(
|
|
@@ -1167,16 +1197,20 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
1167
1197
|
]
|
|
1168
1198
|
)
|
|
1169
1199
|
del volmini_np # not going to reuse this, so delete this reference so the filtration can free some memory.
|
|
1200
|
+
msg = "Filtering unpadded minivol..."
|
|
1201
|
+
logger.debug(msg)
|
|
1170
1202
|
minivol_unpadded_filtered_np = gbc.filters.ramp_filter_conebeam(
|
|
1171
1203
|
ndarray_container,
|
|
1172
1204
|
minivol_voxwid,
|
|
1173
1205
|
2 * vartheta_v,
|
|
1174
1206
|
theta_soft=args.softspan_v,
|
|
1175
1207
|
auto_dc_adjust=False,
|
|
1176
|
-
allow_overwrite_arr=True, # we're not going to reuse the '
|
|
1208
|
+
allow_overwrite_arr=True, # we're not going to reuse the 'volmini_np' object after this.
|
|
1177
1209
|
logger=logger,
|
|
1178
1210
|
copy_to_array=None,
|
|
1179
1211
|
)
|
|
1212
|
+
msg = "Producing minivol correction array..."
|
|
1213
|
+
logger.debug(msg)
|
|
1180
1214
|
minivol_correction_np = (
|
|
1181
1215
|
minivol_padded_filtered_np[
|
|
1182
1216
|
mvc_padx : (-mvc_padx) or None,
|
|
@@ -1192,6 +1226,8 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
1192
1226
|
ndarray_container,
|
|
1193
1227
|
)
|
|
1194
1228
|
# Filter the full recon now
|
|
1229
|
+
msg = "Filtering padded vol and adding upscaled minivol correction..."
|
|
1230
|
+
logger.debug(msg)
|
|
1195
1231
|
ndarray_container = lib.np_tools.NDArrayContainer(array=vol_np)
|
|
1196
1232
|
vol_voxwid = args.voxwid
|
|
1197
1233
|
del vol_np # allows memory to be freed, because the gbc.filters.ramp_filter_conebeam is free to overwrite the ndarray_container.array
|
|
@@ -1201,7 +1237,7 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
1201
1237
|
2 * vartheta_v,
|
|
1202
1238
|
theta_soft=args.softspan_v,
|
|
1203
1239
|
auto_dc_adjust=False,
|
|
1204
|
-
allow_overwrite_arr=True,
|
|
1240
|
+
allow_overwrite_arr=True, # not going to need the 'vol_np' object after this.
|
|
1205
1241
|
logger=logger,
|
|
1206
1242
|
copy_to_array=None, # Should be a contiguous array. E.g., not an arbitrary view.
|
|
1207
1243
|
lowres_correction_array=minivol_correction_np,
|
|
@@ -1231,6 +1267,8 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
1231
1267
|
f"Estimated DC component to be subtracted: {dc_component:.5g}"
|
|
1232
1268
|
)
|
|
1233
1269
|
# Correct the DC component
|
|
1270
|
+
msg = "Adding DC correction..."
|
|
1271
|
+
logger.debug(msg)
|
|
1234
1272
|
ne.evaluate(
|
|
1235
1273
|
"v - dcc",
|
|
1236
1274
|
out=vol_filtered_np,
|
|
@@ -1250,6 +1288,7 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
1250
1288
|
|
|
1251
1289
|
# Clean up
|
|
1252
1290
|
lib.gpu_tools.clear_cache()
|
|
1291
|
+
lib.gpu_tools.clear_pinned_cache()
|
|
1253
1292
|
|
|
1254
1293
|
if path_output is not None:
|
|
1255
1294
|
msg = "Saving volume to disk..."
|
|
@@ -1258,9 +1297,17 @@ def main_from_args(args: types.SimpleNamespace) -> None: # ruff: ignore[complex
|
|
|
1258
1297
|
x = vol_filtered
|
|
1259
1298
|
# Save the volume as a .npy file
|
|
1260
1299
|
tomo_path = path_output.joinpath("recon.npy")
|
|
1261
|
-
lib.ne_tools.save(tomo_path, x)
|
|
1300
|
+
lib.ne_tools.save(tomo_path, x, flush=True)
|
|
1262
1301
|
msg = "Full volume now saved to disk."
|
|
1263
1302
|
logger.debug(msg)
|
|
1303
|
+
# Now get rid of the temporary files, if applicable
|
|
1304
|
+
if args.memmap_vols:
|
|
1305
|
+
savepath = path_output.joinpath("tmp_backproj" + ".npy")
|
|
1306
|
+
savepath.unlink() # delete file
|
|
1307
|
+
savepath = path_output.joinpath(
|
|
1308
|
+
"tmp_backproj" + "_mini" + ".npy"
|
|
1309
|
+
)
|
|
1310
|
+
savepath.unlink() # delete file
|
|
1264
1311
|
# Save slices
|
|
1265
1312
|
for axis, axis_str in enumerate("xyz"):
|
|
1266
1313
|
msg = f"Saving '{axis_str}' slice..."
|
|
@@ -521,7 +521,7 @@ def main() -> None:
|
|
|
521
521
|
save_path.joinpath("tomograms") if is_intermediate else save_path
|
|
522
522
|
)
|
|
523
523
|
tomo_path.mkdir(exist_ok=True)
|
|
524
|
-
lib.ne_tools.save(tomo_path.joinpath(id_str + ".npy"), x)
|
|
524
|
+
lib.ne_tools.save(tomo_path.joinpath(id_str + ".npy"), x, flush=True)
|
|
525
525
|
|
|
526
526
|
# Save midslices from volume as .png files
|
|
527
527
|
# The method used here can be a bit slow, because I get a full numpy array and process that.
|
|
@@ -16,4 +16,4 @@
|
|
|
16
16
|
# This file is read from by 'setup.py', from '__init__.py', and also by a git hook which increments the dev number each time a commit is made on the 'dev' branch. There should only be one line in the file which begins with "version".
|
|
17
17
|
"""File which stores the current version number of this module."""
|
|
18
18
|
|
|
19
|
-
version = "0.0.
|
|
19
|
+
version = "0.0.24.dev1"
|
|
@@ -193,8 +193,21 @@ class Volume[
|
|
|
193
193
|
self._texture, vol._texture, tout=self._texture, eps=eps
|
|
194
194
|
)
|
|
195
195
|
|
|
196
|
-
def as_numpy(
|
|
196
|
+
def as_numpy(
|
|
197
|
+
self, out: np.ndarray | None = None, allow_indirect_copy: bool = False
|
|
198
|
+
) -> np.ndarray:
|
|
197
199
|
"""Copy this volume's data into a numpy array."""
|
|
200
|
+
# Note: the option 'allow_indirect_copy' allows a fast-but-not-fastest copy when the output array is not C-contiguous.
|
|
201
|
+
if out is not None and not out.flags["C_CONTIGUOUS"]:
|
|
202
|
+
# The output volume is not C contiguous. A copy cannot be performed unless
|
|
203
|
+
# allow_indirect_copy=True is supplied.
|
|
204
|
+
if not allow_indirect_copy:
|
|
205
|
+
msg = "The array supplied to the out=... keyword is not C contiguous. The data cannot be copied directly, and indirect copying must be explicitly allowed via allow_indirect_copy=True."
|
|
206
|
+
raise ValueError(msg)
|
|
207
|
+
out_ = self.as_numpy(out=None)
|
|
208
|
+
ne_tools.fastcopy(src=out_, dst=out)
|
|
209
|
+
gpu_tools.clear_pinned_cache()
|
|
210
|
+
return out
|
|
198
211
|
x = (
|
|
199
212
|
out
|
|
200
213
|
if out is not None
|
|
@@ -209,7 +222,7 @@ class Volume[
|
|
|
209
222
|
def save(self, path: pathlib.Path) -> None:
|
|
210
223
|
"""Save this volume into a numpy array on disk."""
|
|
211
224
|
x = self.as_numpy()
|
|
212
|
-
ne_tools.save(path, x)
|
|
225
|
+
ne_tools.save(path, x, flush=True)
|
|
213
226
|
|
|
214
227
|
def as_cupy(self, out: cp.ndarray | None = None) -> cp.ndarray:
|
|
215
228
|
"""Copy this volume's data into a cupy array."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aprict
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.24.dev1
|
|
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>
|
|
@@ -36,6 +36,10 @@ Requires-Dist: neuroglancer>=2.41.0; extra == "gui"
|
|
|
36
36
|
Dynamic: author
|
|
37
37
|
Dynamic: license-file
|
|
38
38
|
|
|
39
|
+
[](https://orcid.org/0000-0002-0015-8284)
|
|
40
|
+
[](https://doi.org/10.5281/zenodo.23632625)
|
|
41
|
+

|
|
42
|
+
[](https://www.repostatus.org/#wip)
|
|
39
43
|
<details open><summary><h1>About</h1></summary>
|
|
40
44
|
|
|
41
45
|
Description
|
|
@@ -71,8 +75,7 @@ Known limitations
|
|
|
71
75
|
* Volume size is limited by CUDA texture limit. For example, a `(2400,2400,4800)` volume can be reconstructed, but not a `(30000,30000,1)` volume, due to a volume of this size not fitting within a single CUDA texture
|
|
72
76
|
* The FORBILD shape `Tetrahedron` is not yet implemented, and no primitive shape is permitted to have more than 3 clipping planes applied, due to internal limitations. All other FORBILD phantoms should be supported.
|
|
73
77
|
* Only one GPU is utilised by this module, at the present time. There is no defined behaviour for which GPU will be chosen.
|
|
74
|
-
* Not fully optimised
|
|
75
|
-
* the GBC reconstruction script assumes that the whole volume (or more) can fit in RAM. This limitation may be lifted in the future. (Note: a present workaround is to create a large swapfile on disk, since swap space is treated as RAM when the physical RAM is exhausted.)
|
|
78
|
+
* Not fully optimised
|
|
76
79
|
* CPU and GPU work not completely asynchronous: due to unresolved bugs, various asynchronous GPU operations have been disabled. This may not have much impact on large reconstructions, but could result in poor GPU utilisation for smaller reconstructions.
|
|
77
80
|
* No smart batching of (back)projections: smarter code would analyse the geometry of projections, and batch together (back)projections that involve similar regions of the volume. Currently, the code does not do any kind of clever batching like this, and so the (back)projection code is not as performant as it could be.
|
|
78
81
|
|
|
@@ -99,7 +102,7 @@ You can install `aprict` like you would any python package, using `pip install`.
|
|
|
99
102
|
Example installation using `uv`:
|
|
100
103
|
```bash
|
|
101
104
|
$ uv venv -p 3.14
|
|
102
|
-
$ uv pip install aprict[gui]==0.0.
|
|
105
|
+
$ uv pip install aprict[gui]==0.0.24
|
|
103
106
|
$ source .venv/bin/activate
|
|
104
107
|
```
|
|
105
108
|
You should now have several executables available on `$PATH`. Try `aprict-cli --help` to see the polished commandline interface.
|
|
@@ -118,11 +121,11 @@ Activate the environment:
|
|
|
118
121
|
```bash
|
|
119
122
|
source .venv/bin/activate
|
|
120
123
|
```
|
|
121
|
-
Now, try the shell command `aprict-cli --help`. Here is the output as at `v0.0.
|
|
124
|
+
Now, try the shell command `aprict-cli --help`. Here is the output as at `v0.0.24`:
|
|
122
125
|
```
|
|
123
126
|
Usage: aprict-cli [OPTIONS] COMMAND [ARGS]...
|
|
124
127
|
|
|
125
|
-
Entry point for aprict
|
|
128
|
+
Entry point for CLI interface to aprict version 0.0.24
|
|
126
129
|
|
|
127
130
|
Options:
|
|
128
131
|
--version Show the version and exit.
|
|
@@ -170,8 +173,8 @@ aprict-cli project cbfp \
|
|
|
170
173
|
--output projs \
|
|
171
174
|
--plot-mode PYQTGRAPH
|
|
172
175
|
````
|
|
173
|
-
(Time on my machine: ~2 minutes,
|
|
174
|
-
The option `--plot-mode PYQTGRAPH` will display a plot window of the projection data after it is created. (This will not be available if the module was not installed with the `[gui]` option.)
|
|
176
|
+
(Time on my machine: ~2 minutes, 56 seconds)
|
|
177
|
+
The options `--ssu 3 --ssv 3` indicate that the line attenuation for each detector pixel is to be calculated as the average of a 3-by-3 grid of exact line integrals. This kind of improved accuracy is necessary for some phantoms, including this one, if using a large detector pixel size. The option `--plot-mode PYQTGRAPH` will display a plot window of the projection data after it is created. (This will not be available if the module was not installed with the `[gui]` option.)
|
|
175
178
|
|
|
176
179
|
Now, let's reconstruct with three different algorithms:
|
|
177
180
|
1. Global Backprojection-Convolution (GBC)
|
|
@@ -186,10 +189,14 @@ aprict-cli recon gbc-cone-cyl \
|
|
|
186
189
|
--voxwid 0.5 \
|
|
187
190
|
--volshape '(525,525,525)' \
|
|
188
191
|
--alg GREWAR \
|
|
192
|
+
--f1 1.2 \
|
|
193
|
+
--f2 6 \
|
|
194
|
+
--n 9 \
|
|
195
|
+
--eps 1e-9 \
|
|
189
196
|
--output recon_gbc \
|
|
190
197
|
--plot-mode PYQTGRAPH
|
|
191
198
|
```
|
|
192
|
-
(Time on my machine: ~
|
|
199
|
+
(Time on my machine: ~39 seconds)
|
|
193
200
|
|
|
194
201
|
To perform an FBP reconstruction, we do:
|
|
195
202
|
```bash
|
|
@@ -202,7 +209,7 @@ aprict-cli recon fbp-cone-cyl \
|
|
|
202
209
|
--output recon_fbp \
|
|
203
210
|
--plot-mode PYQTGRAPH
|
|
204
211
|
```
|
|
205
|
-
(Time on my machine: ~
|
|
212
|
+
(Time on my machine: ~19 seconds)
|
|
206
213
|
|
|
207
214
|
To perform an FBP-VM reconstruction, we change `--alg` to `NOOGREWAR`:
|
|
208
215
|
```bash
|
|
@@ -215,7 +222,7 @@ aprict-cli recon fbp-cone-cyl \
|
|
|
215
222
|
--output recon_fbp-vw \
|
|
216
223
|
--plot-mode PYQTGRAPH
|
|
217
224
|
```
|
|
218
|
-
(Time on my machine: ~
|
|
225
|
+
(Time on my machine: ~26 seconds)
|
|
219
226
|
|
|
220
227
|
|
|
221
228
|
</details>
|
|
@@ -253,7 +260,7 @@ aprict-cli project cbfp \
|
|
|
253
260
|
--output projs \
|
|
254
261
|
--plot-mode PYQTGRAPH
|
|
255
262
|
````
|
|
256
|
-
(Time on my machine: ~1 minute,
|
|
263
|
+
(Time on my machine: ~1 minute, 48 seconds)
|
|
257
264
|
The option `--plot-mode PYQTGRAPH` will display a plot window of the projection data (a sinogram) after it is created. (This will not be available if the module was not installed with the `[gui]` option.)
|
|
258
265
|
|
|
259
266
|
You will find a copy of the `ROCK_CAN` phantom in the output directory `projs`, beside the projection data. The phantom is always copied to the output directory, to ensure a good record of the inputs to the simulation.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|