From 188f022687b7bf6b356484c68d9d8feb3161af6f Mon Sep 17 00:00:00 2001 From: dkazanc Date: Tue, 17 Dec 2024 16:01:57 +0000 Subject: [PATCH 1/5] removing inheretance on methodsIR in CuPy iterative --- tomobar/methodsIR_CuPy.py | 154 +++++++++++++++++++++++++++++++----- tomobar/regularisersCuPy.py | 2 - tomobar/supp/funcs.py | 4 +- 3 files changed, 138 insertions(+), 22 deletions(-) diff --git a/tomobar/methodsIR_CuPy.py b/tomobar/methodsIR_CuPy.py index d9783cbb8..d1558fb61 100644 --- a/tomobar/methodsIR_CuPy.py +++ b/tomobar/methodsIR_CuPy.py @@ -19,12 +19,15 @@ except ImportError: print("____! Astra-toolbox package is missing, please install !____") +from tomobar.supp.funcs import _data_dims_swapper from tomobar.supp.dicts import dicts_check, _reinitialise_atools_OS from tomobar.regularisersCuPy import prox_regul -from tomobar.methodsIR import RecToolsIR +from tomobar.astra_wrappers.astra_tools2d import AstraTools2D +from tomobar.astra_wrappers.astra_tools3d import AstraTools3D -class RecToolsIRCuPy(RecToolsIR): + +class RecToolsIRCuPy(): """CuPy-enabled iterative reconstruction algorithms using ASTRA toolbox, CCPi-RGL toolkit. Parameters for reconstruction algorithms are extracted from three dictionaries: _data_, _algorithm_ and _regularisation_. See API for `tomobar.supp.dicts` function for all parameters @@ -49,27 +52,61 @@ class RecToolsIRCuPy(RecToolsIR): def __init__( self, DetectorsDimH, # Horizontal detector dimension - DetectorsDimV, # Vertical detector dimension (3D case) + DetectorsDimV, # Vertical detector dimension (3D case), 0 or None for 2D case CenterRotOffset, # The Centre of Rotation scalar or a vector AnglesVec, # Array of projection angles in radians ObjSize, # Reconstructed object dimensions (scalar) - datafidelity="LS", # Data fidelity, choose from LS, KL, PWLS, SWLS + datafidelity="LS", # Data fidelity, choose from LS, KL, PWLS, SWLS (not all supported in cupy version) device_projector=0, # provide a GPU index (integer) of a specific device cupyrun=True, ): - super().__init__( - DetectorsDimH, - DetectorsDimV, - CenterRotOffset, - AnglesVec, - ObjSize, - datafidelity=datafidelity, - device_projector=device_projector, - cupyrun=cupyrun, - ) if DetectorsDimV == 0 or DetectorsDimV is None: raise ValueError("2D CuPy reconstruction is not yet supported, only 3D is") + + self.datafidelity = datafidelity + self.cupyrun = cupyrun + + if DetectorsDimV == 0 or DetectorsDimV is None: + self.geom = "2D" + self.Atools = AstraTools2D( + DetectorsDimH, + AnglesVec, + CenterRotOffset, + ObjSize, + 'gpu', + device_projector, + ) + else: + self.geom = "3D" + self.Atools = AstraTools3D( + DetectorsDimH, + DetectorsDimV, + AnglesVec, + CenterRotOffset, + ObjSize, + 'gpu', + device_projector, + ) + + @property + def datafidelity(self) -> int: + return self._datafidelity + + @datafidelity.setter + def datafidelity(self, datafidelity_val): + if datafidelity_val not in ["LS", "PWLS", "SWLS", "KL"]: + raise ValueError("Unknown data fidelity type, select: LS, PWLS, SWLS or KL") + self._datafidelity = datafidelity_val + + @property + def cupyrun(self) -> int: + return self._cupyrun + + @cupyrun.setter + def cupyrun(self, cupyrun_val): + self._cupyrun = cupyrun_val + def Landweber( self, _data_: dict, _algorithm_: Union[dict, None] = None @@ -218,20 +255,101 @@ def CGLS(self, _data_: dict, _algorithm_: Union[dict, None] = None) -> cp.ndarra del d, s, beta, r, alpha, Ad, normr2_new, normr2 return cp.reshape(x_rec, newshape=x_shape_3d, order="C") + def powermethod(self, _data_: dict) -> float: """Power iteration algorithm to calculate the eigenvalue of the operator (projection matrix). projection_raw_data is required for PWLS fidelity (self.datafidelity = PWLS), otherwise will be ignored. Args: - _data_ (dict): Data dictionary, where input data as a cupy array is provided. + _data_ (dict): Data dictionary, where input data is provided. Returns: float: the Lipschitz constant """ - cp._default_memory_pool.free_all_blocks() - # numpy-cupy agnostic function - return super().powermethod(_data_) + + if "data_axes_labels_order" not in _data_: + _data_["data_axes_labels_order"] = None + if ( + self.datafidelity in ["PWLS", "SWLS"] + and "projection_raw_data" not in _data_ + ): + raise ValueError("Please provide projection_raw_data for this model") + if self.datafidelity in ["PWLS", "SWLS"]: + sqweight = _data_["projection_raw_data"] + + if _data_["data_axes_labels_order"] is not None: + if self.geom == "2D": + _data_["projection_norm_data"] = _data_dims_swapper( + _data_["projection_norm_data"], + _data_["data_axes_labels_order"], + ["angles", "detX"], + ) + if self.datafidelity in ["PWLS", "SWLS"]: + _data_["projection_raw_data"] = _data_dims_swapper( + _data_["projection_raw_data"], + _data_["data_axes_labels_order"], + ["angles", "detX"], + ) + sqweight = _data_["projection_raw_data"] + else: + _data_["projection_norm_data"] = _data_dims_swapper( + _data_["projection_norm_data"], + _data_["data_axes_labels_order"], + ["detY", "angles", "detX"], + ) + if self.datafidelity in ["PWLS", "SWLS"]: + _data_["projection_raw_data"] = _data_dims_swapper( + _data_["projection_raw_data"], + _data_["data_axes_labels_order"], + ["detY", "angles", "detX"], + ) + sqweight = _data_["projection_raw_data"] + # we need to reset the swap option here as the data already been modified so we don't swap it again in the method + _data_["data_axes_labels_order"] = None + + if _data_.get("OS_number") is None: + _data_["OS_number"] = 1 # the classical approach (default) + else: + _data_ = _reinitialise_atools_OS(self, _data_) + + power_iterations = 15 + s = 1.0 + proj_geom = astra.geom_size(self.Atools.vol_geom) + x1 = cp.random.randn(*proj_geom, dtype=cp.float32) + + + if _data_["OS_number"] == 1: + # non-OS approach + y = self.Atools._forwprojCuPy(x1) + if self.datafidelity == "PWLS": + y = cp.multiply(sqweight, y) + for iterations in range(power_iterations): + x1 = self.Atools._backprojCuPy(y) + s = cp.linalg.norm(cp.ravel(x1), axis=0) + x1 = x1 / s + y = self.Atools._forwprojCuPy(x1) + if self.datafidelity == "PWLS": + y = cp.multiply(sqweight, y) + else: + # OS approach + y = self.Atools._forwprojOSCuPy(x1, 0) + if self.datafidelity == "PWLS": + if self.geom == "2D": + y = cp.multiply(sqweight[self.Atools.newInd_Vec[0, :], :], y) + else: + y = cp.multiply(sqweight[:, self.Atools.newInd_Vec[0, :], :], y) + for iterations in range(power_iterations): + x1 = self.Atools._backprojOSCuPy(y, 0) + s = cp.linalg.norm(cp.ravel(x1), axis=0) + x1 = x1 / s + y = self.Atools._forwprojOSCuPy(x1, 0) + if self.datafidelity == "PWLS": + if self.geom == "2D": + y = cp.multiply(sqweight[self.Atools.newInd_Vec[0, :], :], y) + else: + y = cp.multiply(sqweight[:, self.Atools.newInd_Vec[0, :], :], y) + return s def FISTA( self, diff --git a/tomobar/regularisersCuPy.py b/tomobar/regularisersCuPy.py index 9d0c69143..898bce7b7 100644 --- a/tomobar/regularisersCuPy.py +++ b/tomobar/regularisersCuPy.py @@ -34,7 +34,6 @@ def prox_regul(self, X: cp.ndarray, _regularisation_: dict) -> cp.ndarray: _regularisation_["regul_param"], _regularisation_["iterations"], _regularisation_["time_marching_step"], - _regularisation_["tolerance"], self.Atools.device_index, ) if "PD_TV" in _regularisation_["method"]: @@ -43,7 +42,6 @@ def prox_regul(self, X: cp.ndarray, _regularisation_: dict) -> cp.ndarray: X, _regularisation_["regul_param"], _regularisation_["iterations"], - _regularisation_["tolerance"], _regularisation_["methodTV"], self.nonneg_regul, _regularisation_["PD_LipschitzConstant"], diff --git a/tomobar/supp/funcs.py b/tomobar/supp/funcs.py index 717c91d05..b80882cc0 100644 --- a/tomobar/supp/funcs.py +++ b/tomobar/supp/funcs.py @@ -3,7 +3,7 @@ """ import numpy as np -from typing import Union, List +from typing import Union, List, Tuple cupy_enabled = False try: @@ -161,7 +161,7 @@ def _data_swap(data: xp.ndarray, data_swap_list: list) -> xp.ndarray: return data -def _parse_device_argument(device_int_or_string): +def _parse_device_argument(device_int_or_string) -> Tuple: """Convert a cpu/gpu string or integer gpu number into a tuple.""" if isinstance(device_int_or_string, int): return "gpu", device_int_or_string From 172db47b3e4ee3e64e671b4fa8e8c4dcc591d26a Mon Sep 17 00:00:00 2001 From: dkazanc Date: Tue, 17 Dec 2024 16:03:35 +0000 Subject: [PATCH 2/5] removing inheretance on methodsIR in CuPy iterative --- tomobar/methodsDIR_CuPy.py | 2 +- tomobar/methodsIR_CuPy.py | 14 +++++--------- tomobar/supp/suppTools.py | 6 +++--- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/tomobar/methodsDIR_CuPy.py b/tomobar/methodsDIR_CuPy.py index 2149e053f..295990811 100644 --- a/tomobar/methodsDIR_CuPy.py +++ b/tomobar/methodsDIR_CuPy.py @@ -130,7 +130,7 @@ def FBP(self, data: xp.ndarray, **kwargs) -> xp.ndarray: # filter the data on the GPU and keep the result there data = _filtersinc3D_cupy(data, cutoff=cutoff_freq) data = xp.ascontiguousarray(xp.swapaxes(data, 0, 1)) - xp._default_memory_pool.free_all_blocks() # free everything related to the filtering before starting Astra + xp._default_memory_pool.free_all_blocks() # free everything related to the filtering before starting Astra reconstruction = self.Atools._backprojCuPy(data) # 3d backprojecting cache = xp.fft.config.get_plan_cache() cache.clear() # flush FFT cache here before performing ifft to save the memory diff --git a/tomobar/methodsIR_CuPy.py b/tomobar/methodsIR_CuPy.py index d1558fb61..d80693607 100644 --- a/tomobar/methodsIR_CuPy.py +++ b/tomobar/methodsIR_CuPy.py @@ -26,8 +26,7 @@ from tomobar.astra_wrappers.astra_tools3d import AstraTools3D - -class RecToolsIRCuPy(): +class RecToolsIRCuPy: """CuPy-enabled iterative reconstruction algorithms using ASTRA toolbox, CCPi-RGL toolkit. Parameters for reconstruction algorithms are extracted from three dictionaries: _data_, _algorithm_ and _regularisation_. See API for `tomobar.supp.dicts` function for all parameters @@ -63,7 +62,7 @@ def __init__( if DetectorsDimV == 0 or DetectorsDimV is None: raise ValueError("2D CuPy reconstruction is not yet supported, only 3D is") - + self.datafidelity = datafidelity self.cupyrun = cupyrun @@ -74,7 +73,7 @@ def __init__( AnglesVec, CenterRotOffset, ObjSize, - 'gpu', + "gpu", device_projector, ) else: @@ -85,10 +84,10 @@ def __init__( AnglesVec, CenterRotOffset, ObjSize, - 'gpu', + "gpu", device_projector, ) - + @property def datafidelity(self) -> int: return self._datafidelity @@ -107,7 +106,6 @@ def cupyrun(self) -> int: def cupyrun(self, cupyrun_val): self._cupyrun = cupyrun_val - def Landweber( self, _data_: dict, _algorithm_: Union[dict, None] = None ) -> cp.ndarray: @@ -255,7 +253,6 @@ def CGLS(self, _data_: dict, _algorithm_: Union[dict, None] = None) -> cp.ndarra del d, s, beta, r, alpha, Ad, normr2_new, normr2 return cp.reshape(x_rec, newshape=x_shape_3d, order="C") - def powermethod(self, _data_: dict) -> float: """Power iteration algorithm to calculate the eigenvalue of the operator (projection matrix). @@ -318,7 +315,6 @@ def powermethod(self, _data_: dict) -> float: proj_geom = astra.geom_size(self.Atools.vol_geom) x1 = cp.random.randn(*proj_geom, dtype=cp.float32) - if _data_["OS_number"] == 1: # non-OS approach y = self.Atools._forwprojCuPy(x1) diff --git a/tomobar/supp/suppTools.py b/tomobar/supp/suppTools.py index f7f61e9fb..276986aa4 100644 --- a/tomobar/supp/suppTools.py +++ b/tomobar/supp/suppTools.py @@ -252,9 +252,9 @@ def normaliser( ) if method != "dynamic": denom = flats - darks - denom[ - (np.where(denom <= 0.0)) - ] = 1.0 # remove zeros/negatives in the denominator if any + denom[(np.where(denom <= 0.0))] = ( + 1.0 # remove zeros/negatives in the denominator if any + ) if axis == 1: denom = denom[:, np.newaxis, :] darks = darks[:, np.newaxis, :] From 251224b19500782e0d2a36ed637715bb2cff08b0 Mon Sep 17 00:00:00 2001 From: dkazanc Date: Thu, 19 Dec 2024 11:33:52 +0000 Subject: [PATCH 3/5] fixing regularisers in tomobar with respect to recent ccpi-regulariser changes --- Demos/Python/DemoFISTA_2D.py | 60 +--------------------------- Demos/Python/DemoFISTA_NLTV_2D.py | 19 ++++----- tests/test_RecToolsIR.py | 18 ++++----- tomobar/astra_wrappers/astra_base.py | 2 +- tomobar/regularisers.py | 43 ++++++++++++-------- 5 files changed, 45 insertions(+), 97 deletions(-) diff --git a/Demos/Python/DemoFISTA_2D.py b/Demos/Python/DemoFISTA_2D.py index 5d852bf4a..7797641c7 100644 --- a/Demos/Python/DemoFISTA_2D.py +++ b/Demos/Python/DemoFISTA_2D.py @@ -1,9 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -""" -Script to generate 2D analytical phantoms and their sinograms with added noise +"""Script to generate 2D analytical phantoms and their sinograms with added noise and then reconstruct using the regularised FISTA algorithm. - """ import numpy as np import matplotlib.pyplot as plt @@ -224,59 +222,3 @@ print("RMSE for FISTA-OS is {}".format(RMSE_FISTA_os)) print("RMSE for regularised FISTA-OS is {}".format(RMSE_FISTA_os_reg)) # %% -print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%") -print("Reconstructing with FISTA-KL-OS method") -print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%") -from tomobar.methodsIR import RecToolsIR - -# set parameters and initiate a class object -Rectools = RecToolsIR( - DetectorsDimH=P, # Horizontal detector dimension - DetectorsDimV=None, # Vertical detector dimension (3D case) - CenterRotOffset=None, # Center of Rotation scalar - AnglesVec=angles_rad, # A vector of projection angles in radians - ObjSize=N_size, # Reconstructed object dimensions (scalar) - datafidelity="KL", # Data fidelity, choose from LS, KL, PWLS - device_projector="gpu", -) - -# prepare dictionaries with parameters: -_data_ = {"projection_norm_data": noisy_sino, "OS_number": 10} # data dictionary -lc = Rectools.powermethod( - _data_ -) # calculate Lipschitz constant (run once to initialise) - -# Run FISTA-OS reconstrucion algorithm without regularisation -_algorithm_ = {"iterations": 50, "lipschitz_const": lc * 0.3} -RecFISTA_os_kl = Rectools.FISTA(_data_, _algorithm_) - -# adding regularisation -_regularisation_ = { - "method": "PD_TV", - "regul_param": 0.00003, - "iterations": 80, - "device_regulariser": "gpu", -} - -# adding regularisation using the CCPi regularisation toolkit -RecFISTA_os_kl_reg = Rectools.FISTA(_data_, _algorithm_, _regularisation_) - -plt.figure() -plt.subplot(121) -plt.imshow(RecFISTA_os_kl, vmin=0, vmax=1, cmap="gray") -plt.colorbar(ticks=[0, 0.5, 1], orientation="vertical") -plt.title("FISTA-KL-OS reconstruction") -plt.subplot(122) -plt.imshow(RecFISTA_os_kl_reg, vmin=0, vmax=1, cmap="gray") -plt.colorbar(ticks=[0, 0.5, 1], orientation="vertical") -plt.title("Regularised FISTA-KL-OS reconstruction") -plt.show() - -# calculate errors -Qtools = QualityTools(phantom_2D[indicesROI], RecFISTA_os_kl[indicesROI]) -RMSE_FISTA_os = Qtools.rmse() -Qtools = QualityTools(phantom_2D[indicesROI], RecFISTA_os_kl_reg[indicesROI]) -RMSE_FISTA_os_reg = Qtools.rmse() -print("RMSE for FISTA-KL-OS is {}".format(RMSE_FISTA_os)) -print("RMSE for regularised FISTA-KL-OS is {}".format(RMSE_FISTA_os_reg)) -# %% diff --git a/Demos/Python/DemoFISTA_NLTV_2D.py b/Demos/Python/DemoFISTA_NLTV_2D.py index 18221550e..5dd56dd86 100644 --- a/Demos/Python/DemoFISTA_NLTV_2D.py +++ b/Demos/Python/DemoFISTA_NLTV_2D.py @@ -1,12 +1,9 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -""" -Script to generate 2D analytical phantoms and their sinograms with added noise +"""Script to generate 2D analytical phantoms and their sinograms with added noise and then reconstruct using Non-local Total variation (NLTV) regularised FISTA algorithm. - NLTV method is quite different to the generic structure of other regularisers, hence a separate implementation - """ import numpy as np import timeit @@ -114,13 +111,12 @@ pars["patchwindow"], pars["neighbours"], pars["edge_parameter"], - "gpu", ) -""" -plt.figure() -plt.imshow(Weights[0,:,:], vmin=0, vmax=1, cmap="gray") -plt.colorbar(ticks=[0, 0.5, 1], orientation='vertical') -""" + +# plt.figure() +# plt.imshow(Weights[0,:,:], vmin=0, vmax=1, cmap="gray") +# plt.colorbar(ticks=[0, 0.5, 1], orientation='vertical') + # %% print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%") print("%%%%%%%%%%%Reconstructing with FISTA-OS method%%%%%%%%%%%%%%") @@ -155,10 +151,11 @@ _regularisation_ = { "method": "NLTV", "regul_param": 0.0025, - "iterations": 5, "NLTV_H_i": H_i, "NLTV_H_j": H_j, "NLTV_Weights": Weights, + "NumNeighb": pars["neighbours"], + "IterNumb": 5, "device_regulariser": "gpu", } diff --git a/tests/test_RecToolsIR.py b/tests/test_RecToolsIR.py index d13e59d28..3971723c8 100644 --- a/tests/test_RecToolsIR.py +++ b/tests/test_RecToolsIR.py @@ -5,7 +5,7 @@ from tomobar.methodsIR import RecToolsIR from tomobar.supp.suppTools import normaliser -eps = 1e-06 +eps = 1e-05 def test_SIRT2D(data, angles): @@ -607,8 +607,8 @@ def test_ADMM3D_reg(data, angles): Iter_rec = RecTools.ADMM(_data_, _algorithm_, _regularisation_) - assert_allclose(np.min(Iter_rec), -0.009140163, rtol=eps) - assert_allclose(np.max(Iter_rec), 0.020371437, rtol=eps) + assert_allclose(np.min(Iter_rec), -0.008855395, rtol=0, atol=eps) + assert_allclose(np.max(Iter_rec), 0.020371437, rtol=0, atol=eps) assert Iter_rec.dtype == np.float32 assert Iter_rec.shape == (128, 160, 160) @@ -684,8 +684,8 @@ def test_FISTA3D(data, angles): Iter_rec = RecTools.FISTA(_data_, _algorithm_) - assert_allclose(np.min(Iter_rec), -0.0021881335, rtol=eps) - assert_allclose(np.max(Iter_rec), 0.024684845, rtol=eps) + assert_allclose(np.min(Iter_rec), -0.0021881335, rtol=0, atol=eps) + assert_allclose(np.max(Iter_rec), 0.024684845, rtol=0, atol=eps) assert Iter_rec.dtype == np.float32 assert Iter_rec.shape == (128, 160, 160) @@ -751,8 +751,8 @@ def test_FISTA_OS_3D(data, angles): Iter_rec = RecTools.FISTA(_data_, _algorithm_) - assert_allclose(np.min(Iter_rec), -0.008425578, rtol=eps) - assert_allclose(np.max(Iter_rec), 0.032162726, rtol=eps) + assert_allclose(np.min(Iter_rec), -0.008425578, rtol=0, atol=eps) + assert_allclose(np.max(Iter_rec), 0.032162726, rtol=0, atol=eps) assert Iter_rec.dtype == np.float32 assert Iter_rec.shape == (128, 160, 160) @@ -790,7 +790,7 @@ def test_FISTA_OS_regul_3D(data, angles): Iter_rec = RecTools.FISTA(_data_, _algorithm_, _regularisation_) - assert_allclose(np.min(Iter_rec), -0.000175, rtol=1e-04) - assert_allclose(np.max(Iter_rec), 0.021823, rtol=1e-04) + assert_allclose(np.min(Iter_rec), -0.000174, rtol=0, atol=eps) + assert_allclose(np.max(Iter_rec), 0.021823, rtol=0, atol=eps) assert Iter_rec.dtype == np.float32 assert Iter_rec.shape == (128, 160, 160) diff --git a/tomobar/astra_wrappers/astra_base.py b/tomobar/astra_wrappers/astra_base.py index 68f3bdb86..ae8a4ac4f 100644 --- a/tomobar/astra_wrappers/astra_base.py +++ b/tomobar/astra_wrappers/astra_base.py @@ -224,7 +224,7 @@ def _set_gpu_projection2d_parallel_geometry(self): self.A_optomo = astra.OpTomo(self.proj_id) def _set_gpu_projection3d_parallel_geometry(self): - """the classical 3D projection geometry (cpu)""" + """the classical 3D projection geometry""" vectors = _vec_geom_init3D(self.angles_vec, 1.0, 1.0, self.centre_of_rotation) self.proj_geom = astra.create_proj_geom( "parallel3d_vec", self.detectors_y, self.detectors_x, vectors diff --git a/tomobar/regularisers.py b/tomobar/regularisers.py index 88cdcdff7..3d5ba0a37 100644 --- a/tomobar/regularisers.py +++ b/tomobar/regularisers.py @@ -41,65 +41,70 @@ def prox_regul(self, X: np.ndarray, _regularisation_: dict) -> Union[np.ndarray, Returns: np.ndarray or a tuple: Filtered 2D or 3D numpy array or a tuple. """ - info_vec = (_regularisation_["iterations"], 0) + info_vec = np.zeros(2, dtype=np.float32) # The proximal operator of the chosen regulariser if "ROF_TV" in _regularisation_["method"]: # Rudin - Osher - Fatemi Total variation method - (X, info_vec) = ROF_TV( + X = ROF_TV( X, _regularisation_["regul_param"], _regularisation_["iterations"], _regularisation_["time_marching_step"], _regularisation_["tolerance"], - self.Atools.device_index, + device=self.Atools.device_index, + infovector=info_vec, ) if "FGP_TV" in _regularisation_["method"]: # Fast-Gradient-Projection Total variation method - (X, info_vec) = FGP_TV( + X = FGP_TV( X, _regularisation_["regul_param"], _regularisation_["iterations"], _regularisation_["tolerance"], _regularisation_["methodTV"], self.nonneg_regul, - self.Atools.device_index, + device=self.Atools.device_index, + infovector=info_vec, ) if "PD_TV" in _regularisation_["method"]: # Primal-Dual (PD) Total variation method by Chambolle-Pock - (X, info_vec) = PD_TV( + X = PD_TV( X, _regularisation_["regul_param"], _regularisation_["iterations"], _regularisation_["tolerance"], + _regularisation_["PD_LipschitzConstant"], _regularisation_["methodTV"], self.nonneg_regul, - _regularisation_["PD_LipschitzConstant"], - self.Atools.device_index, + device=self.Atools.device_index, + infovector=info_vec, ) if "SB_TV" in _regularisation_["method"]: # Split Bregman Total variation method - (X, info_vec) = SB_TV( + X = SB_TV( X, _regularisation_["regul_param"], _regularisation_["iterations"], _regularisation_["tolerance"], _regularisation_["methodTV"], - self.Atools.device_index, + device=self.Atools.device_index, + infovector=info_vec, ) if "LLT_ROF" in _regularisation_["method"]: # Lysaker-Lundervold-Tai + ROF Total variation method - (X, info_vec) = LLT_ROF( + X = LLT_ROF( X, _regularisation_["regul_param"], _regularisation_["regul_param2"], _regularisation_["iterations"], _regularisation_["time_marching_step"], _regularisation_["tolerance"], - self.Atools.device_index, + device=self.Atools.device_index, + infovector=info_vec, ) if "TGV" in _regularisation_["method"]: # Total Generalised Variation method - (X, info_vec) = TGV( + X = TGV( X, _regularisation_["regul_param"], _regularisation_["TGV_alpha1"], @@ -107,11 +112,12 @@ def prox_regul(self, X: np.ndarray, _regularisation_: dict) -> Union[np.ndarray, _regularisation_["iterations"], _regularisation_["PD_LipschitzConstant"], _regularisation_["tolerance"], - self.Atools.device_index, + device=self.Atools.device_index, + infovector=info_vec, ) if "NDF" in _regularisation_["method"]: # Nonlinear isotropic diffusion method - (X, info_vec) = NDF( + X = NDF( X, _regularisation_["regul_param"], _regularisation_["edge_threhsold"], @@ -119,7 +125,8 @@ def prox_regul(self, X: np.ndarray, _regularisation_: dict) -> Union[np.ndarray, _regularisation_["time_marching_step"], self.NDF_method, _regularisation_["tolerance"], - self.Atools.device_index, + device=self.Atools.device_index, + infovector=info_vec, ) if "Diff4th" in _regularisation_["method"]: # Anisotropic diffusion of higher order @@ -130,7 +137,8 @@ def prox_regul(self, X: np.ndarray, _regularisation_: dict) -> Union[np.ndarray, _regularisation_["iterations"], _regularisation_["time_marching_step"], _regularisation_["tolerance"], - self.Atools.device_index, + device=self.Atools.device_index, + infovector=info_vec, ) if "NLTV" in _regularisation_["method"]: # Non-local Total Variation @@ -140,6 +148,7 @@ def prox_regul(self, X: np.ndarray, _regularisation_: dict) -> Union[np.ndarray, _regularisation_["NLTV_H_j"], _regularisation_["NLTV_H_j"], _regularisation_["NLTV_Weights"], + _regularisation_["NumNeighb"], _regularisation_["regul_param"], _regularisation_["iterations"], ) From b3c50af14da8964429a77c033390483f8149845c Mon Sep 17 00:00:00 2001 From: dkazanc Date: Thu, 19 Dec 2024 11:54:43 +0000 Subject: [PATCH 4/5] installation changes --- conda-recipe/environment/environment.yml | 1 - docs/source/howto/installation.rst | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/conda-recipe/environment/environment.yml b/conda-recipe/environment/environment.yml index df26cbd6e..428225456 100644 --- a/conda-recipe/environment/environment.yml +++ b/conda-recipe/environment/environment.yml @@ -3,7 +3,6 @@ channels: - conda-forge - httomo dependencies: - - httomo::ccpi-regularisation-cupy - httomo::ccpi-regulariser - conda-forge::astra-toolbox - conda-forge::cupy diff --git a/docs/source/howto/installation.rst b/docs/source/howto/installation.rst index 5a25f6184..e635e7cbe 100644 --- a/docs/source/howto/installation.rst +++ b/docs/source/howto/installation.rst @@ -2,9 +2,8 @@ Installation Guide ------------------ -ToMoBAR is a Python package with several :ref:`ref_dependencies` to ensure its full functionality. -It mostly relies on the GPU-enabled computations and therefore we suggest having a decent NVIDIA -graphics card to support it. +ToMoBAR is a Python package with several :ref:`ref_dependencies`. To ensure its full functionality it is recommended to install them. +It mostly relies on the GPU-enabled computations and therefore we suggest using a decent NVIDIA graphics card to support it. .. _ref_python: @@ -18,7 +17,7 @@ Install ToMoBAR as a pre-built conda Python package: $ conda install -c httomo tomobar -or install with the main dependencies into a new environment: +or install with the dependencies into a new environment: .. code-block:: console @@ -31,11 +30,12 @@ One can install ToMoBAR from PyPi, however, not all dependencies might be at PyP .. code-block:: console $ pip install tomobar + $ pip install ccpi-regularisation-cupy -Create conda environment: +Using conda environment: +++++++++++++++++++++++++ -Sometimes the one-liner above doesn't work. In that case we suggest creating a new conda environment, -and **pip** install ToMoBAR into it as shown bellow. +One can also create a new conda environment by using environment yaml file, +and then **pip** install ToMoBAR into it. .. code-block:: console From 923e437ee5e0c0aae2effbbc3a0f5e0bc7864d99 Mon Sep 17 00:00:00 2001 From: dkazanc Date: Thu, 19 Dec 2024 14:11:52 +0000 Subject: [PATCH 5/5] installation doc changes --- docs/source/howto/installation.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/howto/installation.rst b/docs/source/howto/installation.rst index e635e7cbe..641cc9fa9 100644 --- a/docs/source/howto/installation.rst +++ b/docs/source/howto/installation.rst @@ -23,6 +23,12 @@ or install with the dependencies into a new environment: $ conda install -c httomo -c conda-forge tomophantom tomobar astra-toolbox ccpi-regulariser pypwt +one can also try this installation, especially for other than Linux OSs: + +.. code-block:: console + + $ conda install -c httomo -c ccpi -c conda-forge tomophantom tomobar astra-toolbox ccpi-regulariser + Install ToMoBAR from PyPi: +++++++++++++++++++++++++++ One can install ToMoBAR from PyPi, however, not all dependencies might be at PyPi yet.