diff --git a/.github/workflows/README.md b/.github/workflows/README.md index a8438871c0..35f6f00bc9 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -23,7 +23,7 @@ Details on some of these jobs are given below. ## conda -When opening or modifying a pull request to `master`, a single variant is built and tested. This variant is for linux with `python=3.9` and `numpy=1.22`. +When opening or modifying a pull request to `master`, a single variant is built and tested. This variant is for linux with `python=3.11` and `numpy=1.25`. > [!NOTE] > The action does not publish to conda, instead this is done by jenkins. We will eventually move from jenkins to conda-forge instead. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index df11e75fef..e915fab70e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,8 +40,8 @@ jobs: runs-on: [self-hosted, python, cuda] strategy: matrix: - python-version: [3.9] - numpy-version: [1.22] + python-version: [3.11] + numpy-version: [1.25] steps: - uses: actions/checkout@v4 with: {fetch-depth: 0, submodules: recursive} @@ -80,15 +80,15 @@ jobs: strategy: matrix: include: - - python-version: 3.8 - numpy-version: 1.21 - python-version: '3.10' - numpy-version: 1.24 + numpy-version: 1.23 + - python-version: 3.12 + numpy-version: 1.26 steps: - uses: actions/checkout@v4 with: {fetch-depth: 0, submodules: recursive} - name: set requirements - run: sed -ri -e '/ python=/d' -e 's/(.* numpy=).*/\1${{ matrix.numpy-version }}/' scripts/requirements-test.yml + run: sed -ri -e '/ python=/d' -e 's/(.* numpy=).*/\1${{ matrix.numpy-version }}/' -e 's/=cuda*//' -e '/tigre/d' scripts/requirements-test.yml - uses: conda-incubator/setup-miniconda@v3 with: python-version: ${{ matrix.python-version }} @@ -105,8 +105,8 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.9] - numpy-version: [1.22] + python-version: [3.11] + numpy-version: [1.25] steps: - uses: actions/checkout@v4 with: {fetch-depth: 0, submodules: recursive} @@ -132,12 +132,12 @@ jobs: - uses: actions/checkout@v4 with: {fetch-depth: 0, submodules: recursive} - uses: conda-incubator/setup-miniconda@v3 - with: {python-version: '3.10'} + with: {python-version: 3.11} - name: install dependencies run: | cd docs conda install -c conda-forge -yq conda-merge - conda-merge ../scripts/requirements-test.yml docs_environment.yml > environment.yml + conda-merge ../scripts/requirements-test.yml docs_environment.yml | sed '/tigre/d' > environment.yml conda env update -n test conda list - name: build cil diff --git a/CHANGELOG.md b/CHANGELOG.md index e2397fb503..8b46e03c46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ -* x.x.x +* 24.0.0 + - Update to new CCPi-Regularisation toolkit v24.0.0. This is a backward incompatible release of the toolkit. + - CIL plugin support for TIGRE version v2.6 + - CIL plugin support for ASTRA-TOOLBOX version v2.1 + - Dropped support for python 3.8 and 3.9 + - Added support for python 3.11 and 3.12 + - Dropped support for numpy 1.21 and 1.22 + - Added support for numpy 1.25 and 1.26 - Set CMake Policy CMP0148 to OLD to avoid warnings in CMake 3.27 - AcquisitionGeometry prints the first and last 10 angles, or all if there are 30 or less, rather than the first 20 - Added a weight argument to the L1Norm function @@ -48,7 +55,6 @@ - `TXRMDataReader` - Added the ApproximateGradientSumFunction and SGFunction to allow for stochastic gradient algorithms to be created using functions with an approximate gradient and deterministic algorithms - * 23.1.0 - Fix bug in IndicatorBox proximal_conjugate - Allow CCPi Regulariser functions for non CIL object diff --git a/Dockerfile b/Dockerfile index 899e8799a7..d59575f7e8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ LABEL org.opencontainers.image.source=https://github.com/TomographicImaging/CIL LABEL org.opencontainers.image.licenses="Apache-2.0 AND BSD-3-Clause AND GPL-3.0" # CUDA-specific packages -ARG CIL_EXTRA_PACKAGES="tigre=2.4 astra-toolbox<2.1" +ARG CIL_EXTRA_PACKAGES="tigre=2.6 astra-toolbox=2.1.0=cuda*" # build & runtime dependencies # TODO: sync scripts/create_local_env_for_cil_development.sh, scripts/requirements-test.yml, recipe/meta.yaml (e.g. missing libstdcxx-ng _openmp_mutex pip)? # vis. https://github.com/TomographicImaging/CIL/pull/1590 @@ -20,7 +20,7 @@ COPY --chown="${NB_USER}" scripts/requirements-test.yml environment.yml RUN sed -ri '/tigre|astra-toolbox/d' environment.yml \ && for pkg in jupyter-server-proxy $CIL_EXTRA_PACKAGES; do echo " - $pkg" >> environment.yml; done \ && conda config --env --set channel_priority strict \ - && for ch in defaults ccpi intel conda-forge; do conda config --env --add channels $ch; done \ + && for ch in defaults nvidia ccpi intel conda-forge; do conda config --env --add channels $ch; done \ && mamba env update -n base \ && mamba clean -a -y -f \ && rm environment.yml \ diff --git a/README.md b/README.md index b8c14d52ee..2689ff4a7f 100644 --- a/README.md +++ b/README.md @@ -29,15 +29,16 @@ conda create --name cil -c conda-forge -c intel -c ccpi cil=23.1.0 To install CIL and the additional packages and plugins needed to run the [CIL demos](https://github.com/TomographicImaging/CIL-Demos) install the environment with: ```sh -conda create --name cil -c conda-forge -c intel -c ccpi cil=23.1.0 astra-toolbox tigre ccpi-regulariser tomophantom ipywidgets +conda create --name cil -c conda-forge -c intel -c ccpi cil=23.1.0 astra-toolbox=*=cuda* tigre ccpi-regulariser tomophantom ipywidgets ``` where: - -- `astra-toolbox` (requires an NVIDIA GPU) enables CIL support for [ASTRA toolbox](http://www.astra-toolbox.com) projectors (GPLv3 license) +- `astra-toolbox` enables CIL support for [ASTRA toolbox](http://www.astra-toolbox.com) CPU projector (2D Parallel beam only) (GPLv3 license) +- `astra-toolbox=*=cuda*` (requires an NVIDIA GPU) enables CIL support for [ASTRA toolbox](http://www.astra-toolbox.com) GPU projectors (GPLv3 license) - `tigre` (requires an NVIDIA GPU) enables support for [TIGRE](https://github.com/CERN/TIGRE) toolbox projectors (BSD license) -- `ccpi-regulariser` is the [CCPi Regularisation Toolkit](https://github.com/vais-ral/CCPi-Regularisation-Toolkit) +- `ccpi-regulariser` is the [CCPi Regularisation Toolkit](https://github.com/TomographicImaging/CCPi-Regularisation-Toolkit) - `tomophantom` can generate phantoms to use as test data [Tomophantom](https://github.com/dkazanc/TomoPhantom) +- `ipywidgets` enables visulisation tools within jupyter noteboooks ### Dependencies diff --git a/Wrappers/Python/cil/plugins/ccpi_regularisation/functions/regularisers.py b/Wrappers/Python/cil/plugins/ccpi_regularisation/functions/regularisers.py index 9b81f2c1c6..04a4f9c642 100644 --- a/Wrappers/Python/cil/plugins/ccpi_regularisation/functions/regularisers.py +++ b/Wrappers/Python/cil/plugins/ccpi_regularisation/functions/regularisers.py @@ -18,9 +18,9 @@ try: from ccpi.filters import regularisers - from ccpi.filters.cpu_regularisers import TV_ENERGY + from ccpi.filters.TV import TV_ENERGY except ImportError as exc: - raise ImportError('Please `conda install "ccpi::ccpi-regulariser>=20.04"`') from exc + raise ImportError('Please `conda install "ccpi::ccpi-regulariser>=24"`') from exc from cil.framework import DataOrder @@ -229,14 +229,17 @@ def _fista_on_dual_rof(self, in_arr, tau): """ - res , info = regularisers.FGP_TV(\ + info = np.zeros((2,), dtype=np.float32) + + res = regularisers.FGP_TV(\ in_arr,\ self.alpha * tau,\ self.max_iteration,\ self.tolerance,\ self.methodTV,\ self.nonnegativity,\ - self.device) + infovector = info, + device = self.device) return res, info @@ -315,14 +318,18 @@ def alpha1(self): return 1. def proximal_numpy(self, in_arr, tau): - res , info = regularisers.TGV(in_arr, + + info = np.zeros((2,), dtype=np.float32) + + res = regularisers.TGV(in_arr, self.alpha * tau, self.alpha1, self.alpha2, self.max_iteration, self.LipshitzConstant, self.tolerance, - self.device) + infovector = info, + device = self.device) # info: return number of iteration and reached tolerance # https://github.com/vais-ral/CCPi-Regularisation-Toolkit/blob/master/src/Core/regularisers_CPU/TGV_core.c#L168 @@ -400,7 +407,10 @@ def __call__(self,x): return np.nan def proximal_numpy(self, in_arr, tau): - res , info = regularisers.FGP_dTV(\ + + info = np.zeros((2,), dtype=np.float32) + + res = regularisers.FGP_dTV(\ in_arr,\ self.reference,\ self.alpha * tau,\ @@ -409,7 +419,8 @@ def proximal_numpy(self, in_arr, tau): self.eta,\ self.methodTV,\ self.nonnegativity,\ - self.device) + infovector = info, + device = self.device) return res, info def convex_conjugate(self, x): @@ -454,7 +465,7 @@ def __call__(self,x): def proximal_numpy(self, in_arr, tau): # remove any dimension of size 1 in_arr = np.squeeze(in_arr) - + res = regularisers.TNV(in_arr, self.alpha * tau, self.max_iteration, diff --git a/Wrappers/Python/cil/plugins/tigre/FBP.py b/Wrappers/Python/cil/plugins/tigre/FBP.py index 933203e081..07aa33158a 100644 --- a/Wrappers/Python/cil/plugins/tigre/FBP.py +++ b/Wrappers/Python/cil/plugins/tigre/FBP.py @@ -97,7 +97,9 @@ def process(self, out=None): arr_out = np.squeeze(arr_out, axis=0) else: if self.acquisition_geometry.geom_type == 'cone': - arr_out = fdk(self.get_input().as_array(), self.tigre_geom, self.tigre_angles) + # suppress print statements from TIGRE https://github.com/CERN/TIGRE/issues/532 + with contextlib.redirect_stdout(io.StringIO()): + arr_out = fdk(self.get_input().as_array(), self.tigre_geom, self.tigre_angles) else: arr_out = fbp(self.get_input().as_array(), self.tigre_geom, self.tigre_angles) diff --git a/Wrappers/Python/test/test_DataProcessor.py b/Wrappers/Python/test/test_DataProcessor.py index bea31dcdf5..a7516d8a65 100644 --- a/Wrappers/Python/test/test_DataProcessor.py +++ b/Wrappers/Python/test/test_DataProcessor.py @@ -572,21 +572,21 @@ def test_process_acquisition(self): proc.set_input(data_in.geometry) geometry_out = proc.process() - self.assertEquals(geometry_out, geometry_gold, + self.assertEqual(geometry_out, geometry_gold, msg="Binner failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(geometry_out, geometry_gold)) proc.set_input(data_in) data_out = proc.process() numpy.testing.assert_array_equal(data_gold, data_out.array) - self.assertEquals(data_out.geometry, geometry_gold, + self.assertEqual(data_out.geometry, geometry_gold, msg="Binner failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, geometry_gold)) data_out.fill(0) proc.process(out=data_out) numpy.testing.assert_array_equal(data_gold, data_out.array) - self.assertEquals(data_out.geometry, geometry_gold, + self.assertEqual(data_out.geometry, geometry_gold, msg="Binner failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, geometry_gold)) @@ -606,21 +606,21 @@ def test_process_image(self): proc.set_input(data_in.geometry) geometry_out = proc.process() - self.assertEquals(geometry_out, geometry_gold, + self.assertEqual(geometry_out, geometry_gold, msg="Binner failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(geometry_out, geometry_gold)) proc.set_input(data_in) data_out = proc.process() numpy.testing.assert_array_equal(data_gold, data_out.array) - self.assertEquals(data_out.geometry, geometry_gold, + self.assertEqual(data_out.geometry, geometry_gold, msg="Binner failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, geometry_gold)) data_out.fill(0) proc.process(out=data_out) numpy.testing.assert_array_equal(data_gold, data_out.array) - self.assertEquals(data_out.geometry, geometry_gold, + self.assertEqual(data_out.geometry, geometry_gold, msg="Binner failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, geometry_gold)) @@ -1058,10 +1058,8 @@ def test_process_image_geometry(self): # slice to single element {'channel':(None,None,4),'vertical':(None,None,28),'horizontal_x':(None, None,8),'horizontal_y':(None,None,16)}, - ] - offset_x =0.1*(8-1-1*4)/2 offset_y =0.2*(16-1-3 * 5)/2 offset_z =0.3*(28-1-3 * 7)/2 @@ -1343,21 +1341,21 @@ def test_process_acquisition(self): proc.set_input(data_in.geometry) geometry_out = proc.process() - self.assertEquals(geometry_out, geometry_gold, + self.assertEqual(geometry_out, geometry_gold, msg="Slicer failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(geometry_out, geometry_gold)) proc.set_input(data_in) data_out = proc.process() numpy.testing.assert_array_equal(data_gold, data_out.array) - self.assertEquals(data_out.geometry, geometry_gold, + self.assertEqual(data_out.geometry, geometry_gold, msg="Slicer failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, geometry_gold)) data_out.fill(0) proc.process(out=data_out) numpy.testing.assert_array_equal(data_gold, data_out.array) - self.assertEquals(data_out.geometry, geometry_gold, + self.assertEqual(data_out.geometry, geometry_gold, msg="Slicer failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, geometry_gold)) @@ -1375,21 +1373,21 @@ def test_process_image(self): proc.set_input(data_in.geometry) geometry_out = proc.process() - self.assertEquals(geometry_out, geometry_gold, + self.assertEqual(geometry_out, geometry_gold, msg="Slicer failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(geometry_out, geometry_gold)) proc.set_input(data_in) data_out = proc.process() numpy.testing.assert_array_equal(data_gold, data_out.array) - self.assertEquals(data_out.geometry, geometry_gold, + self.assertEqual(data_out.geometry, geometry_gold, msg="Slicer failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, geometry_gold)) data_out.fill(0) proc.process(out=data_out) numpy.testing.assert_array_equal(data_gold, data_out.array) - self.assertEquals(data_out.geometry, geometry_gold, + self.assertEqual(data_out.geometry, geometry_gold, msg="Slicer failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, geometry_gold)) @@ -1770,7 +1768,7 @@ def test_process_acquisition_geometry(self): proc.set_input(geometry) geometry_padded = proc._process_acquisition_geometry() - self.assertEquals(geometry_padded, self.ag_padded, + self.assertEqual(geometry_padded, self.ag_padded, msg="Padder failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(geometry_padded, self.ag_padded)) @@ -1784,7 +1782,7 @@ def test_process_acquisition_geometry(self): 0., 90., 180., 270.,\ 360., 450., 540., 630., 720.] - self.assertEquals(geometry_padded, geometry_gold, + self.assertEqual(geometry_padded, geometry_gold, msg="Padder failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(geometry_padded, geometry_gold)) @@ -1795,7 +1793,7 @@ def test_process_acquisition_geometry_origin(self): proc.set_input(geometry) geometry_padded = proc._process_acquisition_geometry() - self.assertEquals(geometry_padded, self.ag2_padded, + self.assertEqual(geometry_padded, self.ag2_padded, msg="Padder failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(geometry_padded, self.ag2_padded)) @@ -1807,7 +1805,7 @@ def test_process_image_geometry(self): proc.set_input(geometry) geometry_padded = proc._process_image_geometry() - self.assertEquals(geometry_padded, self.ig_padded, + self.assertEqual(geometry_padded, self.ig_padded, msg="Padder failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(geometry_padded, self.ig_padded)) @@ -1846,21 +1844,21 @@ def test_process_acquisition(self): proc.set_input(data_in.geometry) geometry_out = proc.process() - self.assertEquals(geometry_out, self.ag_padded, + self.assertEqual(geometry_out, self.ag_padded, msg="Padder failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(geometry_out, self.ag_padded)) proc.set_input(data_in) data_out = proc.process() numpy.testing.assert_array_equal(data_gold.array, data_out.array) - self.assertEquals(data_out.geometry, self.ag_padded, + self.assertEqual(data_out.geometry, self.ag_padded, msg="Padder failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, self.ag_padded)) data_out.fill(0) proc.process(out=data_out) numpy.testing.assert_array_equal(data_gold.array, data_out.array) - self.assertEquals(data_out.geometry, self.ag_padded, + self.assertEqual(data_out.geometry, self.ag_padded, msg="Padder failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, self.ag_padded)) @@ -1880,21 +1878,21 @@ def test_process_image(self): proc.set_input(data_in.geometry) geometry_out = proc.process() - self.assertEquals(geometry_out, self.ig_padded, + self.assertEqual(geometry_out, self.ig_padded, msg="Padder failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(geometry_out, self.ig_padded)) proc.set_input(data_in) data_out = proc.process() numpy.testing.assert_array_equal(data_gold.array, data_out.array) - self.assertEquals(data_out.geometry, self.ig_padded, + self.assertEqual(data_out.geometry, self.ig_padded, msg="Padder failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, self.ig_padded)) data_out.fill(0) proc.process(out=data_out) numpy.testing.assert_array_equal(data_gold.array, data_out.array) - self.assertEquals(data_out.geometry, self.ig_padded, + self.assertEqual(data_out.geometry, self.ig_padded, msg="Padder failed with geometry mismatch. Got:\n{0}\nExpected:\n{1}".format(data_out.geometry, self.ig_padded)) diff --git a/Wrappers/Python/test/test_PluginsRegularisation.py b/Wrappers/Python/test/test_PluginsRegularisation.py index 63be777d49..05370c82f2 100644 --- a/Wrappers/Python/test/test_PluginsRegularisation.py +++ b/Wrappers/Python/test/test_PluginsRegularisation.py @@ -105,7 +105,7 @@ def test_functionality_FGP_TV(self): fcil = FGP_TV() outcil = fcil.proximal(data, tau=tau) # use CIL defaults - outrgl, info = regularisers.FGP_TV(datarr, fcil.alpha*tau, fcil.max_iteration, fcil.tolerance, 0, 1, 'cpu' ) + outrgl = regularisers.FGP_TV(datarr, fcil.alpha*tau, fcil.max_iteration, fcil.tolerance, 0, 1, device='cpu' ) np.testing.assert_almost_equal(outrgl, outcil.as_array()) @@ -118,7 +118,7 @@ def test_functionality_TGV(self): fcil = TGV() outcil = fcil.proximal(data, tau=tau) # use CIL defaults - outrgl, info = regularisers.TGV(datarr, fcil.alpha*tau, 1,1, fcil.max_iteration, 12, fcil.tolerance, 'cpu' ) + outrgl = regularisers.TGV(datarr, fcil.alpha*tau, 1,1, fcil.max_iteration, 12, fcil.tolerance, device='cpu' ) np.testing.assert_almost_equal(outrgl, outcil.as_array()) @@ -133,7 +133,7 @@ def test_functionality_FGP_dTV(self): fcil = FGP_dTV(ref) outcil = fcil.proximal(data, tau=tau) # use CIL defaults - outrgl, info = regularisers.FGP_dTV(datarr, ref.as_array(), fcil.alpha*tau, fcil.max_iteration, fcil.tolerance, 0.01, 0, 1, 'cpu' ) + outrgl = regularisers.FGP_dTV(datarr, ref.as_array(), fcil.alpha*tau, fcil.max_iteration, fcil.tolerance, 0.01, 0, 1, device='cpu' ) np.testing.assert_almost_equal(outrgl, outcil.as_array()) diff --git a/Wrappers/Python/test/test_algorithms.py b/Wrappers/Python/test/test_algorithms.py index b90ff3485c..7a32375478 100644 --- a/Wrappers/Python/test/test_algorithms.py +++ b/Wrappers/Python/test/test_algorithms.py @@ -523,9 +523,9 @@ def test_PDHG_strongly_convex_gamma_g(self): pdhg = PDHG(f=f, g=g, operator=operator, sigma = sigma, tau=tau, max_iteration=5, gamma_g=0.5) pdhg.run(1, verbose=0) - self.assertAlmostEquals(pdhg.theta, 1.0/ np.sqrt(1 + 2 * pdhg.gamma_g * tau)) - self.assertAlmostEquals(pdhg.tau, tau * pdhg.theta) - self.assertAlmostEquals(pdhg.sigma, sigma / pdhg.theta) + self.assertAlmostEqual(pdhg.theta, 1.0/ np.sqrt(1 + 2 * pdhg.gamma_g * tau)) + self.assertAlmostEqual(pdhg.tau, tau * pdhg.theta) + self.assertAlmostEqual(pdhg.sigma, sigma / pdhg.theta) pdhg.run(4, verbose=0) self.assertNotEqual(pdhg.sigma, sigma) self.assertNotEqual(pdhg.tau, tau) @@ -557,9 +557,9 @@ def test_PDHG_strongly_convex_gamma_fcong(self): pdhg = PDHG(f=f, g=g, operator=operator, sigma = sigma, tau=tau, max_iteration=5, gamma_fconj=0.5) pdhg.run(1, verbose=0) - self.assertEquals(pdhg.theta, 1.0/ np.sqrt(1 + 2 * pdhg.gamma_fconj * sigma)) - self.assertEquals(pdhg.tau, tau / pdhg.theta) - self.assertEquals(pdhg.sigma, sigma * pdhg.theta) + self.assertEqual(pdhg.theta, 1.0/ np.sqrt(1 + 2 * pdhg.gamma_fconj * sigma)) + self.assertEqual(pdhg.tau, tau / pdhg.theta) + self.assertEqual(pdhg.sigma, sigma * pdhg.theta) pdhg.run(4, verbose=0) self.assertNotEqual(pdhg.sigma, sigma) self.assertNotEqual(pdhg.tau, tau) diff --git a/Wrappers/Python/test/test_functions.py b/Wrappers/Python/test/test_functions.py index c94a529f99..1fd925abbe 100644 --- a/Wrappers/Python/test/test_functions.py +++ b/Wrappers/Python/test/test_functions.py @@ -1121,16 +1121,16 @@ def setUp(self) -> None: self.alpha_arr = self.ig_real.allocate(0.15) def test_configure_tv_defaults(self): - self.assertEquals(self.tv.warm_start, True) - self.assertEquals(self.tv.iterations, 10) - self.assertEquals(self.tv.correlation, "Space") - self.assertEquals(self.tv.backend, "c") - self.assertEquals(self.tv.lower, -np.inf) - self.assertEquals(self.tv.upper, np.inf) - self.assertEquals(self.tv.isotropic, True) - self.assertEquals(self.tv.split, False) - self.assertEquals(self.tv.strong_convexity_constant, 0) - self.assertEquals(self.tv.tolerance, None) + self.assertEqual(self.tv.warm_start, True) + self.assertEqual(self.tv.iterations, 10) + self.assertEqual(self.tv.correlation, "Space") + self.assertEqual(self.tv.backend, "c") + self.assertEqual(self.tv.lower, -np.inf) + self.assertEqual(self.tv.upper, np.inf) + self.assertEqual(self.tv.isotropic, True) + self.assertEqual(self.tv.split, False) + self.assertEqual(self.tv.strong_convexity_constant, 0) + self.assertEqual(self.tv.tolerance, None) def test_configure_tv_not_defaults(self): tv=TotalVariation( max_iteration=100, @@ -1143,16 +1143,16 @@ def test_configure_tv_not_defaults(self): split = True, strong_convexity_constant = 1., warm_start=False) - self.assertEquals(tv.warm_start, False) - self.assertEquals(tv.iterations, 100) - self.assertEquals(tv.correlation, "SpaceChannels") - self.assertEquals(tv.backend, "numpy") - self.assertEquals(tv.lower, 0.) - self.assertEquals(tv.upper, 1.) - self.assertEquals(tv.isotropic, False) - self.assertEquals(tv.split, True) - self.assertEquals(tv.strong_convexity_constant, 1.) - self.assertEquals(tv.tolerance, 1e-5) + self.assertEqual(tv.warm_start, False) + self.assertEqual(tv.iterations, 100) + self.assertEqual(tv.correlation, "SpaceChannels") + self.assertEqual(tv.backend, "numpy") + self.assertEqual(tv.lower, 0.) + self.assertEqual(tv.upper, 1.) + self.assertEqual(tv.isotropic, False) + self.assertEqual(tv.split, True) + self.assertEqual(tv.strong_convexity_constant, 1.) + self.assertEqual(tv.tolerance, 1e-5) @@ -1407,7 +1407,7 @@ def test_non_scalar_tau_cil_tv(self): def test_get_p2_with_warm_start(self): data = dataexample.SHAPES.get(size=(16, 16)) tv=TotalVariation(warm_start=True, max_iteration=10) - self.assertEquals(tv._p2, None, msg="tv._p2 not initialised to None") + self.assertEqual(tv._p2, None, msg="tv._p2 not initialised to None") tv(data) checkp2=tv.gradient_operator.range_geometry().allocate(0) for i, x in enumerate(tv._get_p2()): @@ -1424,7 +1424,7 @@ def test_get_p2_with_warm_start(self): def test_get_p2_without_warm_start(self): data = dataexample.SHAPES.get(size=(16, 16)) tv=TotalVariation(warm_start=False) - self.assertEquals(tv._p2, None, msg="tv._p2 not initialised to None") + self.assertEqual(tv._p2, None, msg="tv._p2 not initialised to None") tv(data) checkp2=tv.gradient_operator.range_geometry().allocate(0) for i, x in enumerate(tv._get_p2()): diff --git a/Wrappers/Python/test/test_io.py b/Wrappers/Python/test/test_io.py index c47a236121..208ca926ce 100644 --- a/Wrappers/Python/test/test_io.py +++ b/Wrappers/Python/test/test_io.py @@ -475,7 +475,7 @@ def test_get_dataset_metadata(self): dset_dict = HDF5_utilities.get_dataset_metadata(self.path, self.dset_path) dict_by_hand ={'ndim': 3, 'shape': (91, 135, 160), 'size': 1965600, 'dtype': np.float32, 'compression': None, 'chunks': None, 'is_virtual': False} - self.assertDictContainsSubset(dict_by_hand,dset_dict) + self.assertEqual(dset_dict, dict_by_hand | dset_dict) def test_read(self): diff --git a/Wrappers/Python/test/test_subset.py b/Wrappers/Python/test/test_subset.py index ed8323c3df..58db8a1807 100644 --- a/Wrappers/Python/test/test_subset.py +++ b/Wrappers/Python/test/test_subset.py @@ -33,7 +33,7 @@ def test_DataContainer(self): arr = numpy.arange(0,120).reshape(2,3,4,5) data = DataContainer(arr, True,dimension_labels=['c','z','y','x']) data.reorder(['x','y','z','c']) - self.assertEquals(data.shape,(5,4,3,2)) + self.assertEqual(data.shape,(5,4,3,2)) numpy.testing.assert_array_equal(data.array, arr.transpose(3,2,1,0)) def test_ImageData(self): @@ -41,16 +41,16 @@ def test_ImageData(self): data = ig.allocate(None) new_order = ['horizontal_x', 'horizontal_y','vertical', 'channel'] data.reorder(new_order) - self.assertEquals(data.shape,(5,4,3,2)) - self.assertEquals(data.geometry.dimension_labels,tuple(new_order)) + self.assertEqual(data.shape,(5,4,3,2)) + self.assertEqual(data.geometry.dimension_labels,tuple(new_order)) def test_AcquisitionData(self): ag = AcquisitionGeometry.create_Parallel3D().set_panel([5,4]).set_angles([0,1,2]).set_channels(2).set_labels(['channel','angle','vertical','horizontal']) data = ag.allocate(None) new_order = ['horizontal', 'vertical','angle', 'channel'] data.reorder(new_order) - self.assertEquals(data.shape,(5,4,3,2)) - self.assertEquals(data.geometry.dimension_labels,tuple(new_order)) + self.assertEqual(data.shape,(5,4,3,2)) + self.assertEqual(data.geometry.dimension_labels,tuple(new_order)) def test_AcquisitionData_forastra(self): ag = AcquisitionGeometry.create_Parallel3D().set_panel([5,4]).set_angles([0,1,2]).set_channels(2).set_labels(['horizontal','vertical', 'angle', 'channel']) @@ -154,44 +154,44 @@ def test_DataContainer(self): data = DataContainer(arr, True,dimension_labels=['c','z','y','x']) data_new = data.get_slice(c=1) - self.assertEquals(data_new.shape,(3,4,5)) + self.assertEqual(data_new.shape,(3,4,5)) numpy.testing.assert_array_equal(data_new.array, arr[1]) data_new = data.get_slice(c=1,y=3) - self.assertEquals(data_new.shape,(3,5)) + self.assertEqual(data_new.shape,(3,5)) numpy.testing.assert_array_equal(data_new.array, arr[1,:,3,:]) data_new = data.get_slice(c=1,y=3,z=1) - self.assertEquals(data_new.shape,(5,)) + self.assertEqual(data_new.shape,(5,)) numpy.testing.assert_array_equal(data_new.array, arr[1,1,3,:]) def test_ImageData(self): ig = ImageGeometry(voxel_num_x=5, voxel_num_y=4, voxel_num_z=3, channels=2, dimension_labels=['channel','vertical','horizontal_y','horizontal_x']) data = ig.allocate(None) data_new = data.get_slice(vertical=1) - self.assertEquals(data_new.shape,(2,4,5)) - self.assertEquals(data_new.geometry.dimension_labels,('channel','horizontal_y','horizontal_x')) + self.assertEqual(data_new.shape,(2,4,5)) + self.assertEqual(data_new.geometry.dimension_labels,('channel','horizontal_y','horizontal_x')) def test_AcquisitionData(self): ag = AcquisitionGeometry.create_Parallel3D().set_panel([5,4]).set_angles([0,1,2]).set_channels(2).set_labels(['channel','angle','vertical','horizontal']) data = ag.allocate(None) data_new = data.get_slice(angle=2) - self.assertEquals(data_new.shape,(2,4,5)) - self.assertEquals(data_new.geometry.dimension_labels,('channel','vertical','horizontal')) + self.assertEqual(data_new.shape,(2,4,5)) + self.assertEqual(data_new.geometry.dimension_labels,('channel','vertical','horizontal')) #won't return a geometry for un-reconstructable slice ag = AcquisitionGeometry.create_Cone3D([0,-200,0],[0,200,0]).set_panel([5,4]).set_angles([0,1,2]).set_channels(2).set_labels(['channel','angle','vertical','horizontal']) data = ag.allocate('random') data_new = data.get_slice(vertical=1,force=True) - self.assertEquals(data_new.shape,(2,3,5)) + self.assertEqual(data_new.shape,(2,3,5)) self.assertTrue(isinstance(data_new,(DataContainer))) self.assertIsNone(data_new.geometry) - self.assertEquals(data_new.dimension_labels,('channel','angle','horizontal')) + self.assertEqual(data_new.dimension_labels,('channel','angle','horizontal')) #if 'centre' is between pixels interpolates data_new = data.get_slice(vertical='centre') - self.assertEquals(data_new.shape,(2,3,5)) - self.assertEquals(data_new.geometry.dimension_labels,('channel','angle','horizontal')) + self.assertEqual(data_new.shape,(2,3,5)) + self.assertEqual(data_new.geometry.dimension_labels,('channel','angle','horizontal')) numpy.testing.assert_allclose(data_new.array, (data.array[:,:,1,:] +data.array[:,:,2,:])/2 ) class TestSubset(unittest.TestCase): diff --git a/Wrappers/Python/test/utils.py b/Wrappers/Python/test/utils.py index 148bc6abd7..e2e8d825bd 100644 --- a/Wrappers/Python/test/utils.py +++ b/Wrappers/Python/test/utils.py @@ -100,12 +100,13 @@ def initialise_tests(): #ccpi-regularisation toolkit module_info = importlib.util.find_spec("ccpi") if module_info != None: - module_info = importlib.util.find_spec("ccpi.filters.cpu_regularisers") + module_info = importlib.util.find_spec("ccpi.filters.regularisers") if module_info is None: has_ccpi_regularisation = False else: has_ccpi_regularisation = True + system_state['has_ccpi_regularisation']= has_ccpi_regularisation diff --git a/recipe/conda_build_config.yaml b/recipe/conda_build_config.yaml index ca67db8607..28e16d0af2 100644 --- a/recipe/conda_build_config.yaml +++ b/recipe/conda_build_config.yaml @@ -19,31 +19,25 @@ #creates pairs of versions using zip_keys, lists must be the same length python: - - 3.8 - - 3.9 - 3.10 - - 3.8 - - 3.9 - 3.10 - - 3.8 - - 3.9 - 3.10 - - 3.8 - - 3.9 - 3.10 + - 3.11 + - 3.11 + - 3.11 + - 3.11 + - 3.12 numpy: - - 1.21 - - 1.21 - - 1.21 - - 1.22 - - 1.22 - - 1.22 - - 1.23 - - 1.23 - 1.23 - 1.24 + - 1.25 + - 1.26 + - 1.23 - 1.24 - - 1.24 + - 1.25 + - 1.26 + - 1.26 zip_keys: - python - numpy diff --git a/recipe/meta.yaml b/recipe/meta.yaml index d229dc744c..7094ff9660 100644 --- a/recipe/meta.yaml +++ b/recipe/meta.yaml @@ -36,10 +36,10 @@ test: - cvxpy # [ linux ] - scikit-image - tomophantom=2.0.0 # [ linux ] - - tigre=2.4 # [ not osx ] + - tigre=2.6 - packaging - - ccpi-regulariser=22.0.0 # [ not osx ] - - astra-toolbox>=1.9.9.dev5,<2.1 + - ccpi-regulariser=24.0.0 # [ not osx ] + - astra-toolbox=2.1=cuda* # [ not osx ] source_files: - ./Wrappers/Python/test # [win] @@ -91,9 +91,9 @@ requirements: #optional packages with version dependancies run_constrained: - tomophantom=2.0.0 - - astra-toolbox>=1.9.9.dev5,<2.1 - - tigre=2.4 - - ccpi-regulariser=22.0.0 + - astra-toolbox>=1.9.9.dev5,<=2.1 + - tigre>=2.4,<=2.6 + - ccpi-regulariser=24.0.0 - ipywidgets about: diff --git a/scripts/create_local_env_for_cil_development.sh b/scripts/create_local_env_for_cil_development.sh old mode 100755 new mode 100644 index 16ef0222a5..b193b37bb2 --- a/scripts/create_local_env_for_cil_development.sh +++ b/scripts/create_local_env_for_cil_development.sh @@ -74,8 +74,8 @@ if test $test_deps = 0; then conda_args+=(-c conda-forge -c intel -c defaults --override-channels) else conda_args+=( - astra-toolbox'>=1.9.9.dev5,<2.1' - ccpi-regulariser=22.0.0 + astra-toolbox=2.1=cuda* + ccpi-regulariser=24.0.0 cil-data cvxpy ipywidgets @@ -83,7 +83,7 @@ else python-wget setuptools scikit-image - tigre=2.4 + tigre=2.6 tomophantom=2.0.0 -c conda-forge -c intel diff --git a/scripts/requirements-test.yml b/scripts/requirements-test.yml index eb72894e91..e0c109c56c 100644 --- a/scripts/requirements-test.yml +++ b/scripts/requirements-test.yml @@ -14,27 +14,26 @@ name: cil_dev channels: - conda-forge - - intel - - ccpi + - nvidia - defaults dependencies: # base (vis. recipe/conda_build_config.yaml) - python=3.10 - numpy=1.24 - - cil-data - - tigre=2.4 - - ccpi-regulariser=22.0.0 - - tomophantom=2.0.0 - - astra-toolbox >=1.9.9.dev5,<2.1 + - ccpi::cil-data + - ccpi::tigre=2.6 + - ccpi::ccpi-regulariser=24.0.0 + - ccpi::tomophantom=2.0.0 + - astra-toolbox=2.1=cuda* - cvxpy - python-wget - scikit-image - packaging - cmake >=3.16 - setuptools - - ipp-include >=2021.10 - - ipp-devel >=2021.10 - - ipp >=2021.10 + - intel::ipp-include >=2021.10 + - intel::ipp-devel >=2021.10 + - intel::ipp >=2021.10 - ipywidgets - scipy - matplotlib