From c56bf1eb657defa53eaa1348f302c2a425ea3be4 Mon Sep 17 00:00:00 2001
From: theos <theo.steininger@ultimanet.de>
Date: Thu, 8 Sep 2016 02:56:16 +0200
Subject: [PATCH] Fixed lmhptransformation.py and hplmtransformation.py.

---
 .../transformations/gllmtransformation.py     |  37 ++---
 .../transformations/hplmtransformation.py     | 141 ++++++----------
 .../transformations/lmgltransformation.py     |  39 +++--
 .../transformations/lmhptransformation.py     | 150 +++++++-----------
 .../transformations/rgrgtransformation.py     |   6 +-
 .../transformations/slicing_transformation.py |  13 +-
 .../transformations/transformation.py         |   4 +-
 7 files changed, 163 insertions(+), 227 deletions(-)

diff --git a/nifty/operators/fft_operator/transformations/gllmtransformation.py b/nifty/operators/fft_operator/transformations/gllmtransformation.py
index d810b8d0e..934ca364d 100644
--- a/nifty/operators/fft_operator/transformations/gllmtransformation.py
+++ b/nifty/operators/fft_operator/transformations/gllmtransformation.py
@@ -21,8 +21,8 @@ class GLLMTransformation(SlicingTransformation):
 
     # ---Mandatory properties and methods---
 
-    @staticmethod
-    def get_codomain(domain):
+    @classmethod
+    def get_codomain(cls, domain):
         """
             Generates a compatible codomain to which transformations are
             reasonable, i.e.\  an instance of the :py:class:`lm_space` class.
@@ -37,9 +37,6 @@ class GLLMTransformation(SlicingTransformation):
             codomain : LMSpace
                 A compatible codomain.
         """
-        if domain is None:
-            raise ValueError(about._errors.cstring(
-                "ERROR: cannot generate codomain for None-input"))
 
         if not isinstance(domain, GLSpace):
             raise TypeError(about._errors.cstring(
@@ -53,10 +50,12 @@ class GLLMTransformation(SlicingTransformation):
         else:
             return_dtype = np.float64
 
-        return LMSpace(lmax=lmax, mmax=mmax, dtype=return_dtype)
+        result = LMSpace(lmax=lmax, mmax=mmax, dtype=return_dtype)
+        cls.check_codomain(domain, result)
+        return result
 
-    @classmethod
-    def check_codomain(cls, domain, codomain):
+    @staticmethod
+    def check_codomain(domain, codomain):
         if not isinstance(domain, GLSpace):
             raise TypeError(about._errors.cstring(
                 "ERROR: domain is not a GLSpace"))
@@ -71,17 +70,20 @@ class GLLMTransformation(SlicingTransformation):
         mmax = codomain.mmax
 
         if lmax != mmax:
-            raise ValueError('ERROR: codomain has lmax != mmax.')
+            raise ValueError(about._errors.cstring(
+                'ERROR: codomain has lmax != mmax.'))
 
         if lmax != nlat - 1:
-            raise ValueError('ERROR: codomain has lmax != nlat - 1.')
+            raise ValueError(about._errors.cstring(
+                'ERROR: codomain has lmax != nlat - 1.'))
 
         if nlon != 2 * nlat - 1:
-            raise ValueError('ERROR: domain has nlon != 2 * nlat - 1.')
+            raise ValueError(about._errors.cstring(
+                'ERROR: domain has nlon != 2 * nlat - 1.'))
 
         return None
 
-    def _transformation_of_slice(self, inp):
+    def _transformation_of_slice(self, inp, **kwargs):
         nlat = self.domain.nlat
         nlon = self.domain.nlon
         lmax = self.codomain.lmax
@@ -93,19 +95,14 @@ class GLLMTransformation(SlicingTransformation):
                                                              nlat=nlat,
                                                              nlon=nlon,
                                                              lmax=lmax,
-                                                             mmax=mmax)
+                                                             mmax=mmax,
+                                                             **kwargs)
                                         for x in (inp.real, inp.imag)]
 
             [resultReal, resultImag] = [ltf.buildIdx(x, lmax=lmax)
                                         for x in [resultReal, resultImag]]
 
-            # construct correct complex dtype
-            one = resultReal.dtype.type(1)
-            result_dtype = np.dtype(type(one + 1j))
-
-            result = np.empty_like(resultReal, dtype=result_dtype)
-            result.real = resultReal
-            result.imag = resultImag
+            result = self._combine_complex_result(resultReal, resultImag)
         else:
             result = self.libsharpMap2Alm(inp, nlat=nlat, nlon=nlon, lmax=lmax,
                                           mmax=mmax)
diff --git a/nifty/operators/fft_operator/transformations/hplmtransformation.py b/nifty/operators/fft_operator/transformations/hplmtransformation.py
index f1fb2caf4..a73428e69 100644
--- a/nifty/operators/fft_operator/transformations/hplmtransformation.py
+++ b/nifty/operators/fft_operator/transformations/hplmtransformation.py
@@ -1,31 +1,29 @@
 import numpy as np
-from transformation import Transformation
-from d2o import distributed_data_object
-from nifty.config import dependency_injector as gdi
-import nifty.nifty_utilities as utilities
+from nifty.config import dependency_injector as gdi,\
+                         about
 from nifty import HPSpace, LMSpace
+from slicing_transformation import SlicingTransformation
 
 import lm_transformation_factory as ltf
 
 hp = gdi.get('healpy')
 
 
-class HPLMTransformation(Transformation):
+class HPLMTransformation(SlicingTransformation):
+
+    # ---Overwritten properties and methods---
+
     def __init__(self, domain, codomain=None, module=None):
         if 'healpy' not in gdi:
-            raise ImportError("The module healpy is needed but not available")
-
-        if codomain is None:
-            self.domain = domain
-            self.codomain = self.get_codomain(domain)
-        elif self.check_codomain(domain, codomain):
-            self.domain = domain
-            self.codomain = codomain
-        else:
-            raise ValueError("ERROR: Incompatible codomain!")
+            raise ImportError(about._errors.cstring(
+                "The module healpy is needed but not available"))
 
-    @staticmethod
-    def get_codomain(domain):
+        super(HPLMTransformation, self).__init__(domain, codomain, module)
+
+    # ---Mandatory properties and methods---
+
+    @classmethod
+    def get_codomain(cls, domain):
         """
             Generates a compatible codomain to which transformations are
             reasonable, i.e.\  an instance of the :py:class:`lm_space` class.
@@ -40,100 +38,65 @@ class HPLMTransformation(Transformation):
             codomain : LMSpace
                 A compatible codomain.
         """
-        if domain is None:
-            raise ValueError('ERROR: cannot generate codomain for None')
 
         if not isinstance(domain, HPSpace):
-            raise TypeError('ERROR: domain needs to be a HPSpace')
+            raise TypeError(about._errors.cstring(
+                "ERROR: domain needs to be a HPSpace"))
 
         lmax = 3 * domain.nside - 1
         mmax = lmax
-        return LMSpace(lmax=lmax, mmax=mmax, dtype=np.dtype('complex128'))
+
+        result = LMSpace(lmax=lmax, mmax=mmax, dtype=np.dtype('float64'))
+        cls.check_codomain(domain, result)
+        return result
 
     @staticmethod
     def check_codomain(domain, codomain):
         if not isinstance(domain, HPSpace):
-            raise TypeError('ERROR: domain is not a HPSpace')
-
-        if codomain is None:
-            return False
+            raise TypeError(about._errors.cstring(
+                'ERROR: domain is not a HPSpace'))
 
         if not isinstance(codomain, LMSpace):
-            raise TypeError('ERROR: codomain must be a LMSpace.')
+            raise TypeError(about._errors.cstring(
+                'ERROR: codomain must be a LMSpace.'))
 
         nside = domain.nside
         lmax = codomain.lmax
         mmax = codomain.mmax
 
-        if (3 * nside - 1 != lmax) or (lmax != mmax):
-            return False
+        if 3 * nside - 1 != lmax:
+            raise ValueError(about._errors.cstring(
+                'ERROR: codomain has 3*nside-1 != lmax.'))
 
-        return True
+        if lmax != mmax:
+            raise ValueError(about._errors.cstring(
+                'ERROR: codomain has lmax != mmax.'))
 
-    def transform(self, val, axes=None, **kwargs):
-        """
-        HP -> LM transform method.
-
-        Parameters
-        ----------
-        val : np.ndarray or distributed_data_object
-            The value array which is to be transformed
+        return None
 
-        axes : None or tuple
-            The axes along which the transformation should take place
+    def _transformation_of_slice(self, inp, **kwargs):
+        lmax = self.codomain.lmax
+        mmax = self.codomain.mmax
 
-        """
-        # get by number of iterations from kwargs
-        niter = kwargs['niter'] if 'niter' in kwargs else 0
+        if issubclass(inp.dtype.type, np.complexfloating):
+            [resultReal, resultImag] = [hp.map2alm(x.astype(np.float64,
+                                                            copy=False),
+                                                   lmax=lmax,
+                                                   mmax=mmax,
+                                                   pol=True,
+                                                   use_weights=False,
+                                                   **kwargs)
+                                        for x in (inp.real, inp.imag)]
 
-        if self.domain.discrete:
-            val = self.domain.weight(val, power=-0.5, axes=axes)
+            [resultReal, resultImag] = [ltf.buildIdx(x, lmax=lmax)
+                                        for x in [resultReal, resultImag]]
 
-        # shorthands for transform parameters
-        lmax = self.codomain.lmax
-        mmax = self.codomain.mmax
+            result = self._combine_complex_result(resultReal, resultImag)
 
-        if isinstance(val, distributed_data_object):
-            temp_val = val.get_full_data()
-        else:
-            temp_val = val
-
-        return_val = None
-
-        for slice_list in utilities.get_slice_list(temp_val.shape, axes):
-            if slice_list == [slice(None, None)]:
-                inp = temp_val
-            else:
-                if return_val is None:
-                    return_val = np.empty_like(temp_val)
-                inp = temp_val[slice_list]
-
-            if self.domain.dtype == np.dtype('complex128'):
-                inpReal = hp.map2alm(
-                    np.real(inp).astype(np.float64, copy=False),
-                    lmax=lmax, mmax=mmax, iter=niter, pol=True,
-                    use_weights=False, datapath=None)
-                inpImg = hp.map2alm(
-                    np.imag(inp).astype(np.float64, copy=False),
-                    lmax=lmax, mmax=mmax, iter=niter, pol=True,
-                    use_weights=False, datapath=None)
-                inpReal = ltf.buildIdx(inpReal, lmax=lmax)
-                inpImg = ltf.buildIdx(inpImg, lmax=lmax)
-                inp = inpReal + inpImg * 1j
-            else:
-                inp = hp.map2alm(inp.astype(np.float64, copy=False),
-                                 lmax=lmax, mmax=mmax, iter=niter, pol=True,
-                                 use_weights=False, datapath=None)
-                inp = ltf.buildIdx(inp, lmax=lmax)
-            if slice_list == [slice(None, None)]:
-                return_val = inp
-            else:
-                return_val[slice_list] = inp
-
-        if isinstance(val, distributed_data_object):
-            new_val = val.copy_empty(dtype=self.codomain.dtype)
-            new_val.set_full_data(return_val, copy=False)
         else:
-            return_val = return_val.astype(self.codomain.dtype, copy=False)
+            result = hp.map2alm(inp.astype(np.float64, copy=False),
+                                lmax=lmax, mmax=mmax, pol=True,
+                                use_weights=False)
+            result = ltf.buildIdx(result, lmax=lmax)
 
-        return return_val
+        return result
diff --git a/nifty/operators/fft_operator/transformations/lmgltransformation.py b/nifty/operators/fft_operator/transformations/lmgltransformation.py
index 0fa3c27e4..4fe809f65 100644
--- a/nifty/operators/fft_operator/transformations/lmgltransformation.py
+++ b/nifty/operators/fft_operator/transformations/lmgltransformation.py
@@ -22,8 +22,8 @@ class LMGLTransformation(SlicingTransformation):
 
     # ---Mandatory properties and methods---
 
-    @staticmethod
-    def get_codomain(domain):
+    @classmethod
+    def get_codomain(cls, domain):
         """
             Generates a compatible codomain to which transformations are
             reasonable, i.e.\  a pixelization of the two-sphere.
@@ -45,10 +45,6 @@ class LMGLTransformation(SlicingTransformation):
                    harmonic transforms revisited";
                    `arXiv:1303.4945 <http://www.arxiv.org/abs/1303.4945>`_
         """
-        if domain is None:
-            raise ValueError(about._errors.cstring(
-                'ERROR: cannot generate codomain for None-input'))
-
         if not isinstance(domain, LMSpace):
             raise TypeError(about._errors.cstring(
                 'ERROR: domain needs to be a LMSpace'))
@@ -61,15 +57,19 @@ class LMGLTransformation(SlicingTransformation):
         nlat = domain.lmax + 1
         nlon = domain.lmax * 2 + 1
 
-        return GLSpace(nlat=nlat, nlon=nlon, dtype=new_dtype)
+        result = GLSpace(nlat=nlat, nlon=nlon, dtype=new_dtype)
+        cls.check_codomain(domain, result)
+        return result
 
     @staticmethod
     def check_codomain(domain, codomain):
         if not isinstance(domain, LMSpace):
-            raise TypeError('ERROR: domain is not a LMSpace')
+            raise TypeError(about._errors.cstring(
+                'ERROR: domain is not a LMSpace'))
 
         if not isinstance(codomain, GLSpace):
-            raise TypeError('ERROR: codomain must be a GLSpace.')
+            raise TypeError(about._errors.cstring(
+                'ERROR: codomain must be a GLSpace.'))
 
         nlat = codomain.nlat
         nlon = codomain.nlon
@@ -77,17 +77,20 @@ class LMGLTransformation(SlicingTransformation):
         mmax = domain.mmax
 
         if lmax != mmax:
-            raise ValueError('ERROR: domain has lmax != mmax.')
+            raise ValueError(about._errors.cstring(
+                'ERROR: domain has lmax != mmax.'))
 
         if nlat != lmax + 1:
-            raise ValueError('ERROR: codomain has nlat != lmax + 1.')
+            raise ValueError(about._errors.cstring(
+                'ERROR: codomain has nlat != lmax + 1.'))
 
         if nlon != 2 * lmax + 1:
-            raise ValueError('ERROR: domain has nlon != 2 * lmax + 1.')
+            raise ValueError(about._errors.cstring(
+                'ERROR: domain has nlon != 2 * lmax + 1.'))
 
         return None
 
-    def _transformation_of_slice(self, inp):
+    def _transformation_of_slice(self, inp, **kwargs):
         nlat = self.codomain.nlat
         nlon = self.codomain.nlon
         lmax = self.domain.lmax
@@ -102,16 +105,12 @@ class LMGLTransformation(SlicingTransformation):
                                                              nlon=nlon,
                                                              lmax=lmax,
                                                              mmax=mmax,
-                                                             cl=False)
+                                                             cl=False,
+                                                             **kwargs)
                                         for x in [resultReal, resultImag]]
 
-            # construct correct complex dtype
-            one = resultReal.dtype.type(1)
-            result_dtype = np.dtype(type(one + 1j))
+            result = self._combine_complex_result(resultReal, resultImag)
 
-            result = np.empty_like(resultReal, dtype=result_dtype)
-            result.real = resultReal
-            result.imag = resultImag
         else:
             result = ltf.buildLm(inp, lmax=lmax)
             result = self.libsharpAlm2Map(result, nlat=nlat, nlon=nlon,
diff --git a/nifty/operators/fft_operator/transformations/lmhptransformation.py b/nifty/operators/fft_operator/transformations/lmhptransformation.py
index 29c20f4e0..b90e94168 100644
--- a/nifty/operators/fft_operator/transformations/lmhptransformation.py
+++ b/nifty/operators/fft_operator/transformations/lmhptransformation.py
@@ -1,29 +1,28 @@
 import numpy as np
-from transformation import Transformation
-from d2o import distributed_data_object
-from nifty.config import dependency_injector as gdi
-import nifty.nifty_utilities as utilities
+from nifty.config import dependency_injector as gdi,\
+                         about
 from nifty import HPSpace, LMSpace
-
+from slicing_transformation import SlicingTransformation
 import lm_transformation_factory as ltf
 
 hp = gdi.get('healpy')
 
 
-class LMHPTransformation(Transformation):
+class LMHPTransformation(SlicingTransformation):
+
+    # ---Overwritten properties and methods---
+
     def __init__(self, domain, codomain=None, module=None):
         if gdi.get('healpy') is None:
-            raise ImportError(
-                "The module libsharp is needed but not available.")
+            raise ImportError(about._errors.cstring(
+                "The module libsharp is needed but not available."))
 
-        if self.check_codomain(domain, codomain):
-            self.domain = domain
-            self.codomain = codomain
-        else:
-            raise ValueError("ERROR: Incompatible codomain!")
+        super(LMHPTransformation, self).__init__(domain, codomain, module)
 
-    @staticmethod
-    def get_codomain(domain):
+    # ---Mandatory properties and methods---
+
+    @classmethod
+    def get_codomain(cls, domain):
         """
             Generates a compatible codomain to which transformations are
             reasonable, i.e.\  a pixelization of the two-sphere.
@@ -44,100 +43,67 @@ class LMHPTransformation(Transformation):
                    High-Resolution Discretization and Fast Analysis of Data
                    Distributed on the Sphere", *ApJ* 622..759G.
         """
-        if domain is None:
-            raise ValueError('ERROR: cannot generate codomain for None')
-
         if not isinstance(domain, LMSpace):
-            raise TypeError('ERROR: domain needs to be a LMSpace')
+            raise TypeError(about._errors.cstring(
+                'ERROR: domain needs to be a LMSpace'))
 
         nside = (domain.lmax + 1) // 3
-        return HPSpace(nside=nside)
+        result = HPSpace(nside=nside)
+        cls.check_codomain(domain, result)
+        return result
 
     @staticmethod
     def check_codomain(domain, codomain):
         if not isinstance(domain, LMSpace):
-            raise TypeError('ERROR: domain is not a LMSpace')
-
-        if codomain is None:
-            return False
+            raise TypeError(about._errors.cstring(
+                'ERROR: domain is not a LMSpace'))
 
         if not isinstance(codomain, HPSpace):
-            raise TypeError('ERROR: codomain must be a HPSpace.')
+            raise TypeError(about._errors.cstring(
+                'ERROR: codomain must be a HPSpace.'))
+
         nside = codomain.nside
         lmax = domain.lmax
         mmax = domain.mmax
 
-        if (lmax != mmax) or (3 * nside - 1 != lmax):
-            return False
+        if lmax != mmax:
+            raise ValueError(about._errors.cstring(
+                'ERROR: domain has lmax != mmax.'))
 
-        return True
+        if 3*nside - 1 != lmax:
+            raise ValueError(about._errors.cstring(
+                'ERROR: codomain has 3*nside -1 != lmax.'))
 
-    def transform(self, val, axes=None, **kwargs):
-        """
-        LM -> HP transform method.
+        return None
 
-        Parameters
-        ----------
-        val : np.ndarray or distributed_data_object
-            The value array which is to be transformed
+    def _transformation_of_slice(self, inp, **kwargs):
+        nside = self.codomain.nside
+        lmax = self.domain.lmax
+        mmax = self.domain.mmax
 
-        axes : None or tuple
-            The axes along which the transformation should take place
+        if issubclass(inp.dtype.type, np.complexfloating):
+            [resultReal, resultImag] = [ltf.buildLm(x, lmax=lmax)
+                                        for x in (inp.real, inp.imag)]
+
+            [resultReal, resultImag] = [hp.map2alm(x.astype(np.complex128,
+                                                            copy=False),
+                                                   nside,
+                                                   lmax=lmax,
+                                                   mmax=mmax,
+                                                   pixwin=False,
+                                                   fwhm=0.0,
+                                                   sigma=None,
+                                                   pol=True,
+                                                   inplace=False,
+                                                   **kwargs)
+                                        for x in [resultReal, resultImag]]
+
+            result = self._combine_complex_result(resultReal, resultImag)
 
-        """
-        if isinstance(val, distributed_data_object):
-            temp_val = val.get_full_data()
-        else:
-            temp_val = val
-
-        return_val = None
-
-        for slice_list in utilities.get_slice_list(temp_val.shape, axes):
-            if slice_list == [slice(None, None)]:
-                inp = temp_val
-            else:
-                if return_val is None:
-                    return_val = np.empty_like(temp_val)
-                inp = temp_val[slice_list]
-
-            nside = self.codomain.nside
-            lmax = self.domain.lmax
-            mmax = self.domain.mmax
-
-            if self.domain.dtype == np.dtype('complex128'):
-                inpReal = np.real(inp)
-                inpImag = np.imag(inp)
-                inpReal = ltf.buildLm(inpReal,lmax=lmax)
-                inpImag = ltf.buildLm(inpImag,lmax=lmax)
-                inpReal = hp.alm2map(inpReal.astype(np.complex128, copy=False), nside,
-                                 lmax=lmax, mmax=mmax,
-                                 pixwin=False, fwhm=0.0, sigma=None,
-                                 pol=True, inplace=False)
-                inpImag = hp.alm2map(inpImag.astype(np.complex128, copy=False), nside,
-                                 lmax=lmax, mmax=mmax,
-                                 pixwin=False, fwhm=0.0, sigma=None,
-                                 pol=True, inplace=False)
-                inp = inpReal+inpImag*(1j)
-            else:
-                inp = ltf.buildLm(inp, lmax=lmax)
-                inp = hp.alm2map(inp.astype(np.complex128, copy=False), nside,
-                                 lmax=lmax, mmax=mmax,
-                                 pixwin=False, fwhm=0.0, sigma=None,
-                                 pol=True, inplace=False)
-
-            if slice_list == [slice(None, None)]:
-                return_val = inp
-            else:
-                return_val[slice_list] = inp
-
-        # re-weight if discrete
-        if self.codomain.discrete:
-            val = self.codomain.weight(val, power=0.5, axes=axes)
-
-        if isinstance(val, distributed_data_object):
-            new_val = val.copy_empty(dtype=self.codomain.dtype)
-            new_val.set_full_data(return_val, copy=False)
         else:
-            return_val = return_val.astype(self.codomain.dtype, copy=False)
+            result = ltf.buildLm(inp, lmax=lmax)
+            result = hp.alm2map(result.astype(np.complex128, copy=False),
+                                nside, lmax=lmax, mmax=mmax, pixwin=False,
+                                fwhm=0.0, sigma=None, pol=True, inplace=False)
 
-        return return_val
+        return result
diff --git a/nifty/operators/fft_operator/transformations/rgrgtransformation.py b/nifty/operators/fft_operator/transformations/rgrgtransformation.py
index fac5ac5dd..0cbcaa868 100644
--- a/nifty/operators/fft_operator/transformations/rgrgtransformation.py
+++ b/nifty/operators/fft_operator/transformations/rgrgtransformation.py
@@ -33,8 +33,8 @@ class RGRGTransformation(Transformation):
             else:
                 raise ValueError('ERROR: unknow FFT module:' + module)
 
-    @staticmethod
-    def get_codomain(domain, dtype=None, zerocenter=None):
+    @classmethod
+    def get_codomain(cls, domain, dtype=None, zerocenter=None):
         """
             Generates a compatible codomain to which transformations are
             reasonable, i.e.\  either a shifted grid or a Fourier conjugate
@@ -78,7 +78,7 @@ class RGRGTransformation(Transformation):
                             distances=distances,
                             harmonic=(not domain.harmonic),
                             dtype=dtype)
-
+        cls.check_codomain(domain, new_space)
         return new_space
 
     @staticmethod
diff --git a/nifty/operators/fft_operator/transformations/slicing_transformation.py b/nifty/operators/fft_operator/transformations/slicing_transformation.py
index 914a02d99..d0cc0df9e 100644
--- a/nifty/operators/fft_operator/transformations/slicing_transformation.py
+++ b/nifty/operators/fft_operator/transformations/slicing_transformation.py
@@ -25,12 +25,23 @@ class SlicingTransformation(Transformation):
             data = val.get_data(slice_list, copy=False)
             data = data.get_full_data()
 
-            data = self._transformation_of_slice(data)
+            data = self._transformation_of_slice(data, **kwargs)
 
             return_val.set_data(data=data, to_key=slice_list, copy=False)
 
         return return_val
 
+    def _combine_complex_result(self, resultReal, resultImag):
+        # construct correct complex dtype
+        one = resultReal.dtype.type(1)
+        result_dtype = np.dtype(type(one + 1j))
+
+        result = np.empty_like(resultReal, dtype=result_dtype)
+        result.real = resultReal
+        result.imag = resultImag
+
+        return result
+
     @abc.abstractmethod
     def _transformation_of_slice(self, inp):
         raise NotImplementedError
diff --git a/nifty/operators/fft_operator/transformations/transformation.py b/nifty/operators/fft_operator/transformations/transformation.py
index 125efe768..0e5df8f46 100644
--- a/nifty/operators/fft_operator/transformations/transformation.py
+++ b/nifty/operators/fft_operator/transformations/transformation.py
@@ -18,8 +18,8 @@ class Transformation(object):
             self.domain = domain
             self.codomain = codomain
 
-    @staticmethod
-    def get_codomain(domain, dtype=None, zerocenter=None):
+    @classmethod
+    def get_codomain(cls, domain, dtype=None, zerocenter=None):
         raise NotImplementedError
 
     @staticmethod
-- 
GitLab