summaryrefslogtreecommitdiff
path: root/silx/math/fft/test/test_fft.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/math/fft/test/test_fft.py')
-rw-r--r--silx/math/fft/test/test_fft.py270
1 files changed, 0 insertions, 270 deletions
diff --git a/silx/math/fft/test/test_fft.py b/silx/math/fft/test/test_fft.py
deleted file mode 100644
index 9ef2fd2..0000000
--- a/silx/math/fft/test/test_fft.py
+++ /dev/null
@@ -1,270 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-"""Test of the FFT module"""
-
-import numpy as np
-import unittest
-import logging
-try:
- from scipy.misc import ascent
- __have_scipy = True
-except ImportError:
- __have_scipy = False
-from silx.utils.testutils import ParametricTestCase
-from silx.math.fft.fft import FFT
-from silx.math.fft.clfft import __have_clfft__
-from silx.math.fft.cufft import __have_cufft__
-from silx.math.fft.fftw import __have_fftw__
-
-from silx.test.utils import test_options
-
-logger = logging.getLogger(__name__)
-
-
-class TransformInfos(object):
- def __init__(self):
- self.dimensions = [
- "1D",
- "batched_1D",
- "2D",
- "batched_2D",
- "3D",
- ]
- self.modes = {
- "R2C": np.float32,
- "R2C_double": np.float64,
- "C2C": np.complex64,
- "C2C_double": np.complex128,
- }
- self.sizes = {
- "1D": [(128,), (127,)],
- "2D": [(128, 128), (128, 127), (127, 128), (127, 127)],
- "3D": [(64, 64, 64), (64, 64, 63), (64, 63, 64), (63, 64, 64),
- (64, 63, 63), (63, 64, 63), (63, 63, 64), (63, 63, 63)]
- }
- self.axes = {
- "1D": None,
- "batched_1D": (-1,),
- "2D": None,
- "batched_2D": (-2, -1),
- "3D": None,
- }
- self.sizes["batched_1D"] = self.sizes["2D"]
- self.sizes["batched_2D"] = self.sizes["3D"]
-
-
-class TestData(object):
- def __init__(self):
- self.data = ascent().astype("float32")
- self.data1d = self.data[:, 0] # non-contiguous data
- self.data3d = np.tile(self.data[:64, :64], (64, 1, 1))
- self.data_refs = {
- 1: self.data1d,
- 2: self.data,
- 3: self.data3d,
- }
-
-
-@unittest.skipUnless(__have_scipy, "scipy is missing")
-class TestFFT(ParametricTestCase):
- """Test cuda/opencl/fftw backends of FFT"""
-
- def setUp(self):
- self.tol = {
- np.dtype("float32"): 1e-3,
- np.dtype("float64"): 1e-9,
- np.dtype("complex64"): 1e-3,
- np.dtype("complex128"): 1e-9,
- }
- self.transform_infos = TransformInfos()
- self.test_data = TestData()
-
- @staticmethod
- def calc_mae(arr1, arr2):
- """
- Compute the Max Absolute Error between two arrays
- """
- return np.max(np.abs(arr1 - arr2))
-
- @unittest.skipIf(not __have_cufft__,
- "cuda back-end requires pycuda and scikit-cuda")
- def test_cuda(self):
- import pycuda.autoinit
-
- # Error is higher when using cuda. fast_math mode ?
- self.tol[np.dtype("float32")] *= 2
-
- self.__run_tests(backend="cuda")
-
- @unittest.skipIf(not __have_clfft__,
- "opencl back-end requires pyopencl and gpyfft")
- def test_opencl(self):
- from silx.opencl.common import ocl
- if ocl is not None:
- self.__run_tests(backend="opencl", ctx=ocl.create_context())
-
- @unittest.skipIf(not __have_fftw__,
- "fftw back-end requires pyfftw")
- def test_fftw(self):
- self.__run_tests(backend="fftw")
-
- def __run_tests(self, backend, **extra_args):
- """Run all tests with the given backend
-
- :param str backend:
- :param dict extra_args: Additional arguments to provide to FFT
- """
- for trdim in self.transform_infos.dimensions:
- for mode in self.transform_infos.modes:
- for size in self.transform_infos.sizes[trdim]:
- with self.subTest(trdim=trdim, mode=mode, size=size):
- self.__test(backend, trdim, mode, size, **extra_args)
-
- def __test(self, backend, trdim, mode, size, **extra_args):
- """Compare given backend with numpy for given conditions"""
- logger.debug("backend: %s, trdim: %s, mode: %s, size: %s",
- backend, trdim, mode, str(size))
- if size == "3D" and test_options.TEST_LOW_MEM:
- self.skipTest("low mem")
-
- ndim = len(size)
- input_data = self.test_data.data_refs[ndim].astype(
- self.transform_infos.modes[mode])
- tol = self.tol[np.dtype(input_data.dtype)]
- if trdim == "3D":
- tol *= 10 # Error is relatively high in high dimensions
- # It seems that cuda has problems with C2D batched 1D
- if trdim == "batched_1D" and backend == "cuda" and mode == "C2C":
- tol *= 10
-
- # Python < 3.5 does not want to mix **extra_args with existing kwargs
- fft_args = {
- "template": input_data,
- "axes": self.transform_infos.axes[trdim],
- "backend": backend,
- }
- fft_args.update(extra_args)
- F = FFT(
- **fft_args
- )
- F_np = FFT(
- template=input_data,
- axes=self.transform_infos.axes[trdim],
- backend="numpy"
- )
-
- # Forward FFT
- res = F.fft(input_data)
- res_np = F_np.fft(input_data)
- mae = self.calc_mae(res, res_np)
- all_close = np.allclose(res, res_np, atol=tol, rtol=tol),
- self.assertTrue(
- all_close,
- "FFT %s:%s, MAE(%s, numpy) = %f (tol = %.2e)" % (mode, trdim, backend, mae, tol)
- )
-
- # Inverse FFT
- res2 = F.ifft(res)
- mae = self.calc_mae(res2, input_data)
- self.assertTrue(
- mae < tol,
- "IFFT %s:%s, MAE(%s, numpy) = %f" % (mode, trdim, backend, mae)
- )
-
-
-@unittest.skipUnless(__have_scipy, "scipy is missing")
-class TestNumpyFFT(ParametricTestCase):
- """
- Test the Numpy backend individually.
- """
-
- def setUp(self):
- transforms = {
- "1D": {
- True: (np.fft.rfft, np.fft.irfft),
- False: (np.fft.fft, np.fft.ifft),
- },
- "2D": {
- True: (np.fft.rfft2, np.fft.irfft2),
- False: (np.fft.fft2, np.fft.ifft2),
- },
- "3D": {
- True: (np.fft.rfftn, np.fft.irfftn),
- False: (np.fft.fftn, np.fft.ifftn),
- },
- }
- transforms["batched_1D"] = transforms["1D"]
- transforms["batched_2D"] = transforms["2D"]
- self.transforms = transforms
- self.transform_infos = TransformInfos()
- self.test_data = TestData()
-
- def test(self):
- """Test the numpy backend against native fft.
-
- Results should be exactly the same.
- """
- for trdim in self.transform_infos.dimensions:
- for mode in self.transform_infos.modes:
- for size in self.transform_infos.sizes[trdim]:
- with self.subTest(trdim=trdim, mode=mode, size=size):
- self.__test(trdim, mode, size)
-
- def __test(self, trdim, mode, size):
- logger.debug("trdim: %s, mode: %s, size: %s", trdim, mode, str(size))
- ndim = len(size)
- input_data = self.test_data.data_refs[ndim].astype(
- self.transform_infos.modes[mode])
- np_fft, np_ifft = self.transforms[trdim][np.isrealobj(input_data)]
-
- F = FFT(
- template=input_data,
- axes=self.transform_infos.axes[trdim],
- backend="numpy"
- )
- # Test FFT
- res = F.fft(input_data)
- ref = np_fft(input_data)
- self.assertTrue(np.allclose(res, ref))
-
- # Test IFFT
- res2 = F.ifft(res)
- ref2 = np_ifft(ref)
- self.assertTrue(np.allclose(res2, ref2))
-
-
-def suite():
- suite = unittest.TestSuite()
- for cls in (TestNumpyFFT, TestFFT):
- suite.addTest(
- unittest.defaultTestLoader.loadTestsFromTestCase(cls))
- return suite
-
-
-if __name__ == '__main__':
- unittest.main(defaultTest="suite")
-
-