From 139e92089c29296289825d199e5f09b3abbbe67b Mon Sep 17 00:00:00 2001 From: algol Date: Wed, 1 Jul 2026 22:44:28 +0100 Subject: [PATCH 1/8] work begins on wrappers --- httomo/method_wrappers/__init__.py | 1 + httomo/method_wrappers/average_frames.py | 62 ++++++++++++++++++++++++ httomo/runner/method_wrapper.py | 1 + 3 files changed, 64 insertions(+) create mode 100644 httomo/method_wrappers/average_frames.py diff --git a/httomo/method_wrappers/__init__.py b/httomo/method_wrappers/__init__.py index 890fefac5..140634a24 100644 --- a/httomo/method_wrappers/__init__.py +++ b/httomo/method_wrappers/__init__.py @@ -10,6 +10,7 @@ import httomo.method_wrappers.dezinging import httomo.method_wrappers.distortion_correction import httomo.method_wrappers.seam_blender +import httomo.method_wrappers.average_frames import httomo.method_wrappers.images import httomo.method_wrappers.reconstruction import httomo.method_wrappers.rotation diff --git a/httomo/method_wrappers/average_frames.py b/httomo/method_wrappers/average_frames.py new file mode 100644 index 000000000..71e96d5c2 --- /dev/null +++ b/httomo/method_wrappers/average_frames.py @@ -0,0 +1,62 @@ +from typing import Dict, Optional + +from mpi4py.MPI import Comm + +from httomo.method_wrappers.generic import GenericMethodWrapper +from httomo.preview import PreviewConfig +from httomo.runner.methods_repository_interface import MethodRepository + + +class AverageFramesWrapper(GenericMethodWrapper): + """ + Wrapper for frames/projection averaging. + """ + + @classmethod + def should_select_this_class(cls, module_path: str, method_name: str) -> bool: + return "average_projection_frames" in method_name + + @classmethod + def requires_preview(cls) -> bool: + return True + + def __init__( + self, + method_repository: MethodRepository, + module_path: str, + method_name: str, + comm: Comm, + preview_config: PreviewConfig, + save_result: Optional[bool] = None, + output_mapping: Dict[str, str] = {}, + **kwargs, + ): + super().__init__( + method_repository, + module_path, + method_name, + comm, + save_result, + output_mapping, + **kwargs, + ) + self._update_params_from_preview(preview_config) + + def _update_params_from_preview(self, preview_config: PreviewConfig) -> None: + """ + Extract information from preview config to define the parameter values required for + distortion correction methods, and update `self._config_params`. + """ + SHIFT_PARAM_NAME = "shift_xy" + STEP_PARAM_NAME = "step_xy" + shift_param_value = [ + preview_config.detector_x.start, + preview_config.detector_y.start, + ] + step_param_value = [1, 1] + self.append_config_params( + { + SHIFT_PARAM_NAME: shift_param_value, + STEP_PARAM_NAME: step_param_value, + } + ) diff --git a/httomo/runner/method_wrapper.py b/httomo/runner/method_wrapper.py index c5b7e499a..9c4597aa6 100644 --- a/httomo/runner/method_wrapper.py +++ b/httomo/runner/method_wrapper.py @@ -194,6 +194,7 @@ def calculate_max_slices( data_dtype: np.dtype, slicing_dim: int, non_slice_dims_shape: Tuple[int, int], + angles: np.ndarray, available_memory: int, ) -> Tuple[int, int]: """If it runs on GPU, determine the maximum number of slices that can fit in the From e3b8c9bc6b947a701abdb7d55fec9b78d19a9343 Mon Sep 17 00:00:00 2001 From: dkazanc Date: Thu, 2 Jul 2026 15:23:50 +0100 Subject: [PATCH 2/8] adding a wrapper for 360 to 180 conversion --- httomo/method_wrappers/__init__.py | 1 + httomo/method_wrappers/reconstruction.py | 7 ------- httomo/method_wrappers/sino360_to_180.py | 18 ++++++++++++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 httomo/method_wrappers/sino360_to_180.py diff --git a/httomo/method_wrappers/__init__.py b/httomo/method_wrappers/__init__.py index 140634a24..4f22f4208 100644 --- a/httomo/method_wrappers/__init__.py +++ b/httomo/method_wrappers/__init__.py @@ -7,6 +7,7 @@ # import all other wrappers to make sure they are available to the factory function # (add imports here when createing new wrappers) import httomo.method_wrappers.datareducer +import httomo.method_wrappers.sino360_to_180 import httomo.method_wrappers.dezinging import httomo.method_wrappers.distortion_correction import httomo.method_wrappers.seam_blender diff --git a/httomo/method_wrappers/reconstruction.py b/httomo/method_wrappers/reconstruction.py index 10fb85292..9565c3862 100644 --- a/httomo/method_wrappers/reconstruction.py +++ b/httomo/method_wrappers/reconstruction.py @@ -20,16 +20,9 @@ def should_select_this_class(cls, module_path: str, method_name: str) -> bool: return module_path.endswith(".algorithm") def _preprocess_data(self, block: T) -> T: - # this is essential for the angles cutting below to be valid assert ( self.pattern == Pattern.sinogram ), "reconstruction methods must be sinogram" - - # for 360 degrees data the angular dimension will be truncated while angles are not. - # Truncating angles if the angular dimension has got a different size - datashape0 = block.data.shape[0] - if datashape0 != len(block.angles_radians): - block.angles_radians = block.angles_radians[0:datashape0] self._input_shape = block.data.shape return super()._preprocess_data(block) diff --git a/httomo/method_wrappers/sino360_to_180.py b/httomo/method_wrappers/sino360_to_180.py new file mode 100644 index 000000000..7b902850f --- /dev/null +++ b/httomo/method_wrappers/sino360_to_180.py @@ -0,0 +1,18 @@ +from httomo.method_wrappers.generic import GenericMethodWrapper +from httomo.block_interfaces import T + + +class Sino360to180Wrapper(GenericMethodWrapper): + """ + Wrapper to perform extended FoV (360degrees) data conversion to a standard 180 degrees data. + The wrapper is responsible for changing the angles after the data has changed. + """ + + @classmethod + def should_select_this_class(cls, module_path: str, method_name: str) -> bool: + return "sino_360_to_180" in method_name + + def _postprocess_data(self, block: T) -> T: + # for 360 degrees data the angular dimension is truncated so the angles should be changed in a similar fashion. + block.angles_radians = block.angles_radians[0 : block.data.shape[0]] + return block From e653ce9c6018e17c9b9a7f4e7aa1fba8ac71bc8c Mon Sep 17 00:00:00 2001 From: dkazanc Date: Thu, 2 Jul 2026 16:20:44 +0100 Subject: [PATCH 3/8] work on the wrapper for averaging --- httomo/method_wrappers/average_frames.py | 76 ++++++++---------------- 1 file changed, 26 insertions(+), 50 deletions(-) diff --git a/httomo/method_wrappers/average_frames.py b/httomo/method_wrappers/average_frames.py index 71e96d5c2..7b2f5b555 100644 --- a/httomo/method_wrappers/average_frames.py +++ b/httomo/method_wrappers/average_frames.py @@ -1,10 +1,6 @@ -from typing import Dict, Optional - -from mpi4py.MPI import Comm - from httomo.method_wrappers.generic import GenericMethodWrapper -from httomo.preview import PreviewConfig -from httomo.runner.methods_repository_interface import MethodRepository +from httomo.block_interfaces import T +import numpy as np class AverageFramesWrapper(GenericMethodWrapper): @@ -16,47 +12,27 @@ class AverageFramesWrapper(GenericMethodWrapper): def should_select_this_class(cls, module_path: str, method_name: str) -> bool: return "average_projection_frames" in method_name - @classmethod - def requires_preview(cls) -> bool: - return True - - def __init__( - self, - method_repository: MethodRepository, - module_path: str, - method_name: str, - comm: Comm, - preview_config: PreviewConfig, - save_result: Optional[bool] = None, - output_mapping: Dict[str, str] = {}, - **kwargs, - ): - super().__init__( - method_repository, - module_path, - method_name, - comm, - save_result, - output_mapping, - **kwargs, - ) - self._update_params_from_preview(preview_config) - - def _update_params_from_preview(self, preview_config: PreviewConfig) -> None: - """ - Extract information from preview config to define the parameter values required for - distortion correction methods, and update `self._config_params`. - """ - SHIFT_PARAM_NAME = "shift_xy" - STEP_PARAM_NAME = "step_xy" - shift_param_value = [ - preview_config.detector_x.start, - preview_config.detector_y.start, - ] - step_param_value = [1, 1] - self.append_config_params( - { - SHIFT_PARAM_NAME: shift_param_value, - STEP_PARAM_NAME: step_param_value, - } - ) + def _preprocess_data(self, block: T) -> T: + # when the angular preview is getting changed by averaging the angles should be changed accordingly + config_params = self._config_params + k = config_params["projection_averaging_factor"] + + n_proj = block.data.shape[0] # original data angular size + n_full = n_proj // k + remainder = n_proj % k + + n_out = n_full + (remainder > 0) + + averaged_angles = np.float32(np.empty((n_out,))) + + # if n_full: + # averaged[:n_full] = ( + # data[: n_full * k].reshape(n_full, k, *data.shape[1:]).mean(axis=1) + # ) + + # if remainder: + # averaged[-1] = data[n_full * k :].mean(axis=0) + + # TODO: assertion on angles length and data shape + # block.angles_radians = block.angles_radians[0 : block.data.shape[0]] + return block From 382a6e1cf0c7d88aaef99a3463d10b38648b1cf7 Mon Sep 17 00:00:00 2001 From: algol Date: Mon, 6 Jul 2026 23:14:00 +0100 Subject: [PATCH 4/8] working averaging wrapper --- httomo/method_wrappers/average_frames.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/httomo/method_wrappers/average_frames.py b/httomo/method_wrappers/average_frames.py index 7b2f5b555..ec9f3cc23 100644 --- a/httomo/method_wrappers/average_frames.py +++ b/httomo/method_wrappers/average_frames.py @@ -23,16 +23,18 @@ def _preprocess_data(self, block: T) -> T: n_out = n_full + (remainder > 0) - averaged_angles = np.float32(np.empty((n_out,))) + averaged_angles = np.empty(n_out, dtype=block.angles.dtype) - # if n_full: - # averaged[:n_full] = ( - # data[: n_full * k].reshape(n_full, k, *data.shape[1:]).mean(axis=1) - # ) + if n_full: + averaged_angles[:n_full] = ( + block.angles_radians[: n_full * k] + .reshape(n_full, k) + .mean(axis=1) + ) - # if remainder: - # averaged[-1] = data[n_full * k :].mean(axis=0) + if remainder: + averaged_angles[-1] = block.angles_radians[n_full * k :].mean() # TODO: assertion on angles length and data shape - # block.angles_radians = block.angles_radians[0 : block.data.shape[0]] + block.angles_radians = averaged_angles return block From 7ab69d0dd5ef74bb4d2adb69e7da92810365d8b2 Mon Sep 17 00:00:00 2001 From: dkazanc Date: Wed, 8 Jul 2026 17:16:25 +0100 Subject: [PATCH 5/8] adding tests --- httomo/method_wrappers/average_frames.py | 1 - httomo/method_wrappers/reconstruction.py | 4 +- tests/method_wrappers/test_360_to_180.py | 47 ++++++++++++++++++++ tests/method_wrappers/test_angle_average.py | 47 ++++++++++++++++++++ tests/method_wrappers/test_reconstruction.py | 44 ------------------ 5 files changed, 96 insertions(+), 47 deletions(-) create mode 100644 tests/method_wrappers/test_360_to_180.py create mode 100644 tests/method_wrappers/test_angle_average.py diff --git a/httomo/method_wrappers/average_frames.py b/httomo/method_wrappers/average_frames.py index ec9f3cc23..3ff6042ad 100644 --- a/httomo/method_wrappers/average_frames.py +++ b/httomo/method_wrappers/average_frames.py @@ -35,6 +35,5 @@ def _preprocess_data(self, block: T) -> T: if remainder: averaged_angles[-1] = block.angles_radians[n_full * k :].mean() - # TODO: assertion on angles length and data shape block.angles_radians = averaged_angles return block diff --git a/httomo/method_wrappers/reconstruction.py b/httomo/method_wrappers/reconstruction.py index 9565c3862..782268e95 100644 --- a/httomo/method_wrappers/reconstruction.py +++ b/httomo/method_wrappers/reconstruction.py @@ -12,8 +12,7 @@ class ReconstructionWrapper(GenericMethodWrapper): - """Wraps reconstruction functions, limiting the length of the angles array - before calling the method.""" + """Wraps reconstruction functions.""" @classmethod def should_select_this_class(cls, module_path: str, method_name: str) -> bool: @@ -23,6 +22,7 @@ def _preprocess_data(self, block: T) -> T: assert ( self.pattern == Pattern.sinogram ), "reconstruction methods must be sinogram" + assert len(block.angles_radians) == block.data.shape[0] self._input_shape = block.data.shape return super()._preprocess_data(block) diff --git a/tests/method_wrappers/test_360_to_180.py b/tests/method_wrappers/test_360_to_180.py new file mode 100644 index 000000000..1a0754622 --- /dev/null +++ b/tests/method_wrappers/test_360_to_180.py @@ -0,0 +1,47 @@ +from httomo.method_wrappers import make_method_wrapper +from httomo.method_wrappers.average_frames import AverageFramesWrapper +from httomo.runner.auxiliary_data import AuxiliaryData +from httomo.runner.dataset import DataSetBlock +from ..testing_utils import make_mock_preview_config, make_mock_repo +from httomo_backends.methods_database.query import Pattern + +import numpy as np +from mpi4py import MPI +from pytest_mock import MockerFixture + +def test_angle_averaging(mocker: MockerFixture): + GLOBAL_SHAPE = (10, 20, 30) + + class FakeModule: + def average_projection_frames_tester(data, projection_averaging_factor): + np.testing.assert_array_equal(data, 1) + return data + + mocker.patch( + "httomo.method_wrappers.generic.import_module", return_value=FakeModule + ) + wrp = make_method_wrapper( + make_mock_repo(mocker, pattern=Pattern.sinogram), + "mocked_module_path.morph", + "average_projection_frames_tester", + MPI.COMM_WORLD, + make_mock_preview_config(mocker), + projection_averaging_factor = 2, + ) + assert isinstance(wrp, AverageFramesWrapper) + + aux_data = AuxiliaryData( + angles=2.0 * np.ones(GLOBAL_SHAPE[0] + 10, dtype=np.float32) + ) + data = np.ones(GLOBAL_SHAPE, dtype=np.float32) # assuming the data already averaged here by factor of 2 + input = DataSetBlock( + data[:, 0:3, :], + slicing_dim=1, + aux_data=aux_data, + chunk_shape=GLOBAL_SHAPE, + global_shape=GLOBAL_SHAPE, + ) + + wrp.execute(input) + + assert aux_data.get_angles().shape[0] == 5 \ No newline at end of file diff --git a/tests/method_wrappers/test_angle_average.py b/tests/method_wrappers/test_angle_average.py new file mode 100644 index 000000000..1a0754622 --- /dev/null +++ b/tests/method_wrappers/test_angle_average.py @@ -0,0 +1,47 @@ +from httomo.method_wrappers import make_method_wrapper +from httomo.method_wrappers.average_frames import AverageFramesWrapper +from httomo.runner.auxiliary_data import AuxiliaryData +from httomo.runner.dataset import DataSetBlock +from ..testing_utils import make_mock_preview_config, make_mock_repo +from httomo_backends.methods_database.query import Pattern + +import numpy as np +from mpi4py import MPI +from pytest_mock import MockerFixture + +def test_angle_averaging(mocker: MockerFixture): + GLOBAL_SHAPE = (10, 20, 30) + + class FakeModule: + def average_projection_frames_tester(data, projection_averaging_factor): + np.testing.assert_array_equal(data, 1) + return data + + mocker.patch( + "httomo.method_wrappers.generic.import_module", return_value=FakeModule + ) + wrp = make_method_wrapper( + make_mock_repo(mocker, pattern=Pattern.sinogram), + "mocked_module_path.morph", + "average_projection_frames_tester", + MPI.COMM_WORLD, + make_mock_preview_config(mocker), + projection_averaging_factor = 2, + ) + assert isinstance(wrp, AverageFramesWrapper) + + aux_data = AuxiliaryData( + angles=2.0 * np.ones(GLOBAL_SHAPE[0] + 10, dtype=np.float32) + ) + data = np.ones(GLOBAL_SHAPE, dtype=np.float32) # assuming the data already averaged here by factor of 2 + input = DataSetBlock( + data[:, 0:3, :], + slicing_dim=1, + aux_data=aux_data, + chunk_shape=GLOBAL_SHAPE, + global_shape=GLOBAL_SHAPE, + ) + + wrp.execute(input) + + assert aux_data.get_angles().shape[0] == 5 \ No newline at end of file diff --git a/tests/method_wrappers/test_reconstruction.py b/tests/method_wrappers/test_reconstruction.py index 89675f9ce..a3f27e196 100644 --- a/tests/method_wrappers/test_reconstruction.py +++ b/tests/method_wrappers/test_reconstruction.py @@ -1,57 +1,13 @@ -import math from httomo.method_wrappers import make_method_wrapper -from httomo.method_wrappers.reconstruction import ReconstructionWrapper from httomo.runner.auxiliary_data import AuxiliaryData from httomo.runner.dataset import DataSetBlock from ..testing_utils import make_mock_preview_config, make_mock_repo -from httomo_backends.methods_database.query import Pattern - import numpy as np from mpi4py import MPI from pytest_mock import MockerFixture -def test_recon_handles_reconstruction_angle_reshape(mocker: MockerFixture): - GLOBAL_SHAPE = (10, 20, 30) - - class FakeModule: - # we give the angles a different name on purpose - def recon_tester(data, theta): - np.testing.assert_array_equal(data, 1) - np.testing.assert_array_equal(theta, 2) - assert data.shape[0] == len(theta) - return data - - mocker.patch( - "httomo.method_wrappers.generic.import_module", return_value=FakeModule - ) - wrp = make_method_wrapper( - make_mock_repo(mocker, pattern=Pattern.sinogram), - "mocked_module_path.algorithm", - "recon_tester", - MPI.COMM_WORLD, - make_mock_preview_config(mocker), - ) - assert isinstance(wrp, ReconstructionWrapper) - - aux_data = AuxiliaryData( - angles=2.0 * np.ones(GLOBAL_SHAPE[0] + 10, dtype=np.float32) - ) - data = np.ones(GLOBAL_SHAPE, dtype=np.float32) - input = DataSetBlock( - data[:, 0:3, :], - slicing_dim=1, - aux_data=aux_data, - chunk_shape=GLOBAL_SHAPE, - global_shape=GLOBAL_SHAPE, - ) - - wrp.execute(input) - - assert aux_data.get_angles().shape[0] == GLOBAL_SHAPE[0] - - def test_recon_handles_reconstruction_axisswap(mocker: MockerFixture): class FakeModule: def recon_tester(data, theta): From 75d9616a5e2abb383a853d1c6ad721b5119af3c2 Mon Sep 17 00:00:00 2001 From: algol Date: Thu, 9 Jul 2026 10:30:12 +0100 Subject: [PATCH 6/8] tests wrappers finished --- httomo/method_wrappers/average_frames.py | 4 +-- tests/method_wrappers/test_360_to_180.py | 27 +++++++++++---------- tests/method_wrappers/test_angle_average.py | 9 ++++--- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/httomo/method_wrappers/average_frames.py b/httomo/method_wrappers/average_frames.py index 3ff6042ad..9e4ee4692 100644 --- a/httomo/method_wrappers/average_frames.py +++ b/httomo/method_wrappers/average_frames.py @@ -27,9 +27,7 @@ def _preprocess_data(self, block: T) -> T: if n_full: averaged_angles[:n_full] = ( - block.angles_radians[: n_full * k] - .reshape(n_full, k) - .mean(axis=1) + block.angles_radians[: n_full * k].reshape(n_full, k).mean(axis=1) ) if remainder: diff --git a/tests/method_wrappers/test_360_to_180.py b/tests/method_wrappers/test_360_to_180.py index 1a0754622..194799324 100644 --- a/tests/method_wrappers/test_360_to_180.py +++ b/tests/method_wrappers/test_360_to_180.py @@ -1,5 +1,5 @@ from httomo.method_wrappers import make_method_wrapper -from httomo.method_wrappers.average_frames import AverageFramesWrapper +from httomo.method_wrappers.sino360_to_180 import Sino360to180Wrapper from httomo.runner.auxiliary_data import AuxiliaryData from httomo.runner.dataset import DataSetBlock from ..testing_utils import make_mock_preview_config, make_mock_repo @@ -9,11 +9,13 @@ from mpi4py import MPI from pytest_mock import MockerFixture -def test_angle_averaging(mocker: MockerFixture): + +def test_sino_360_to_180(mocker: MockerFixture): GLOBAL_SHAPE = (10, 20, 30) + GLOBAL_SHAPE_MOD = (5, 20, 30) class FakeModule: - def average_projection_frames_tester(data, projection_averaging_factor): + def sino_360_to_180_tester(data): np.testing.assert_array_equal(data, 1) return data @@ -23,25 +25,24 @@ def average_projection_frames_tester(data, projection_averaging_factor): wrp = make_method_wrapper( make_mock_repo(mocker, pattern=Pattern.sinogram), "mocked_module_path.morph", - "average_projection_frames_tester", + "sino_360_to_180_tester", MPI.COMM_WORLD, make_mock_preview_config(mocker), - projection_averaging_factor = 2, ) - assert isinstance(wrp, AverageFramesWrapper) + assert isinstance(wrp, Sino360to180Wrapper) - aux_data = AuxiliaryData( - angles=2.0 * np.ones(GLOBAL_SHAPE[0] + 10, dtype=np.float32) - ) - data = np.ones(GLOBAL_SHAPE, dtype=np.float32) # assuming the data already averaged here by factor of 2 + aux_data = AuxiliaryData(angles=2.0 * np.ones(GLOBAL_SHAPE[0], dtype=np.float32)) + data = np.ones( + GLOBAL_SHAPE_MOD, dtype=np.float32 + ) # assuming the data already averaged here by factor of 2 input = DataSetBlock( data[:, 0:3, :], slicing_dim=1, aux_data=aux_data, - chunk_shape=GLOBAL_SHAPE, - global_shape=GLOBAL_SHAPE, + chunk_shape=GLOBAL_SHAPE_MOD, + global_shape=GLOBAL_SHAPE_MOD, ) wrp.execute(input) - assert aux_data.get_angles().shape[0] == 5 \ No newline at end of file + assert aux_data.get_angles().shape[0] == 5 diff --git a/tests/method_wrappers/test_angle_average.py b/tests/method_wrappers/test_angle_average.py index 1a0754622..18503b765 100644 --- a/tests/method_wrappers/test_angle_average.py +++ b/tests/method_wrappers/test_angle_average.py @@ -9,6 +9,7 @@ from mpi4py import MPI from pytest_mock import MockerFixture + def test_angle_averaging(mocker: MockerFixture): GLOBAL_SHAPE = (10, 20, 30) @@ -26,14 +27,16 @@ def average_projection_frames_tester(data, projection_averaging_factor): "average_projection_frames_tester", MPI.COMM_WORLD, make_mock_preview_config(mocker), - projection_averaging_factor = 2, + projection_averaging_factor=2, ) assert isinstance(wrp, AverageFramesWrapper) aux_data = AuxiliaryData( angles=2.0 * np.ones(GLOBAL_SHAPE[0] + 10, dtype=np.float32) ) - data = np.ones(GLOBAL_SHAPE, dtype=np.float32) # assuming the data already averaged here by factor of 2 + data = np.ones( + GLOBAL_SHAPE, dtype=np.float32 + ) # assuming the data already averaged here by factor of 2 input = DataSetBlock( data[:, 0:3, :], slicing_dim=1, @@ -44,4 +47,4 @@ def average_projection_frames_tester(data, projection_averaging_factor): wrp.execute(input) - assert aux_data.get_angles().shape[0] == 5 \ No newline at end of file + assert aux_data.get_angles().shape[0] == 5 From 03dcb63b4eaba52cbe81448b8abba905d19df15f Mon Sep 17 00:00:00 2001 From: algol Date: Thu, 9 Jul 2026 11:14:48 +0100 Subject: [PATCH 7/8] adding pipeline tests --- tests/conftest.py | 4 ++ tests/test_parallel_pipeline_big.py | 79 +++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index dbeca7356..300f68650 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -228,6 +228,10 @@ def FBP2d_astra(): def FBP3d_tomobar_denoising(): return "docs/source/pipelines_full/FBP3d_tomobar_denoising.yaml" +@pytest.fixture +def angles_averaging(): + return "docs/source/pipelines_full/angles_averaging.yaml" + @pytest.fixture def FISTA3d_tomobar(): diff --git a/tests/test_parallel_pipeline_big.py b/tests/test_parallel_pipeline_big.py index 39563d98d..c6b6a74ef 100644 --- a/tests/test_parallel_pipeline_big.py +++ b/tests/test_parallel_pipeline_big.py @@ -176,6 +176,85 @@ def test_pipe_parallel_FBP3d_tomobar_k11_38730_in_memory_preview( assert res_norm < 1e-6 +# ######################################################################## +@pytest.mark.full_data_parallel +def test_angles_averaging_LPRec_i12_119647_preview( + get_files: Callable, + cmd_mpirun, + i12_119647, + angles_averaging, + FBP3d_tomobar_k11_38730_npz, + output_folder, +): + + change_value_parameters_method_pipeline( + angles_averaging, + method=[ + "standard_tomo", + "standard_tomo", + "standard_tomo", + "standard_tomo", + "average_projection_frames", + ], + key=[ + "data_path", + "image_key_path", + "rotation_angles", + "preview", + "projection_averaging_factor", + ], + value=[ + "/entry/imaging/data", + "/entry/instrument/imaging/image_key", + {"data_path": "/entry/imaging_sum/gts_cs_theta"}, + {"detector_y": {"start": 500, "stop": 1500}}, + 12, + ], + ) + + cmd_mpirun.insert(9, i12_119647) + cmd_mpirun.insert(10, angles_averaging) + cmd_mpirun.insert(11, output_folder) + + process = Popen( + cmd_mpirun, env=os.environ, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE + ) + output, error = process.communicate() + print(output) + + files = get_files(output_folder) + + # #: check the generated reconstruction (hdf5 file) + # h5_files = list(filter(lambda x: ".h5" in x, files)) + # assert len(h5_files) == 1 + + # # load the pre-saved numpy array for comparison bellow + # data_gt = FBP3d_tomobar_k11_38730_npz["data"] + # axis_slice = FBP3d_tomobar_k11_38730_npz["axis_slice"] + # slices, sizeX, sizeY = np.shape(data_gt) + + # step = axis_slice // (slices + 2) + # # store for the result + # data_result = np.zeros((slices, sizeX, sizeY), dtype=np.float32) + + # path_to_data = "data/" + # h5_file_name = "FBP3d_tomobar" + # for file_to_open in h5_files: + # if h5_file_name in file_to_open: + # h5f = h5py.File(file_to_open, "r") + # index_prog = step + # for i in range(slices): + # data_result[i, :, :] = h5f[path_to_data][:, index_prog, :] + # index_prog += step + # h5f.close() + # else: + # message_str = f"File name with {h5_file_name} string cannot be found." + # raise FileNotFoundError(message_str) + + # residual_im = data_gt - data_result + # res_norm = np.linalg.norm(residual_im.flatten()).astype("float32") + # assert res_norm < 1e-6 + # ######################################################################## From ba7d89e0ad57ccdfb5193c5faa98bafb7975ffa3 Mon Sep 17 00:00:00 2001 From: algol Date: Thu, 9 Jul 2026 11:59:38 +0100 Subject: [PATCH 8/8] slight change to test preview --- tests/test_parallel_pipeline_big.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_parallel_pipeline_big.py b/tests/test_parallel_pipeline_big.py index c6b6a74ef..bdced7546 100644 --- a/tests/test_parallel_pipeline_big.py +++ b/tests/test_parallel_pipeline_big.py @@ -207,7 +207,7 @@ def test_angles_averaging_LPRec_i12_119647_preview( "/entry/imaging/data", "/entry/instrument/imaging/image_key", {"data_path": "/entry/imaging_sum/gts_cs_theta"}, - {"detector_y": {"start": 500, "stop": 1500}}, + {"detector_y": {"start": 800, "stop": 1200}}, 12, ], )