From 32e3b4e142c8c69e15aa4e7889d4709afddf4ea5 Mon Sep 17 00:00:00 2001
From: Marco Selig <mselig@ncg-02.MPA-Garching.MPG.DE>
Date: Fri, 30 Jan 2015 10:37:41 +0100
Subject: [PATCH] submodule rg implemented.

---
 .gitignore                              |    8 +
 __init__.py                             |   10 +-
 nifty_core.py                           | 1175 +---------------------
 rg/__init__.py                          |   24 +
 rg/gfft_rg.py                           |  454 +++++++++
 rg/nifty_power_conversion_rg.py         |  155 +++
 rg/nifty_rg.py                          | 1218 +++++++++++++++++++++++
 powerspectrum.py => rg/powerspectrum.py |    0
 smoothing.py => rg/smoothing.py         |    0
 9 files changed, 1871 insertions(+), 1173 deletions(-)
 create mode 100644 rg/__init__.py
 create mode 100644 rg/gfft_rg.py
 create mode 100644 rg/nifty_power_conversion_rg.py
 create mode 100644 rg/nifty_rg.py
 rename powerspectrum.py => rg/powerspectrum.py (100%)
 rename smoothing.py => rg/smoothing.py (100%)

diff --git a/.gitignore b/.gitignore
index 130c46a0a..3c5d66878 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,14 @@
 .spyderproject
 build
 
+rg/*
+!rg/__init__.py
+!rg/nifty_rg.py
+!rg/nifty_power_conversion_rg.py
+!rg/gfft_rg.py
+!rg/powerspectrum.py
+!rg/smoothing.py
+
 demos/*
 !demos/__init__.py
 !demos/demos_core.py
diff --git a/__init__.py b/__init__.py
index 4a281acad..196df02aa 100644
--- a/__init__.py
+++ b/__init__.py
@@ -20,12 +20,18 @@
 ## along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 from __future__ import division
-from nifty_core import *
+from nifty_core import * ## imports `about`
 from nifty_cmaps import *
 from nifty_power import *
 from nifty_tools import *
 from nifty_explicit import *
-#from nifty_power_conversion import *
+
+## optional submodule `rg`
+try:
+    from rg import *
+except(ImportError):
+    pass
+
 from demos import *
 from pickling import *
 
diff --git a/nifty_core.py b/nifty_core.py
index bddfe50f3..7cc7493a5 100644
--- a/nifty_core.py
+++ b/nifty_core.py
@@ -153,17 +153,17 @@ from multiprocessing import Pool as mp
 from multiprocessing import Value as mv
 from multiprocessing import Array as ma
 ## third party libraries
-import gfft as gf
+#import gfft as gf
 import healpy as hp
 import libsharp_wrapper_gl as gl
 ## internal libraries
-import smoothing as gs
-import powerspectrum as gp
+#import smoothing as gs
+#import powerspectrum as gp
 
 
 pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
 
-__version__ = "0.9.7"
+__version__ = "1.0.0"
 
 
 ##-----------------------------------------------------------------------------
@@ -2106,1173 +2106,6 @@ class point_space(space):
 
 
 
-##-----------------------------------------------------------------------------
-
-class rg_space(space):
-    """
-        ..      _____   _______
-        ..    /   __/ /   _   /
-        ..   /  /    /  /_/  /
-        ..  /__/     \____  /  space class
-        ..          /______/
-
-        NIFTY subclass for spaces of regular Cartesian grids.
-
-        Parameters
-        ----------
-        num : {int, numpy.ndarray}
-            Number of gridpoints or numbers of gridpoints along each axis.
-        naxes : int, *optional*
-            Number of axes (default: None).
-        zerocenter : {bool, numpy.ndarray}, *optional*
-            Whether the Fourier zero-mode is located in the center of the grid
-            (or the center of each axis speparately) or not (default: True).
-        hermitian : bool, *optional*
-            Whether the fields living in the space follow hermitian symmetry or
-            not (default: True).
-        purelyreal : bool, *optional*
-            Whether the field values are purely real (default: True).
-        dist : {float, numpy.ndarray}, *optional*
-            Distance between two grid points along each axis (default: None).
-        fourier : bool, *optional*
-            Whether the space represents a Fourier or a position grid
-            (default: False).
-
-        Notes
-        -----
-        Only even numbers of grid points per axis are supported.
-        The basis transformations between position `x` and Fourier mode `k`
-        rely on (inverse) fast Fourier transformations using the
-        :math:`exp(2 \pi i k^\dagger x)`-formulation.
-
-        Attributes
-        ----------
-        para : numpy.ndarray
-            One-dimensional array containing information on the axes of the
-            space in the following form: The first entries give the grid-points
-            along each axis in reverse order; the next entry is 0 if the
-            fields defined on the space are purely real-valued, 1 if they are
-            hermitian and complex, and 2 if they are not hermitian, but
-            complex-valued; the last entries hold the information on whether
-            the axes are centered on zero or not, containing a one for each
-            zero-centered axis and a zero for each other one, in reverse order.
-        datatype : numpy.dtype
-            Data type of the field values for a field defined on this space,
-            either ``numpy.float64`` or ``numpy.complex128``.
-        discrete : bool
-            Whether or not the underlying space is discrete, always ``False``
-            for regular grids.
-        vol : numpy.ndarray
-            One-dimensional array containing the distances between two grid
-            points along each axis, in reverse order. By default, the total
-            length of each axis is assumed to be one.
-        fourier : bool
-            Whether or not the grid represents a Fourier basis.
-    """
-    epsilon = 0.0001 ## relative precision for comparisons
-
-    def __init__(self,num,naxes=None,zerocenter=True,hermitian=True,purelyreal=True,dist=None,fourier=False):
-        """
-            Sets the attributes for an rg_space class instance.
-
-            Parameters
-            ----------
-            num : {int, numpy.ndarray}
-                Number of gridpoints or numbers of gridpoints along each axis.
-            naxes : int, *optional*
-                Number of axes (default: None).
-            zerocenter : {bool, numpy.ndarray}, *optional*
-                Whether the Fourier zero-mode is located in the center of the
-                grid (or the center of each axis speparately) or not
-                (default: True).
-            hermitian : bool, *optional*
-                Whether the fields living in the space follow hermitian
-                symmetry or not (default: True).
-            purelyreal : bool, *optional*
-                Whether the field values are purely real (default: True).
-            dist : {float, numpy.ndarray}, *optional*
-                Distance between two grid points along each axis
-                (default: None).
-            fourier : bool, *optional*
-                Whether the space represents a Fourier or a position grid
-                (default: False).
-
-            Returns
-            -------
-            None
-        """
-        ## check parameters
-        para = np.array([],dtype=np.int)
-        if(np.isscalar(num)):
-            num = np.array([num],dtype=np.int)
-        else:
-            num = np.array(num,dtype=np.int)
-        if(np.any(num%2)): ## module restriction
-            raise ValueError(about._errors.cstring("ERROR: unsupported odd number of grid points."))
-        if(naxes is None):
-            naxes = np.size(num)
-        elif(np.size(num)==1):
-            num = num*np.ones(naxes,dtype=np.int,order='C')
-        elif(np.size(num)!=naxes):
-            raise ValueError(about._errors.cstring("ERROR: size mismatch ( "+str(np.size(num))+" <> "+str(naxes)+" )."))
-        para = np.append(para,num[::-1],axis=None)
-        para = np.append(para,2-(bool(hermitian) or bool(purelyreal))-bool(purelyreal),axis=None) ## {0,1,2}
-        if(np.isscalar(zerocenter)):
-            zerocenter = bool(zerocenter)*np.ones(naxes,dtype=np.int,order='C')
-        else:
-            zerocenter = np.array(zerocenter,dtype=np.bool)
-            if(np.size(zerocenter)==1):
-                zerocenter = zerocenter*np.ones(naxes,dtype=np.int,order='C')
-            elif(np.size(zerocenter)!=naxes):
-                raise ValueError(about._errors.cstring("ERROR: size mismatch ( "+str(np.size(zerocenter))+" <> "+str(naxes)+" )."))
-        para = np.append(para,zerocenter[::-1]*-1,axis=None) ## -1 XOR 0 (centered XOR not)
-
-        self.para = para
-
-        ## set data type
-        if(not self.para[naxes]):
-            self.datatype = np.float64
-        else:
-            self.datatype = np.complex128
-
-        self.discrete = False
-
-        ## set volume
-        if(dist is None):
-            dist = 1/num.astype(self.datatype)
-        elif(np.isscalar(dist)):
-            dist = self.datatype(dist)*np.ones(naxes,dtype=self.datatype,order='C')
-        else:
-            dist = np.array(dist,dtype=self.datatype)
-            if(np.size(dist)==1):
-                dist = dist*np.ones(naxes,dtype=self.datatype,order='C')
-            if(np.size(dist)!=naxes):
-                raise ValueError(about._errors.cstring("ERROR: size mismatch ( "+str(np.size(dist))+" <> "+str(naxes)+" )."))
-        if(np.any(dist<=0)):
-            raise ValueError(about._errors.cstring("ERROR: nonpositive distance(s)."))
-        self.vol = np.real(dist)[::-1]
-
-        self.fourier = bool(fourier)
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def naxes(self):
-        """
-            Returns the number of axes of the grid.
-
-            Returns
-            -------
-            naxes : int
-                Number of axes of the regular grid.
-        """
-        return (np.size(self.para)-1)//2
-
-    def zerocenter(self):
-        """
-            Returns information on the centering of the axes.
-
-            Returns
-            -------
-            zerocenter : numpy.ndarray
-                Whether the grid is centered on zero for each axis or not.
-        """
-        return self.para[-(np.size(self.para)-1)//2:][::-1].astype(np.bool)
-
-    def dist(self):
-        """
-            Returns the distances between grid points along each axis.
-
-            Returns
-            -------
-            dist : np.ndarray
-                Distances between two grid points on each axis.
-        """
-        return self.vol[::-1]
-
-    def dim(self,split=False):
-        """
-            Computes the dimension of the space, i.e.\  the number of pixels.
-
-            Parameters
-            ----------
-            split : bool, *optional*
-                Whether to return the dimension split up, i.e. the numbers of
-                pixels along each axis, or their product (default: False).
-
-            Returns
-            -------
-            dim : {int, numpy.ndarray}
-                Dimension(s) of the space. If ``split==True``, a
-                one-dimensional array with an entry for each axis is returned.
-        """
-        ## dim = product(n)
-        if(split):
-            return self.para[:(np.size(self.para)-1)//2]
-        else:
-            return np.prod(self.para[:(np.size(self.para)-1)//2],axis=0,dtype=None,out=None)
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def dof(self):
-        """
-            Computes the number of degrees of freedom of the space, i.e.\  the
-            number of grid points multiplied with one or two, depending on
-            complex-valuedness and hermitian symmetry of the fields.
-
-            Returns
-            -------
-            dof : int
-                Number of degrees of freedom of the space.
-        """
-        ## dof ~ dim
-        if(self.para[(np.size(self.para)-1)//2]<2):
-            return np.prod(self.para[:(np.size(self.para)-1)//2],axis=0,dtype=None,out=None)
-        else:
-            return 2*np.prod(self.para[:(np.size(self.para)-1)//2],axis=0,dtype=None,out=None)
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def enforce_power(self,spec,size=None,**kwargs):
-        """
-            Provides a valid power spectrum array from a given object.
-
-            Parameters
-            ----------
-            spec : {float, list, numpy.ndarray, nifty.field, function}
-                Fiducial power spectrum from which a valid power spectrum is to
-                be calculated. Scalars are interpreted as constant power
-                spectra.
-
-            Returns
-            -------
-            spec : numpy.ndarray
-                Valid power spectrum.
-
-            Other parameters
-            ----------------
-            size : int, *optional*
-                Number of bands the power spectrum shall have (default: None).
-            kindex : numpy.ndarray, *optional*
-                Scale of each band.
-            codomain : nifty.space, *optional*
-                A compatible codomain for power indexing (default: None).
-            log : bool, *optional*
-                Flag specifying if the spectral binning is performed on logarithmic
-                scale or not; if set, the number of used bins is set
-                automatically (if not given otherwise); by default no binning
-                is done (default: None).
-            nbin : integer, *optional*
-                Number of used spectral bins; if given `log` is set to ``False``;
-                integers below the minimum of 3 induce an automatic setting;
-                by default no binning is done (default: None).
-            binbounds : {list, array}, *optional*
-                User specific inner boundaries of the bins, which are preferred
-                over the above parameters; by default no binning is done
-                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
-                Lower limit of the uniform distribution if ``random == "uni"``
-                (default: 0).
-
-        """
-        if(size is None)or(callable(spec)):
-            ## explicit kindex
-            kindex = kwargs.get("kindex",None)
-            if(kindex is None):
-                ## quick kindex
-                if(self.fourier)and(not hasattr(self,"power_indices"))and(len(kwargs)==0):
-                    kindex = gp.nklength(gp.nkdict_fast(self.para[:(np.size(self.para)-1)//2],self.vol,fourier=True))
-                ## implicit kindex
-                else:
-                    try:
-                        self.set_power_indices(**kwargs)
-                    except:
-                        codomain = kwargs.get("codomain",self.get_codomain())
-                        codomain.set_power_indices(**kwargs)
-                        kindex = codomain.power_indices.get("kindex")
-                    else:
-                        kindex = self.power_indices.get("kindex")
-            size = len(kindex)
-
-        if(isinstance(spec,field)):
-            spec = spec.val.astype(self.datatype)
-        elif(callable(spec)):
-            try:
-                spec = np.array(spec(kindex),dtype=self.datatype)
-            except:
-                raise TypeError(about._errors.cstring("ERROR: invalid power spectra function.")) ## exception in ``spec(kindex)``
-        elif(np.isscalar(spec)):
-            spec = np.array([spec],dtype=self.datatype)
-        else:
-            spec = np.array(spec,dtype=self.datatype)
-
-        ## drop imaginary part
-        spec = np.real(spec)
-        ## check finiteness
-        if(not np.all(np.isfinite(spec))):
-            about.warnings.cprint("WARNING: infinite value(s).")
-        ## check positivity (excluding null)
-        if(np.any(spec<0)):
-            raise ValueError(about._errors.cstring("ERROR: nonpositive value(s)."))
-        elif(np.any(spec==0)):
-            about.warnings.cprint("WARNING: nonpositive value(s).")
-
-        ## extend
-        if(np.size(spec)==1):
-            spec = spec*np.ones(size,dtype=spec.dtype,order='C')
-        ## size check
-        elif(np.size(spec)<size):
-            raise ValueError(about._errors.cstring("ERROR: size mismatch ( "+str(np.size(spec))+" < "+str(size)+" )."))
-        elif(np.size(spec)>size):
-            about.warnings.cprint("WARNING: power spectrum cut to size ( == "+str(size)+" ).")
-            spec = spec[:size]
-
-        return spec
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def set_power_indices(self,**kwargs):
-        """
-            Sets the (un)indexing objects for spectral indexing internally.
-
-            Parameters
-            ----------
-            log : bool
-                Flag specifying if the binning is performed on logarithmic
-                scale or not; if set, the number of used bins is set
-                automatically (if not given otherwise); by default no binning
-                is done (default: None).
-            nbin : integer
-                Number of used bins; if given `log` is set to ``False``;
-                integers below the minimum of 3 induce an automatic setting;
-                by default no binning is done (default: None).
-            binbounds : {list, array}
-                User specific inner boundaries of the bins, which are preferred
-                over the above parameters; by default no binning is done
-                (default: None).
-
-            Returns
-            -------
-            None
-
-            See Also
-            --------
-            get_power_indices
-
-            Raises
-            ------
-            AttributeError
-                If ``self.fourier == False``.
-            ValueError
-                If the binning leaves one or more bins empty.
-
-        """
-        if(not self.fourier):
-            raise AttributeError(about._errors.cstring("ERROR: power spectra indexing ill-defined."))
-        ## check storage
-        if(hasattr(self,"power_indices")):
-            config = self.power_indices.get("config")
-            ## check configuration
-            redo = False
-            if(config.get("log")!=kwargs.get("log",config.get("log"))):
-                config["log"] = kwargs.get("log")
-                redo = True
-            if(config.get("nbin")!=kwargs.get("nbin",config.get("nbin"))):
-                config["nbin"] = kwargs.get("nbin")
-                redo = True
-            if(np.any(config.get("binbounds")!=kwargs.get("binbounds",config.get("binbounds")))):
-                config["binbounds"] = kwargs.get("binbounds")
-                redo = True
-            if(not redo):
-                return None
-        else:
-            config = {"binbounds":kwargs.get("binbounds",None),"log":kwargs.get("log",None),"nbin":kwargs.get("nbin",None)}
-        ## power indices
-        about.infos.cflush("INFO: setting power indices ...")
-        pindex,kindex,rho = gp.get_power_indices2(self.para[:(np.size(self.para)-1)//2],self.vol,self.para[-((np.size(self.para)-1)//2):].astype(np.bool),fourier=True)
-        ## bin if ...
-        if(config.get("log") is not None)or(config.get("nbin") is not None)or(config.get("binbounds") is not None):
-            pindex,kindex,rho = gp.bin_power_indices(pindex,kindex,rho,**config)
-            ## check binning
-            if(np.any(rho==0)):
-                raise ValueError(about._errors.cstring("ERROR: empty bin(s).")) ## binning too fine
-        ## power undex
-        pundex = np.unique(pindex,return_index=True,return_inverse=False)[1]
-        ## storage
-        self.power_indices = {"config":config,"kindex":kindex,"pindex":pindex,"pundex":pundex,"rho":rho} ## alphabetical
-        about.infos.cprint(" done.")
-        return None
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def enforce_values(self,x,extend=True):
-        """
-            Computes valid field values from a given object, taking care of
-            data types, shape, and symmetry.
-
-            Parameters
-            ----------
-            x : {float, numpy.ndarray, nifty.field}
-                Object to be transformed into an array of valid field values.
-
-            Returns
-            -------
-            x : numpy.ndarray
-                Array containing the valid field values.
-
-            Other parameters
-            ----------------
-            extend : bool, *optional*
-                Whether a scalar is extented to a constant array or not
-                (default: True).
-        """
-        if(isinstance(x,field)):
-            if(self==x.domain):
-                if(self.datatype is not x.domain.datatype):
-                    raise TypeError(about._errors.cstring("ERROR: inequal data types ( '"+str(np.result_type(self.datatype))+"' <> '"+str(np.result_type(x.domain.datatype))+"' )."))
-                else:
-                    x = np.copy(x.val)
-            else:
-                raise ValueError(about._errors.cstring("ERROR: inequal domains."))
-        else:
-            if(np.size(x)==1):
-                if(extend):
-                    x = self.datatype(x)*np.ones(self.dim(split=True),dtype=self.datatype,order='C')
-                else:
-                    if(np.isscalar(x)):
-                        x = np.array([x],dtype=self.datatype)
-                    else:
-                        x = np.array(x,dtype=self.datatype)
-            else:
-                x = self.enforce_shape(np.array(x,dtype=self.datatype))
-
-        ## hermitianize if ...
-        if(about.hermitianize.status)and(np.size(x)!=1)and(self.para[(np.size(self.para)-1)//2]==1):
-            x = gp.nhermitianize_fast(x,self.para[-((np.size(self.para)-1)//2):].astype(np.bool),special=False)
-
-        ## check finiteness
-        if(not np.all(np.isfinite(x))):
-            about.warnings.cprint("WARNING: infinite value(s).")
-
-        return x
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def get_random_values(self,**kwargs):
-        """
-            Generates random field values according to the specifications given
-            by the parameters, taking into account possible complex-valuedness
-            and hermitian symmetry.
-
-            Returns
-            -------
-            x : numpy.ndarray
-                Valid field values.
-
-            Other parameters
-            ----------------
-            random : string, *optional*
-                Specifies the probability distribution from which the random
-                numbers are to be drawn.
-                Supported distributions are:
-
-                - "pm1" (uniform distribution over {+1,-1} or {+1,+i,-1,-i}
-                - "gau" (normal distribution with zero-mean and a given standard
-                    deviation or variance)
-                - "syn" (synthesizes from a given power spectrum)
-                - "uni" (uniform distribution over [vmin,vmax[)
-
-                (default: None).
-            dev : float, *optional*
-                Standard deviation (default: 1).
-            var : float, *optional*
-                Variance, overriding `dev` if both are specified
-                (default: 1).
-            spec : {scalar, list, numpy.ndarray, nifty.field, function}, *optional*
-                Power spectrum (default: 1).
-            pindex : numpy.ndarray, *optional*
-                Indexing array giving the power spectrum index of each band
-                (default: None).
-            kindex : numpy.ndarray, *optional*
-                Scale of each band (default: None).
-            codomain : nifty.rg_space, *optional*
-                A compatible codomain with power indices (default: None).
-            log : bool, *optional*
-                Flag specifying if the spectral binning is performed on logarithmic
-                scale or not; if set, the number of used bins is set
-                automatically (if not given otherwise); by default no binning
-                is done (default: None).
-            nbin : integer, *optional*
-                Number of used spectral bins; if given `log` is set to ``False``;
-                integers below the minimum of 3 induce an automatic setting;
-                by default no binning is done (default: None).
-            binbounds : {list, array}, *optional*
-                User specific inner boundaries of the bins, which are preferred
-                over the above parameters; by default no binning is done
-                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
-                Lower limit of the uniform distribution if ``random == "uni"``
-                (default: 0).            vmin : float, *optional*
-                Lower limit for a uniform distribution (default: 0).
-            vmax : float, *optional*
-                Upper limit for a uniform distribution (default: 1).
-        """
-        arg = random.arguments(self,**kwargs)
-
-        if(arg is None):
-            return np.zeros(self.dim(split=True),dtype=self.datatype,order='C')
-
-        elif(arg[0]=="pm1"):
-            if(about.hermitianize.status)and(self.para[(np.size(self.para)-1)//2]==1):
-                return gp.random_hermitian_pm1(self.datatype,self.para[-((np.size(self.para)-1)//2):].astype(np.bool),self.dim(split=True)) ## special case
-            else:
-                x = random.pm1(datatype=self.datatype,shape=self.dim(split=True))
-
-        elif(arg[0]=="gau"):
-            x = random.gau(datatype=self.datatype,shape=self.dim(split=True),mean=None,dev=arg[2],var=arg[3])
-
-        elif(arg[0]=="syn"):
-            naxes = (np.size(self.para)-1)//2
-            x = gp.draw_vector_nd(self.para[:naxes],self.vol,arg[1],symtype=self.para[naxes],fourier=self.fourier,zerocentered=self.para[-naxes:].astype(np.bool),kpack=arg[2])
-            ## correct for 'ifft'
-            if(not self.fourier):
-                x = self.calc_weight(x,power=-1)
-            return x
-
-        elif(arg[0]=="uni"):
-            x = random.uni(datatype=self.datatype,shape=self.dim(split=True),vmin=arg[1],vmax=arg[2])
-
-        else:
-            raise KeyError(about._errors.cstring("ERROR: unsupported random key '"+str(arg[0])+"'."))
-
-        ## hermitianize if ...
-        if(about.hermitianize.status)and(self.para[(np.size(self.para)-1)//2]==1):
-            x = gp.nhermitianize_fast(x,self.para[-((np.size(self.para)-1)//2):].astype(np.bool),special=(arg[0] in ["gau","pm1"]))
-
-        return x
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def check_codomain(self,codomain):
-        """
-            Checks whether a given codomain is compatible to the space or not.
-
-            Parameters
-            ----------
-            codomain : nifty.space
-                Space to be checked for compatibility.
-
-            Returns
-            -------
-            check : bool
-                Whether or not the given codomain is compatible to the space.
-        """
-        if(not isinstance(codomain,space)):
-            raise TypeError(about._errors.cstring("ERROR: invalid input."))
-
-        elif(isinstance(codomain,rg_space)):
-            ##                       naxes==naxes
-            if((np.size(codomain.para)-1)//2==(np.size(self.para)-1)//2):
-                naxes = (np.size(self.para)-1)//2
-                ##                            num'==num
-                if(np.all(codomain.para[:naxes]==self.para[:naxes])):
-                    ##                 typ'==typ             ==2
-                    if(codomain.para[naxes]==self.para[naxes]==2):
-                        ##                                         dist'~=1/(num*dist)
-                        if(np.all(np.absolute(self.para[:naxes]*self.vol*codomain.vol-1)<self.epsilon)):
-                            return True
-                        ##           fourier'==fourier
-                        elif(codomain.fourier==self.fourier):
-                            ##                           dist'~=dist
-                            if(np.all(np.absolute(codomain.vol/self.vol-1)<self.epsilon)):
-                                return True
-                            else:
-                                about.warnings.cprint("WARNING: unrecommended codomain.")
-                    ##   2!=                typ'!=typ             !=2                                             dist'~=1/(num*dist)
-                    elif(2!=codomain.para[naxes]!=self.para[naxes]!=2)and(np.all(np.absolute(self.para[:naxes]*self.vol*codomain.vol-1)<self.epsilon)):
-                        return True
-                    ##                   typ'==typ             !=2
-                    elif(codomain.para[naxes]==self.para[naxes]!=2)and(codomain.fourier==self.fourier):
-                        ##                           dist'~=dist
-                        if(np.all(np.absolute(codomain.vol/self.vol-1)<self.epsilon)):
-                            return True
-                        else:
-                            about.warnings.cprint("WARNING: unrecommended codomain.")
-
-        return False
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def get_codomain(self,coname=None,cozerocenter=None,**kwargs):
-        """
-            Generates a compatible codomain to which transformations are
-            reasonable, i.e.\  either a shifted grid or a Fourier conjugate
-            grid.
-
-            Parameters
-            ----------
-            coname : string, *optional*
-                String specifying a desired codomain (default: None).
-            cozerocenter : {bool, numpy.ndarray}, *optional*
-                Whether or not the grid is zerocentered for each axis or not
-                (default: None).
-
-            Returns
-            -------
-            codomain : nifty.rg_space
-                A compatible codomain.
-
-            Notes
-            -----
-            Possible arguments for `coname` are ``'f'`` in which case the
-            codomain arises from a Fourier transformation, ``'i'`` in which case
-            it arises from an inverse Fourier transformation, and ``'?'`` in
-            which case it arises from a simple shift. If no `coname` is given,
-            the Fourier conjugate grid is produced.
-        """
-        naxes = (np.size(self.para)-1)//2
-        if(cozerocenter is None):
-            cozerocenter = self.para[-naxes:][::-1]
-        elif(np.isscalar(cozerocenter)):
-            cozerocenter = bool(cozerocenter)
-        else:
-            cozerocenter = np.array(cozerocenter,dtype=np.bool)
-            if(np.size(cozerocenter)==1):
-                cozerocenter = np.asscalar(cozerocenter)
-            elif(np.size(cozerocenter)!=naxes):
-                raise ValueError(about._errors.cstring("ERROR: size mismatch ( "+str(np.size(cozerocenter))+" <> "+str(naxes)+" )."))
-
-        if(coname is None):
-            return rg_space(self.para[:naxes][::-1],naxes=naxes,zerocenter=cozerocenter,hermitian=bool(self.para[naxes]<2),purelyreal=bool(self.para[naxes]==1),dist=1/(self.para[:naxes]*self.vol)[::-1],fourier=bool(not self.fourier)) ## dist',fourier' = 1/(num*dist),NOT fourier
-
-        elif(coname[0]=='f'):
-            return rg_space(self.para[:naxes][::-1],naxes=naxes,zerocenter=cozerocenter,hermitian=bool(self.para[naxes]<2),purelyreal=bool(self.para[naxes]==1),dist=1/(self.para[:naxes]*self.vol)[::-1],fourier=True) ## dist',fourier' = 1/(num*dist),True
-
-        elif(coname[0]=='i'):
-            return rg_space(self.para[:naxes][::-1],naxes=naxes,zerocenter=cozerocenter,hermitian=bool(self.para[naxes]<2),purelyreal=bool(self.para[naxes]==1),dist=1/(self.para[:naxes]*self.vol)[::-1],fourier=False) ## dist',fourier' = 1/(num*dist),False
-
-        else:
-            return rg_space(self.para[:naxes][::-1],naxes=naxes,zerocenter=cozerocenter,hermitian=bool(self.para[naxes]<2),purelyreal=bool(not self.para[naxes]),dist=self.vol[::-1],fourier=self.fourier) ## dist',fourier' = dist,fourier
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def get_meta_volume(self,total=False):
-        """
-            Calculates the meta volumes.
-
-            The meta volumes are the volumes associated with each component of
-            a field, taking into account field components that are not
-            explicitly included in the array of field values but are determined
-            by symmetry conditions. In the case of an :py:class:`rg_space`, the
-            meta volumes are simply the pixel volumes.
-
-            Parameters
-            ----------
-            total : bool, *optional*
-                Whether to return the total meta volume of the space or the
-                individual ones of each pixel (default: False).
-
-            Returns
-            -------
-            mol : {numpy.ndarray, float}
-                Meta volume of the pixels or the complete space.
-        """
-        if(total):
-            return self.dim(split=False)*np.prod(self.vol,axis=0,dtype=None,out=None)
-        else:
-            mol = np.ones(self.dim(split=True),dtype=self.vol.dtype,order='C')
-            return self.calc_weight(mol,power=1)
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def calc_weight(self,x,power=1):
-        """
-            Weights a given array with the pixel volumes to a given power.
-
-            Parameters
-            ----------
-            x : numpy.ndarray
-                Array to be weighted.
-            power : float, *optional*
-                Power of the pixel volumes to be used (default: 1).
-
-            Returns
-            -------
-            y : numpy.ndarray
-                Weighted array.
-        """
-        x = self.enforce_shape(np.array(x,dtype=self.datatype))
-        ## weight
-        return x*np.prod(self.vol,axis=0,dtype=None,out=None)**power
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def calc_dot(self,x,y):
-        """
-            Computes the discrete inner product of two given arrays.
-
-            Parameters
-            ----------
-            x : numpy.ndarray
-                First array
-            y : numpy.ndarray
-                Second array
-
-            Returns
-            -------
-            dot : scalar
-                Inner product of the two arrays.
-        """
-        x = self.enforce_shape(np.array(x,dtype=self.datatype))
-        y = self.enforce_shape(np.array(y,dtype=self.datatype))
-        ## inner product
-        dot = np.dot(np.conjugate(x.flatten(order='C')),y.flatten(order='C'),out=None)
-        if(np.isreal(dot)):
-            return np.asscalar(np.real(dot))
-        elif(self.para[(np.size(self.para)-1)//2]!=2):
-                ## check imaginary part
-                if(np.absolute(dot.imag)>self.epsilon**2*np.absolute(dot.real)):
-                    about.warnings.cprint("WARNING: discarding considerable imaginary part.")
-                return np.asscalar(np.real(dot))
-        else:
-            return dot
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def calc_transform(self,x,codomain=None,**kwargs):
-        """
-            Computes the transform of a given array of field values.
-
-            Parameters
-            ----------
-            x : numpy.ndarray
-                Array to be transformed.
-            codomain : nifty.rg_space, *optional*
-                Target space to which the transformation shall map
-                (default: None).
-
-            Returns
-            -------
-            Tx : numpy.ndarray
-                Transformed array
-        """
-        x = self.enforce_shape(np.array(x,dtype=self.datatype))
-
-        if(codomain is None):
-            return x ## T == id
-
-        ## mandatory(!) codomain check
-        if(isinstance(codomain,rg_space))and(self.check_codomain(codomain)):
-            naxes = (np.size(self.para)-1)//2
-            ## select machine
-            if(np.all(np.absolute(self.para[:naxes]*self.vol*codomain.vol-1)<self.epsilon)):
-                if(codomain.fourier):
-                    ftmachine = "fft"
-                    ## correct for 'fft'
-                    x = self.calc_weight(x,power=1)
-                else:
-                    ftmachine = "ifft"
-                    ## correct for 'ifft'
-                    x = self.calc_weight(x,power=1)
-                    x *= self.dim(split=False)
-            else:
-                ftmachine = "none"
-            ## transform
-            if(self.datatype==np.float64):
-                Tx = gf.gfft(x.astype(np.complex128),in_ax=[],out_ax=[],ftmachine=ftmachine,in_zero_center=self.para[-naxes:].astype(np.bool).tolist(),out_zero_center=codomain.para[-naxes:].astype(np.bool).tolist(),enforce_hermitian_symmetry=bool(codomain.para[naxes]==1),W=-1,alpha=-1,verbose=False)
-            else:
-                Tx = gf.gfft(x,in_ax=[],out_ax=[],ftmachine=ftmachine,in_zero_center=self.para[-naxes:].astype(np.bool).tolist(),out_zero_center=codomain.para[-naxes:].astype(np.bool).tolist(),enforce_hermitian_symmetry=bool(codomain.para[naxes]==1),W=-1,alpha=-1,verbose=False)
-            ## check complexity
-            if(not codomain.para[naxes]): ## purely real
-                ## check imaginary part
-                if(np.any(Tx.imag!=0))and(np.dot(Tx.imag.flatten(order='C'),Tx.imag.flatten(order='C'),out=None)>self.epsilon**2*np.dot(Tx.real.flatten(order='C'),Tx.real.flatten(order='C'),out=None)):
-                    about.warnings.cprint("WARNING: discarding considerable imaginary part.")
-                Tx = np.real(Tx)
-
-        else:
-            raise ValueError(about._errors.cstring("ERROR: unsupported transformation."))
-
-        return Tx.astype(codomain.datatype)
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def calc_smooth(self,x,sigma=0,**kwargs):
-        """
-            Smoothes an array of field values by convolution with a Gaussian
-            kernel.
-
-            Parameters
-            ----------
-            x : numpy.ndarray
-                Array of field values to be smoothed.
-            sigma : float, *optional*
-                Standard deviation of the Gaussian kernel, specified in units
-                of length in position space; for testing: a sigma of -1 will be
-                reset to a reasonable value (default: 0).
-
-            Returns
-            -------
-            Gx : numpy.ndarray
-                Smoothed array.
-        """
-        x = self.enforce_shape(np.array(x,dtype=self.datatype))
-        naxes = (np.size(self.para)-1)//2
-
-        ## check sigma
-        if(sigma==0):
-            return x
-        elif(sigma==-1):
-            about.infos.cprint("INFO: invalid sigma reset.")
-            if(self.fourier):
-                sigma = 1.5/np.min(self.para[:naxes]*self.vol) ## sqrt(2)*max(dist)
-            else:
-                sigma = 1.5*np.max(self.vol) ## sqrt(2)*max(dist)
-        elif(sigma<0):
-            raise ValueError(about._errors.cstring("ERROR: invalid sigma."))
-        ## smooth
-        Gx = gs.smooth_field(x,self.fourier,self.para[-naxes:].astype(np.bool).tolist(),bool(self.para[naxes]==1),self.vol,smooth_length=sigma)
-        ## check complexity
-        if(not self.para[naxes]): ## purely real
-            ## check imaginary part
-            if(np.any(Gx.imag!=0))and(np.dot(Gx.imag.flatten(order='C'),Gx.imag.flatten(order='C'),out=None)>self.epsilon**2*np.dot(Gx.real.flatten(order='C'),Gx.real.flatten(order='C'),out=None)):
-                about.warnings.cprint("WARNING: discarding considerable imaginary part.")
-            Gx = np.real(Gx)
-        return Gx
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def calc_power(self,x,**kwargs):
-        """
-            Computes the power of an array of field values.
-
-            Parameters
-            ----------
-            x : numpy.ndarray
-                Array containing the field values of which the power is to be
-                calculated.
-
-            Returns
-            -------
-            spec : numpy.ndarray
-                Power contained in the input array.
-
-            Other parameters
-            ----------------
-            pindex : numpy.ndarray, *optional*
-                Indexing array assigning the input array components to
-                components of the power spectrum (default: None).
-            kindex : numpy.ndarray, *optional*
-                Scale corresponding to each band in the power spectrum
-                (default: None).
-            rho : numpy.ndarray, *optional*
-                Number of degrees of freedom per band (default: None).
-            codomain : nifty.space, *optional*
-                A compatible codomain for power indexing (default: None).
-            log : bool, *optional*
-                Flag specifying if the spectral binning is performed on logarithmic
-                scale or not; if set, the number of used bins is set
-                automatically (if not given otherwise); by default no binning
-                is done (default: None).
-            nbin : integer, *optional*
-                Number of used spectral bins; if given `log` is set to ``False``;
-                integers below the minimum of 3 induce an automatic setting;
-                by default no binning is done (default: None).
-            binbounds : {list, array}, *optional*
-                User specific inner boundaries of the bins, which are preferred
-                over the above parameters; by default no binning is done
-                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
-                Lower limit of the uniform distribution if ``random == "uni"``
-                (default: 0).
-
-        """
-        x = self.enforce_shape(np.array(x,dtype=self.datatype))
-        ## correct for 'fft'
-        if(not self.fourier):
-            x = self.calc_weight(x,power=1)
-        ## explicit power indices
-        pindex,kindex,rho = kwargs.get("pindex",None),kwargs.get("kindex",None),kwargs.get("rho",None)
-        ## implicit power indices
-        if(pindex is None)or(kindex is None)or(rho is None):
-            try:
-                self.set_power_indices(**kwargs)
-            except:
-                codomain = kwargs.get("codomain",self.get_codomain())
-                codomain.set_power_indices(**kwargs)
-                pindex,kindex,rho = codomain.power_indices.get("pindex"),codomain.power_indices.get("kindex"),codomain.power_indices.get("rho")
-            else:
-                pindex,kindex,rho = self.power_indices.get("pindex"),self.power_indices.get("kindex"),self.power_indices.get("rho")
-        ## power spectrum
-        return gp.calc_ps_fast(x,self.para[:(np.size(self.para)-1)//2],self.vol,self.para[-((np.size(self.para)-1)//2):].astype(np.bool),fourier=self.fourier,pindex=pindex,kindex=kindex,rho=rho)
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def get_plot(self,x,title="",vmin=None,vmax=None,power=None,unit="",norm=None,cmap=None,cbar=True,other=None,legend=False,mono=True,**kwargs):
-        """
-            Creates a plot of field values according to the specifications
-            given by the parameters.
-
-            Parameters
-            ----------
-            x : numpy.ndarray
-                Array containing the field values.
-
-            Returns
-            -------
-            None
-
-            Other parameters
-            ----------------
-            title : string, *optional*
-                Title of the plot (default: "").
-            vmin : float, *optional*
-                Minimum value to be displayed (default: ``min(x)``).
-            vmax : float, *optional*
-                Maximum value to be displayed (default: ``max(x)``).
-            power : bool, *optional*
-                Whether to plot the power contained in the field or the field
-                values themselves (default: False).
-            unit : string, *optional*
-                Unit of the field values (default: "").
-            norm : string, *optional*
-                Scaling of the field values before plotting (default: None).
-            cmap : matplotlib.colors.LinearSegmentedColormap, *optional*
-                Color map to be used for two-dimensional plots (default: None).
-            cbar : bool, *optional*
-                Whether to show the color bar or not (default: True).
-            other : {single object, tuple of objects}, *optional*
-                Object or tuple of objects to be added, where objects can be
-                scalars, arrays, or fields (default: None).
-            legend : bool, *optional*
-                Whether to show the legend or not (default: False).
-            mono : bool, *optional*
-                Whether to plot the monopole or not (default: True).
-            save : string, *optional*
-                Valid file name where the figure is to be stored, by default
-                the figure is not saved (default: False).
-            error : {float, numpy.ndarray, nifty.field}, *optional*
-                Object indicating some confidence interval to be plotted
-                (default: None).
-            kindex : numpy.ndarray, *optional*
-                Scale corresponding to each band in the power spectrum
-                (default: None).
-            codomain : nifty.space, *optional*
-                A compatible codomain for power indexing (default: None).
-            log : bool, *optional*
-                Flag specifying if the spectral binning is performed on logarithmic
-                scale or not; if set, the number of used bins is set
-                automatically (if not given otherwise); by default no binning
-                is done (default: None).
-            nbin : integer, *optional*
-                Number of used spectral bins; if given `log` is set to ``False``;
-                integers below the minimum of 3 induce an automatic setting;
-                by default no binning is done (default: None).
-            binbounds : {list, array}, *optional*
-                User specific inner boundaries of the bins, which are preferred
-                over the above parameters; by default no binning is done
-                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
-                Lower limit of the uniform distribution if ``random == "uni"``
-                (default: 0).
-
-        """
-        if(not pl.isinteractive())and(not bool(kwargs.get("save",False))):
-            about.warnings.cprint("WARNING: interactive mode off.")
-
-        naxes = (np.size(self.para)-1)//2
-        if(power is None):
-            power = bool(self.para[naxes])
-
-        if(power):
-            x = self.calc_power(x,**kwargs)
-
-            fig = pl.figure(num=None,figsize=(6.4,4.8),dpi=None,facecolor="none",edgecolor="none",frameon=False,FigureClass=pl.Figure)
-            ax0 = fig.add_axes([0.12,0.12,0.82,0.76])
-
-            ## explicit kindex
-            xaxes = kwargs.get("kindex",None)
-            ## implicit kindex
-            if(xaxes is None):
-                try:
-                    self.set_power_indices(**kwargs)
-                except:
-                    codomain = kwargs.get("codomain",self.get_codomain())
-                    codomain.set_power_indices(**kwargs)
-                    xaxes = codomain.power_indices.get("kindex")
-                else:
-                    xaxes = self.power_indices.get("kindex")
-
-            if(norm is None)or(not isinstance(norm,int)):
-                norm = naxes
-            if(vmin is None):
-                vmin = np.min(x[:mono].tolist()+(xaxes**norm*x)[1:].tolist(),axis=None,out=None)
-            if(vmax is None):
-                vmax = np.max(x[:mono].tolist()+(xaxes**norm*x)[1:].tolist(),axis=None,out=None)
-            ax0.loglog(xaxes[1:],(xaxes**norm*x)[1:],color=[0.0,0.5,0.0],label="graph 0",linestyle='-',linewidth=2.0,zorder=1)
-            if(mono):
-                ax0.scatter(0.5*(xaxes[1]+xaxes[2]),x[0],s=20,color=[0.0,0.5,0.0],marker='o',cmap=None,norm=None,vmin=None,vmax=None,alpha=None,linewidths=None,verts=None,zorder=1)
-
-            if(other is not None):
-                if(isinstance(other,tuple)):
-                    other = list(other)
-                    for ii in xrange(len(other)):
-                        if(isinstance(other[ii],field)):
-                            other[ii] = other[ii].power(**kwargs)
-                        else:
-                            other[ii] = self.enforce_power(other[ii],size=np.size(xaxes),kindex=xaxes)
-                elif(isinstance(other,field)):
-                    other = [other.power(**kwargs)]
-                else:
-                    other = [self.enforce_power(other,size=np.size(xaxes),kindex=xaxes)]
-                imax = max(1,len(other)-1)
-                for ii in xrange(len(other)):
-                    ax0.loglog(xaxes[1:],(xaxes**norm*other[ii])[1:],color=[max(0.0,1.0-(2*ii/imax)**2),0.5*((2*ii-imax)/imax)**2,max(0.0,1.0-(2*(ii-imax)/imax)**2)],label="graph "+str(ii+1),linestyle='-',linewidth=1.0,zorder=-ii)
-                    if(mono):
-                        ax0.scatter(0.5*(xaxes[1]+xaxes[2]),other[ii][0],s=20,color=[max(0.0,1.0-(2*ii/imax)**2),0.5*((2*ii-imax)/imax)**2,max(0.0,1.0-(2*(ii-imax)/imax)**2)],marker='o',cmap=None,norm=None,vmin=None,vmax=None,alpha=None,linewidths=None,verts=None,zorder=-ii)
-                if(legend):
-                    ax0.legend()
-
-            ax0.set_xlim(xaxes[1],xaxes[-1])
-            ax0.set_xlabel(r"$|k|$")
-            ax0.set_ylim(vmin,vmax)
-            ax0.set_ylabel(r"$|k|^{%i} P_k$"%norm)
-            ax0.set_title(title)
-
-        else:
-            x = self.enforce_shape(np.array(x))
-
-            if(naxes==1):
-                fig = pl.figure(num=None,figsize=(6.4,4.8),dpi=None,facecolor="none",edgecolor="none",frameon=False,FigureClass=pl.Figure)
-                ax0 = fig.add_axes([0.12,0.12,0.82,0.76])
-
-                xaxes = (np.arange(self.para[0],dtype=np.int)+self.para[2]*(self.para[0]//2))*self.vol
-                if(vmin is None):
-                    if(np.iscomplexobj(x)):
-                        vmin = min(np.min(np.absolute(x),axis=None,out=None),np.min(np.real(x),axis=None,out=None),np.min(np.imag(x),axis=None,out=None))
-                    else:
-                        vmin = np.min(x,axis=None,out=None)
-                if(vmax is None):
-                    if(np.iscomplexobj(x)):
-                        vmax = max(np.max(np.absolute(x),axis=None,out=None),np.max(np.real(x),axis=None,out=None),np.max(np.imag(x),axis=None,out=None))
-                    else:
-                        vmax = np.max(x,axis=None,out=None)
-                if(norm=="log"):
-                    ax0graph = ax0.semilogy
-                    if(vmin<=0):
-                        raise ValueError(about._errors.cstring("ERROR: nonpositive value(s)."))
-                else:
-                    ax0graph = ax0.plot
-
-                if(np.iscomplexobj(x)):
-                    ax0graph(xaxes,np.absolute(x),color=[0.0,0.5,0.0],label="graph (absolute)",linestyle='-',linewidth=2.0,zorder=1)
-                    ax0graph(xaxes,np.real(x),color=[0.0,0.5,0.0],label="graph (real part)",linestyle="--",linewidth=1.0,zorder=0)
-                    ax0graph(xaxes,np.imag(x),color=[0.0,0.5,0.0],label="graph (imaginary part)",linestyle=':',linewidth=1.0,zorder=0)
-                    if(legend):
-                        ax0.legend()
-                elif(other is not None):
-                    ax0graph(xaxes,x,color=[0.0,0.5,0.0],label="graph 0",linestyle='-',linewidth=2.0,zorder=1)
-                    if(isinstance(other,tuple)):
-                        other = [self.enforce_values(xx,extend=True) for xx in other]
-                    else:
-                        other = [self.enforce_values(other,extend=True)]
-                    imax = max(1,len(other)-1)
-                    for ii in xrange(len(other)):
-                        ax0graph(xaxes,other[ii],color=[max(0.0,1.0-(2*ii/imax)**2),0.5*((2*ii-imax)/imax)**2,max(0.0,1.0-(2*(ii-imax)/imax)**2)],label="graph "+str(ii+1),linestyle='-',linewidth=1.0,zorder=-ii)
-                    if("error" in kwargs):
-                        error = self.enforce_values(np.absolute(kwargs.get("error")),extend=True)
-                        ax0.fill_between(xaxes,x-error,x+error,color=[0.8,0.8,0.8],label="error 0",zorder=-len(other))
-                    if(legend):
-                        ax0.legend()
-                else:
-                    ax0graph(xaxes,x,color=[0.0,0.5,0.0],label="graph 0",linestyle='-',linewidth=2.0,zorder=1)
-                    if("error" in kwargs):
-                        error = self.enforce_values(np.absolute(kwargs.get("error")),extend=True)
-                        ax0.fill_between(xaxes,x-error,x+error,color=[0.8,0.8,0.8],label="error 0",zorder=0)
-
-                ax0.set_xlim(xaxes[0],xaxes[-1])
-                ax0.set_xlabel("coordinate")
-                ax0.set_ylim(vmin,vmax)
-                if(unit):
-                    unit = " ["+unit+"]"
-                ax0.set_ylabel("values"+unit)
-                ax0.set_title(title)
-
-            elif(naxes==2):
-                if(np.iscomplexobj(x)):
-                    about.infos.cprint("INFO: absolute values and phases are plotted.")
-                    if(title):
-                        title += " "
-                    if(bool(kwargs.get("save",False))):
-                        save_ = os.path.splitext(os.path.basename(str(kwargs.get("save"))))
-                        kwargs.update(save=save_[0]+"_absolute"+save_[1])
-                    self.get_plot(np.absolute(x),title=title+"(absolute)",vmin=vmin,vmax=vmax,power=False,unit=unit,norm=norm,cmap=cmap,cbar=cbar,other=None,legend=False,**kwargs)
-#                    self.get_plot(np.real(x),title=title+"(real part)",vmin=vmin,vmax=vmax,power=False,unit=unit,norm=norm,cmap=cmap,cbar=cbar,other=None,legend=False,**kwargs)
-#                    self.get_plot(np.imag(x),title=title+"(imaginary part)",vmin=vmin,vmax=vmax,power=False,unit=unit,norm=norm,cmap=cmap,cbar=cbar,other=None,legend=False,**kwargs)
-                    if(unit):
-                        unit = "rad"
-                    if(cmap is None):
-                        cmap = pl.cm.hsv_r
-                    if(bool(kwargs.get("save",False))):
-                        kwargs.update(save=save_[0]+"_phase"+save_[1])
-                    self.get_plot(np.angle(x,deg=False),title=title+"(phase)",vmin=-3.1416,vmax=3.1416,power=False,unit=unit,norm=None,cmap=cmap,cbar=cbar,other=None,legend=False,**kwargs) ## values in [-pi,pi]
-                    return None ## leave method
-                else:
-                    if(vmin is None):
-                        vmin = np.min(x,axis=None,out=None)
-                    if(vmax is None):
-                        vmax = np.max(x,axis=None,out=None)
-                    if(norm=="log")and(vmin<=0):
-                        raise ValueError(about._errors.cstring("ERROR: nonpositive value(s)."))
-
-                    s_ = np.array([self.para[1]*self.vol[1]/np.max(self.para[:naxes]*self.vol,axis=None,out=None),self.para[0]*self.vol[0]/np.max(self.para[:naxes]*self.vol,axis=None,out=None)*(1.0+0.159*bool(cbar))])
-                    fig = pl.figure(num=None,figsize=(6.4*s_[0],6.4*s_[1]),dpi=None,facecolor="none",edgecolor="none",frameon=False,FigureClass=pl.Figure)
-                    ax0 = fig.add_axes([0.06/s_[0],0.06/s_[1],1.0-0.12/s_[0],1.0-0.12/s_[1]])
-
-                    xaxes = (np.arange(self.para[1]+1,dtype=np.int)-0.5+self.para[4]*(self.para[1]//2))*self.vol[1]
-                    yaxes = (np.arange(self.para[0]+1,dtype=np.int)-0.5+self.para[3]*(self.para[0]//2))*self.vol[0]
-                    if(norm=="log"):
-                        n_ = ln(vmin=vmin,vmax=vmax)
-                    else:
-                        n_ = None
-                    sub = ax0.pcolormesh(xaxes,yaxes,x,cmap=cmap,norm=n_,vmin=vmin,vmax=vmax)
-                    ax0.set_xlim(xaxes[0],xaxes[-1])
-                    ax0.set_xticks([0],minor=False)
-                    ax0.set_ylim(yaxes[0],yaxes[-1])
-                    ax0.set_yticks([0],minor=False)
-                    ax0.set_aspect("equal")
-                    if(cbar):
-                        if(norm=="log"):
-                            f_ = lf(10,labelOnlyBase=False)
-                            b_ = sub.norm.inverse(np.linspace(0,1,sub.cmap.N+1))
-                            v_ = np.linspace(sub.norm.vmin,sub.norm.vmax,sub.cmap.N)
-                        else:
-                            f_ = None
-                            b_ = None
-                            v_ = None
-                        cb0 = fig.colorbar(sub,ax=ax0,orientation="horizontal",fraction=0.1,pad=0.05,shrink=0.75,aspect=20,ticks=[vmin,vmax],format=f_,drawedges=False,boundaries=b_,values=v_)
-                        cb0.ax.text(0.5,-1.0,unit,fontdict=None,withdash=False,transform=cb0.ax.transAxes,horizontalalignment="center",verticalalignment="center")
-                    ax0.set_title(title)
-
-            else:
-                raise ValueError(about._errors.cstring("ERROR: unsupported number of axes ( "+str(naxes)+" > 2 )."))
-
-        if(bool(kwargs.get("save",False))):
-            fig.savefig(str(kwargs.get("save")),dpi=None,facecolor="none",edgecolor="none",orientation="portrait",papertype=None,format=None,transparent=False,bbox_inches=None,pad_inches=0.1)
-            pl.close(fig)
-        else:
-            fig.canvas.draw()
-
-    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-    def __repr__(self):
-        return "<nifty_core.rg_space>"
-
-    def __str__(self):
-        naxes = (np.size(self.para)-1)//2
-        num = self.para[:naxes][::-1].tolist()
-        zerocenter = self.para[-naxes:][::-1].astype(np.bool).tolist()
-        dist = self.vol[::-1].tolist()
-        return "nifty_core.rg_space instance\n- num        = "+str(num)+"\n- naxes      = "+str(naxes)+"\n- hermitian  = "+str(bool(self.para[naxes]<2))+"\n- purelyreal = "+str(bool(not self.para[naxes]))+"\n- zerocenter = "+str(zerocenter)+"\n- dist       = "+str(dist)+"\n- fourier    = "+str(self.fourier)
-
-##-----------------------------------------------------------------------------
-
-
-
 ##-----------------------------------------------------------------------------
 
 class lm_space(space):
diff --git a/rg/__init__.py b/rg/__init__.py
new file mode 100644
index 000000000..36dfae639
--- /dev/null
+++ b/rg/__init__.py
@@ -0,0 +1,24 @@
+## NIFTY (Numerical Information Field Theory) has been developed at the
+## Max-Planck-Institute for Astrophysics.
+##
+## Copyright (C) 2015 Max-Planck-Society
+##
+## Author: Marco Selig
+## Project homepage: <http://www.mpa-garching.mpg.de/ift/nifty/>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+## See the GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import division
+from nifty_rg import *
+
diff --git a/rg/gfft_rg.py b/rg/gfft_rg.py
new file mode 100644
index 000000000..49c62781c
--- /dev/null
+++ b/rg/gfft_rg.py
@@ -0,0 +1,454 @@
+## NIFTY (Numerical Information Field Theory) has been developed at the
+## Max-Planck-Institute for Astrophysics.
+##
+## Copyright (C) 2015 Max-Planck-Society
+##
+## Author: Michael Bell, Henrik Junklewitz, Marco Selig
+## Project homepage: <http://www.mpa-garching.mpg.de/ift/nifty/>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+## See the GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+## This is a "plain" version of gfft.py that was originally created as part of
+## GFFT v0.1.0 by Michael Bell and Henrik Junklewitz.
+
+import numpy as np
+import warnings
+
+
+def gfft(inp, in_ax=[], out_ax=[], ftmachine='fft', in_zero_center=True, \
+    out_zero_center=True, enforce_hermitian_symmetry=False, W=6, alpha=1.5,\
+    verbose=True):
+
+    """
+    gfft (Generalized FFT)
+
+
+    def gfft(inp, in_ax=[], out_ax=[], ftmachine='fft', in_zero_center=True, \
+        out_zero_center=True, out_is_real=False, W=6, alpha=1.5)
+
+    This is a generalized Fourier transformation function that can transform
+    between regularly- or irregularly-spaced, 1- 2- or 3-D fields. Gridding and
+    degridding is performed when irregularly spaced fields are requested.
+
+    input
+    ------------------
+    inp: The input data to be transformed. This can be a 1-, 2- or 3-D
+        (henceforth N-D) numpy array.
+
+    in_ax, out_ax: The axes on which the input/output arrays are defined. There
+        are a few options here depending on the types of fields that are to be
+        transformed:
+
+        To go from regularly spaced input to regularly spaced output: in can be
+            an N-D array, leave in_ax and out_ax blank. No gridding is
+            performed, it just does an fft or ifft directly.
+
+        To go from irregularly spaced input to regularly spaced output: in must
+            be a list of 1-D arrays, in_ax = [N*array([...])] and
+            out_ax = [N*(dx, nx)]. So in_ax is a length N list of numpy arrays
+            (each of length len(in)) that contain the coordinates for which the
+            input data are defined. out_ax is a length N list of tuples
+            containing the number of pixels and size of the pixels in the
+            regularly spaced N-D out array. Gridding is performed on the input
+            data before performing the fft or ifft.
+
+        To go from regularly spaced input to irregularly spaced output: same as
+            above except in_ax and out_ax are reversed. out will always be a 1D
+            array. De-gridding is performed.
+
+        To go from irregularly spaced input to irregularly spaced output: This
+            gets a bit tricky. In this case either in_ax or out_ax =
+            ([N x array([...])], [N x (dx, nx)]) **this is a tuple** and the
+            other is just [N x array([...])] as before. In this mode, the code
+            grids in, Fourier transforms, then degrids onto the coordinates
+            given in out_ax. The N tuples of (nx,dx) are necessary because a
+            grid must be defined in the middle even though neither the input or
+            output arrays live on a grid. The grid can be defined either for the
+            input or output space (which is why either in_ax or out_ax can be
+            given as a tuple).
+
+    ftmachine: a length N list of strings, with each entry containing either
+        'fft' or 'ifft'. This defines whether an FFT or and IFFT should be
+        performed for each axis. So, if you have a 3D dataset and you want to do
+        an FFT on the first two axes, but an IFFT on the last, you would pass
+        ftmachine=['fft', 'fft', 'ifft']. In principle, we could also make DFTs
+        an option here, and the code would just do a DFT rather than gridding.
+        For an N-D input array, one could also just use ftmachine='fft' and it
+        would do an fft for all axes.
+
+        For now, options include: 'fft', 'ifft', and 'none'.
+
+    in_zero_center/out_zero_center: a length N list of booleans. True indicates
+        that the zero frequency is in (or should be in) the central pixel, false
+        indicates that it is in pixel 0. Basically this indicates whether
+        fftshifts should be performed before and after Fourier transforming. For
+        an N-D array, in_zero_center=T would indicate that all axes should have
+        the zero channel in the central pixel.
+
+    W, alpha: These are gridding parameters.
+
+    enforce_hermitian_symmetry: A length N list of booleans. If the in array is
+        to be gridded, setting this to 'True' indicates that the Hermitian
+        conjugate of the input array needs to be generated during gridding.
+        This can be set for each axis independently. This is ignored when going
+        from a regular grid to another regular grid.
+
+
+    output
+    ------------------
+    out: A numpy array that contains the FT or IFT of inp.
+
+    """
+
+    VERSION = "0.2.1"
+
+    if verbose:
+        print "gfft v. "+VERSION
+
+    ############################################################################
+    # Set some global variables
+
+    # different modes of operation
+    MODE_RR = 0 # regular grid to regular grid
+    MODE_IR = 1 # irregular grid to regular grid
+    MODE_RI = 2 # regular grid to irregular grid
+    MODE_II = 3 # irregular grid to irregular grid
+
+    mode_types = {MODE_RR:"regular to regular (no gridding)", \
+        MODE_IR:"irregular to regular (gridding)", \
+        MODE_RI:"regular to irregular (de-gridding)", \
+        MODE_II:"irregular to irregular (gridding and degridding)"}
+
+    # Different ftmachine options
+    FTM_FFT = 'fft'
+    FTM_IFFT = 'ifft'
+#    FTM_NONE = 'none'
+
+    ############################################################################
+    # Validate the inputs...
+
+    if type(inp) != np.ndarray:
+        raise TypeError('inp must be a numpy array.')
+
+    if type(in_ax) != list and type(in_ax) != tuple:
+        raise TypeError('in_ax must be either a list or a tuple.')
+    if type(out_ax) != list and type(out_ax) != tuple:
+        raise TypeError('out_ax must be either a list or a tuple.')
+    if type(out_ax) == tuple and type(in_ax) == tuple:
+        raise TypeError('out_ax and in_ax cannot both be tuples')
+
+    if type(in_ax) == tuple and (not validate_iterrable_types(in_ax, list)\
+        or len(in_ax) != 2):
+            raise TypeError('If in_ax is a tuple, it must contain two lists.')
+    if type(out_ax) == tuple and (not validate_iterrable_types(out_ax, list)\
+        or len(out_ax) != 2):
+            raise TypeError('If out_ax is a tuple, it must contain two lists.')
+
+    if type(in_ax) == tuple and \
+        not validate_iterrable_types(in_ax[0], np.ndarray):
+            raise TypeError('If in_ax is a tuple, it must contain two lists,' +\
+                ' the first of which is a list of arrays.')
+    if type(in_ax) == tuple and \
+        not validate_iterrable_types(in_ax[1], tuple):
+            raise TypeError('If in_ax is a tuple, it must contain two lists,' +\
+                ' the second of which is a list of tuples.')
+
+    if type(out_ax) == tuple and \
+        not validate_iterrable_types(out_ax[0], np.ndarray):
+            raise TypeError('If out_ax is a tuple, it must contain two lists,'+\
+                ' the first of which is a list of arrays.')
+    if type(out_ax) == tuple and \
+        not validate_iterrable_types(out_ax[1], tuple):
+            raise TypeError('If out_ax is a tuple, it must contain two lists,'+\
+                ' the second of which is a list of tuples.')
+
+    if type(W) != int:
+        raise TypeError('W must be an integer.')
+    if type(alpha) != float and type(alpha) != int:
+        raise TypeError('alpha must be a float or int.')
+
+    if (type(ftmachine) != str and type(ftmachine) != list) or \
+        (type(ftmachine) == list and \
+        not validate_iterrable_types(ftmachine, str)):
+            raise TypeError('ftmachine must be a string or a list of strings.')
+
+    if (type(in_zero_center) != bool and type(in_zero_center) != list) or \
+        (type(in_zero_center) == list and \
+        not validate_iterrable_types(in_zero_center, bool)):
+            raise TypeError('in_zero_center must be a Bool or list of Bools.')
+
+    if (type(out_zero_center) != bool and type(out_zero_center) != list) or \
+        (type(out_zero_center) == list and \
+        not validate_iterrable_types(out_zero_center, bool)):
+            raise TypeError('out_zero_center must be a Bool or list of Bools.')
+
+    if (type(enforce_hermitian_symmetry) != bool and \
+        type(enforce_hermitian_symmetry) != list) or \
+        (type(enforce_hermitian_symmetry) == list and \
+        not validate_iterrable_types(enforce_hermitian_symmetry, bool)):
+            raise TypeError('enforce_hermitian_symmetry must be a Bool '\
+                +'or list of Bools.')
+
+
+    ############################################################################
+    # figure out how many dimensions we are talking about, and what mode we
+    # want to use
+
+    N = 0 # number of dimensions
+    mode = -1
+
+    if len(in_ax) == 0:
+        # regular to regular transformation
+        mode = MODE_RR
+        N = inp.ndim
+        if len(out_ax) != 0:
+            warnings.warn('in_ax is empty, indicating regular to regular '\
+                +'transformation is requested, but out_ax is not empty. '+\
+                'Ignoring out_ax and proceeding with regular to regular mode.')
+    elif type(in_ax)==tuple or type(out_ax)==tuple:
+        # irregular to irregular transformation
+        mode = MODE_II
+        if type(out_ax)==tuple:
+            if len(out_ax) != 2:
+                raise TypeError('Invalid out_ax for '+\
+                    'irregular to irregular mode.')
+            N = len(in_ax)
+        else:
+            if len(in_ax) != 2:
+                raise TypeError('Invalid in_ax for '+\
+                    'irregular to irregular mode.')
+            N = len(out_ax)
+    else:
+        if type(in_ax[0])==tuple:
+            # regular to irregular transformation
+            mode = MODE_RI
+        else:
+            # irregular to regular transformation
+            mode = MODE_IR
+        N = len(in_ax)
+        if len(out_ax) != len(in_ax):
+            raise TypeError('For regular to irregular mode, len(in_ax) must '+\
+                'equal len(out_ax).')
+
+    if N==0 or mode == -1:
+        raise Exception('Something went wrong in setting the mode and ' \
+            + 'dimensionality.')
+
+    if N > 3 and mode != MODE_RR:
+        raise Exception('Gridding has been requested for an unsupported '+\
+            'number of dimensions!')
+
+    if verbose:
+        print 'Requested mode = ' + mode_types[mode]
+        print "Number of dimensions = " + str(N)
+
+    ############################################################################
+    # Figure out which axes should have which transforms applied to them
+
+    # flags to determine whether I need to use fftn and/or ifftn
+    do_fft = False
+    do_ifft = False
+    # if you give an empty list to fftn in the axes position, nothing happens
+    fftaxes = []
+    ifftaxes = []
+
+    if type(ftmachine) == str:
+        if ftmachine.lower() == FTM_FFT:
+            do_fft = True
+            fftaxes = None
+        elif ftmachine.lower() == FTM_IFFT:
+            do_ifft = True
+            ifftaxes = None
+    elif type(ftmachine) == list:
+        if len(ftmachine) != N:
+            raise Exception('ftmachine is a list with invalid length')
+
+        for i in range(len(ftmachine)):
+            if ftmachine[i].lower() == FTM_FFT:
+                do_fft = True
+                fftaxes += [i]
+            elif ftmachine[i].lower() == FTM_IFFT:
+                do_ifft = True
+                ifftaxes += [i]
+
+    if (do_fft == False and do_ifft == False) or \
+        (fftaxes == [] and ifftaxes == []):
+#            warnings.warn('No Fourier transformation requested, only '+\
+#                'shifting will be performed!')
+            if verbose:
+                print "No Fourier transformation requested, only "+\
+                    "shifting will be performed!"
+            mode = MODE_RR #Since gridding will not be needed, just use RR mode
+
+    ############################################################################
+    # figure out which axes need to be shifted (before and after FT)
+
+    do_preshift = False
+    do_postshift = False
+
+    preshift_axes = []
+    postshift_axes = []
+
+    if type(in_zero_center) == bool:
+        if in_zero_center:
+            do_preshift = True
+            preshift_axes = None
+    elif type(in_zero_center) == list:
+        if len(in_zero_center) != N:
+            raise Exception('in_zero_center is a list with invalid length')
+
+        for i in range(len(in_zero_center)):
+            if in_zero_center[i]:
+                do_preshift = True
+                preshift_axes += [i]
+
+    if type(out_zero_center) == bool:
+        if out_zero_center:
+            do_postshift = True
+            postshift_axes = None
+    elif type(out_zero_center) == list:
+        if len(out_zero_center) != N:
+            raise Exception('out_zero_center is a list with invalid length')
+
+        for i in range(len(out_zero_center)):
+            if out_zero_center[i]:
+                do_postshift = True
+                postshift_axes += [i]
+
+    ############################################################################
+    # figure out which axes need to be hermitianized
+
+    hermitianized_axes = []
+
+    if type(enforce_hermitian_symmetry) == bool:
+        if enforce_hermitian_symmetry:
+            for i in range(N):
+                hermitianized_axes += [True]
+        else:
+            for i in range(N):
+                hermitianized_axes += [False]
+
+    elif type(enforce_hermitian_symmetry) == list:
+        if len(enforce_hermitian_symmetry) != N:
+            raise Exception('enforce_hermitian_symmetry is a list with '+\
+                'invalid length')
+
+        for i in range(len(enforce_hermitian_symmetry)):
+            if enforce_hermitian_symmetry[i]:
+                hermitianized_axes += [True]
+            else:
+                hermitianized_axes += [False]
+
+    if len(hermitianized_axes) != N:
+        raise Exception('Something went wrong when setting up the '+\
+            'hermitianized_axes list!')
+
+    ############################################################################
+    # Print operation summary
+
+    if verbose:
+        print ""
+        print "Axis#, FFT, IFFT, ZCIN, ZCOUT, HERM"
+
+        for i in range(N):
+            pstr = str(N)+', '
+
+            if fftaxes == None or fftaxes.count(i)>0:
+                pstr = pstr + 'True, '
+            else:
+                pstr = pstr + 'False, '
+
+            if ifftaxes == None or ifftaxes.count(i)>0:
+                pstr = pstr + 'True, '
+            else:
+                pstr = pstr + 'False, '
+
+            if preshift_axes == None or preshift_axes.count(i)>0:
+                pstr = pstr + 'True, '
+            else:
+                pstr = pstr + 'False, '
+
+            if postshift_axes == None or postshift_axes.count(i)>0:
+                pstr = pstr + 'True, '
+            else:
+                pstr = pstr + 'False, '
+
+            if hermitianized_axes[i]:
+                pstr = pstr + 'True'
+            else:
+                pstr = pstr + 'False'
+
+        print pstr
+
+    ############################################################################
+    # Do MODE_RR transform
+
+    if mode == MODE_RR:
+
+        if do_preshift:
+            inp = np.fft.fftshift(inp, axes=preshift_axes)
+
+        if do_fft:
+            out = np.fft.fftn(inp, axes=fftaxes)
+        else:
+            out = inp.copy()
+
+        if do_ifft:
+            out = np.fft.ifftn(out, axes=ifftaxes)
+
+        if do_postshift:
+            out = np.fft.fftshift(out, axes=postshift_axes)
+
+        if verbose:
+            print "Done!"
+            print ""
+
+        return out
+
+    ############################################################################
+    # Do MODE_IR transform
+
+    elif mode == MODE_IR:
+
+        raise NotImplementedError('Mode irregular-to-regular is not part of this "plain" GFFT version.')
+
+    ############################################################################
+    # Do MODE_RI transform
+
+    elif mode == MODE_RI:
+
+        raise NotImplementedError('Mode regular-to-irregular is not part of this "plain" GFFT version.')
+
+    ############################################################################
+    # Do MODE_II transform
+
+    elif mode == MODE_II:
+
+        raise NotImplementedError('Mode irregular-to-irregular is not part of this "plain" GFFT version.')
+
+
+def validate_iterrable_types(l, t):
+    """
+    Used to check whether the types of the items within the list or tuple l are
+    of the type t. Returns True if all items are of type t, False otherwise.
+    """
+
+    is_valid = True
+
+    for i in range(len(l)):
+        if type(l[i]) != t:
+            is_valid = False
+
+    return is_valid
+
diff --git a/rg/nifty_power_conversion_rg.py b/rg/nifty_power_conversion_rg.py
new file mode 100644
index 000000000..2e34ae1f2
--- /dev/null
+++ b/rg/nifty_power_conversion_rg.py
@@ -0,0 +1,155 @@
+## NIFTY (Numerical Information Field Theory) has been developed at the
+## Max-Planck-Institute for Astrophysics.
+##
+## Copyright (C) 2014 Max-Planck-Society
+##
+## Author: Maksim Greiner, Marco Selig
+## Project homepage: <http://www.mpa-garching.mpg.de/ift/nifty/>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+## See the GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#from nifty import *
+import numpy as np
+from nifty import about,                                                     \
+                  field,                                                     \
+                  sqrt,exp,log,                                              \
+                  power_operator
+
+
+def power_backward_conversion_rg(k_space,p,mean=None,bare=True):
+    """
+        This function is designed to convert a theoretical/statistical power
+        spectrum of a log-normal field to the theoretical power spectrum of
+        the underlying Gaussian field.
+        The function only works for power spectra defined for rg_spaces
+
+        Parameters
+        ----------
+        k_space : nifty.rg_space,
+            a regular grid space with the attribute `Fourier = True`
+        p : np.array,
+            the power spectrum of the log-normal field.
+            Needs to have the same number of entries as
+            `k_space.get_power_indices()[0]`
+        mean : float, *optional*
+            specifies the mean of the log-normal field. If `mean` is not
+            specified the function will use the monopole of the power spectrum.
+            If it is specified the function will NOT use the monopole of the
+            spectrum (default: None).
+            WARNING: a mean that is too low can violate positive definiteness
+            of the log-normal field. In this case the function produces an
+            error.
+        bare : bool, *optional*
+            whether `p` is the bare power spectrum or not (default: True).
+
+        Returns
+        -------
+        mean : float,
+            the recovered mean of the underlying Gaussian distribution.
+        p1 : np.array,
+            the power spectrum of the underlying Gaussian field, where the
+            monopole has been set to zero. Eventual monopole power has been
+            shifted to the mean.
+
+        References
+        ----------
+        .. [#] M. Greiner and T.A. Ensslin, "Log-transforming the matter power spectrum";
+            `arXiv:1312.1354 <http://arxiv.org/abs/1312.1354>`_
+    """
+    pindex = k_space.get_power_indices()[2]
+    V = k_space.vol.prod()**(-1)
+
+    mono_ind = np.where(pindex==0)
+
+    spec = power_operator(k_space,spec=p,bare=bare).get_power(bare=False)
+
+    if(mean is None):
+        mean = 0.
+    else:
+        spec[0] = 0.
+
+    pf = field(k_space,val=spec[pindex]).transform()+mean**2
+
+    if(np.any(pf.val<0.)):
+        raise ValueError(about._errors.cstring("ERROR: spectrum or mean incompatible with positive definiteness.\n Try increasing the mean."))
+        return None
+
+    p1 = sqrt(log(pf).power())
+
+    p1[0] = (log(pf)).transform()[mono_ind][0]
+
+    p2 = 0.5*V*log(k_space.calc_weight(spec[pindex],1).sum()+mean**2)
+
+    logmean = 1/V * (p1[0]-p2)
+
+    p1[0] = 0.
+
+    if(np.any(p1<0.)):
+        raise ValueError(about._errors.cstring("ERROR: spectrum or mean incompatible with positive definiteness.\n Try increasing the mean."))
+        return None
+
+    if(bare==True):
+        return logmean.real,power_operator(k_space,spec=p1,bare=False).get_power(bare=True).real
+    else:
+        return logmean.real,p1.real
+
+
+def power_forward_conversion_rg(k_space,p,mean=0,bare=True):
+    """
+        This function is designed to convert a theoretical/statistical power
+        spectrum of a Gaussian field to the theoretical power spectrum of
+        the exponentiated field.
+        The function only works for power spectra defined for rg_spaces
+
+        Parameters
+        ----------
+        k_space : nifty.rg_space,
+            a regular grid space with the attribute `Fourier = True`
+        p : np.array,
+            the power spectrum of the Gaussian field.
+            Needs to have the same number of entries as
+            `k_space.get_power_indices()[0]`
+        mean : float, *optional*
+            specifies the mean of the Gaussian field (default: 0).
+        bare : bool, *optional*
+            whether `p` is the bare power spectrum or not (default: True).
+
+        Returns
+        -------
+        p1 : np.array,
+            the power spectrum of the exponentiated Gaussian field.
+
+        References
+        ----------
+        .. [#] M. Greiner and T.A. Ensslin, "Log-transforming the matter power spectrum";
+            `arXiv:1312.1354 <http://arxiv.org/abs/1312.1354>`_
+    """
+
+    pindex = k_space.get_power_indices()[2]
+
+    spec = power_operator(k_space,spec=p,bare=bare).get_power(bare=False)
+
+    S_x = field(k_space,val=spec[pindex]).transform()
+
+    S_0 = k_space.calc_weight(spec[pindex],1).sum()
+
+    pf = exp(S_x+S_0+2*mean)
+
+    p1 = sqrt(pf.power())
+
+    if(bare==True):
+        return power_operator(k_space,spec=p1,bare=False).get_power(bare=True).real
+    else:
+        return p1.real
+
diff --git a/rg/nifty_rg.py b/rg/nifty_rg.py
new file mode 100644
index 000000000..7d00d085c
--- /dev/null
+++ b/rg/nifty_rg.py
@@ -0,0 +1,1218 @@
+## NIFTY (Numerical Information Field Theory) has been developed at the
+## Max-Planck-Institute for Astrophysics.
+##
+## Copyright (C) 2015 Max-Planck-Society
+##
+## Author: Marco Selig
+## Project homepage: <http://www.mpa-garching.mpg.de/ift/nifty/>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+## See the GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+    ..                  __   ____   __
+    ..                /__/ /   _/ /  /_
+    ..      __ ___    __  /  /_  /   _/  __   __
+    ..    /   _   | /  / /   _/ /  /   /  / /  /
+    ..   /  / /  / /  / /  /   /  /_  /  /_/  /
+    ..  /__/ /__/ /__/ /__/    \___/  \___   /  rg
+    ..                               /______/
+
+    This submodule for regular Cartesian grids.
+
+"""
+from __future__ import division
+#from nifty import *
+import os
+import numpy as np
+import pylab as pl
+from matplotlib.colors import LogNorm as ln
+from matplotlib.ticker import LogFormatter as lf
+from nifty.nifty_core import about,                                          \
+                             random,                                         \
+                             space,                                          \
+                             field
+import nifty.smoothing as gs
+import nifty.powerspectrum as gp
+try:
+    import gfft as gf
+except(ImportError):
+    about.infos.cprint('INFO: "plain" gfft version 0.1.0')
+    import gfft_rg as gf
+
+
+##-----------------------------------------------------------------------------
+
+class rg_space(space):
+    """
+        ..      _____   _______
+        ..    /   __/ /   _   /
+        ..   /  /    /  /_/  /
+        ..  /__/     \____  /  space class
+        ..          /______/
+
+        NIFTY subclass for spaces of regular Cartesian grids.
+
+        Parameters
+        ----------
+        num : {int, numpy.ndarray}
+            Number of gridpoints or numbers of gridpoints along each axis.
+        naxes : int, *optional*
+            Number of axes (default: None).
+        zerocenter : {bool, numpy.ndarray}, *optional*
+            Whether the Fourier zero-mode is located in the center of the grid
+            (or the center of each axis speparately) or not (default: True).
+        hermitian : bool, *optional*
+            Whether the fields living in the space follow hermitian symmetry or
+            not (default: True).
+        purelyreal : bool, *optional*
+            Whether the field values are purely real (default: True).
+        dist : {float, numpy.ndarray}, *optional*
+            Distance between two grid points along each axis (default: None).
+        fourier : bool, *optional*
+            Whether the space represents a Fourier or a position grid
+            (default: False).
+
+        Notes
+        -----
+        Only even numbers of grid points per axis are supported.
+        The basis transformations between position `x` and Fourier mode `k`
+        rely on (inverse) fast Fourier transformations using the
+        :math:`exp(2 \pi i k^\dagger x)`-formulation.
+
+        Attributes
+        ----------
+        para : numpy.ndarray
+            One-dimensional array containing information on the axes of the
+            space in the following form: The first entries give the grid-points
+            along each axis in reverse order; the next entry is 0 if the
+            fields defined on the space are purely real-valued, 1 if they are
+            hermitian and complex, and 2 if they are not hermitian, but
+            complex-valued; the last entries hold the information on whether
+            the axes are centered on zero or not, containing a one for each
+            zero-centered axis and a zero for each other one, in reverse order.
+        datatype : numpy.dtype
+            Data type of the field values for a field defined on this space,
+            either ``numpy.float64`` or ``numpy.complex128``.
+        discrete : bool
+            Whether or not the underlying space is discrete, always ``False``
+            for regular grids.
+        vol : numpy.ndarray
+            One-dimensional array containing the distances between two grid
+            points along each axis, in reverse order. By default, the total
+            length of each axis is assumed to be one.
+        fourier : bool
+            Whether or not the grid represents a Fourier basis.
+    """
+    epsilon = 0.0001 ## relative precision for comparisons
+
+    def __init__(self,num,naxes=None,zerocenter=True,hermitian=True,purelyreal=True,dist=None,fourier=False):
+        """
+            Sets the attributes for an rg_space class instance.
+
+            Parameters
+            ----------
+            num : {int, numpy.ndarray}
+                Number of gridpoints or numbers of gridpoints along each axis.
+            naxes : int, *optional*
+                Number of axes (default: None).
+            zerocenter : {bool, numpy.ndarray}, *optional*
+                Whether the Fourier zero-mode is located in the center of the
+                grid (or the center of each axis speparately) or not
+                (default: True).
+            hermitian : bool, *optional*
+                Whether the fields living in the space follow hermitian
+                symmetry or not (default: True).
+            purelyreal : bool, *optional*
+                Whether the field values are purely real (default: True).
+            dist : {float, numpy.ndarray}, *optional*
+                Distance between two grid points along each axis
+                (default: None).
+            fourier : bool, *optional*
+                Whether the space represents a Fourier or a position grid
+                (default: False).
+
+            Returns
+            -------
+            None
+        """
+        ## check parameters
+        para = np.array([],dtype=np.int)
+        if(np.isscalar(num)):
+            num = np.array([num],dtype=np.int)
+        else:
+            num = np.array(num,dtype=np.int)
+        if(np.any(num%2)): ## module restriction
+            raise ValueError(about._errors.cstring("ERROR: unsupported odd number of grid points."))
+        if(naxes is None):
+            naxes = np.size(num)
+        elif(np.size(num)==1):
+            num = num*np.ones(naxes,dtype=np.int,order='C')
+        elif(np.size(num)!=naxes):
+            raise ValueError(about._errors.cstring("ERROR: size mismatch ( "+str(np.size(num))+" <> "+str(naxes)+" )."))
+        para = np.append(para,num[::-1],axis=None)
+        para = np.append(para,2-(bool(hermitian) or bool(purelyreal))-bool(purelyreal),axis=None) ## {0,1,2}
+        if(np.isscalar(zerocenter)):
+            zerocenter = bool(zerocenter)*np.ones(naxes,dtype=np.int,order='C')
+        else:
+            zerocenter = np.array(zerocenter,dtype=np.bool)
+            if(np.size(zerocenter)==1):
+                zerocenter = zerocenter*np.ones(naxes,dtype=np.int,order='C')
+            elif(np.size(zerocenter)!=naxes):
+                raise ValueError(about._errors.cstring("ERROR: size mismatch ( "+str(np.size(zerocenter))+" <> "+str(naxes)+" )."))
+        para = np.append(para,zerocenter[::-1]*-1,axis=None) ## -1 XOR 0 (centered XOR not)
+
+        self.para = para
+
+        ## set data type
+        if(not self.para[naxes]):
+            self.datatype = np.float64
+        else:
+            self.datatype = np.complex128
+
+        self.discrete = False
+
+        ## set volume
+        if(dist is None):
+            dist = 1/num.astype(self.datatype)
+        elif(np.isscalar(dist)):
+            dist = self.datatype(dist)*np.ones(naxes,dtype=self.datatype,order='C')
+        else:
+            dist = np.array(dist,dtype=self.datatype)
+            if(np.size(dist)==1):
+                dist = dist*np.ones(naxes,dtype=self.datatype,order='C')
+            if(np.size(dist)!=naxes):
+                raise ValueError(about._errors.cstring("ERROR: size mismatch ( "+str(np.size(dist))+" <> "+str(naxes)+" )."))
+        if(np.any(dist<=0)):
+            raise ValueError(about._errors.cstring("ERROR: nonpositive distance(s)."))
+        self.vol = np.real(dist)[::-1]
+
+        self.fourier = bool(fourier)
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def naxes(self):
+        """
+            Returns the number of axes of the grid.
+
+            Returns
+            -------
+            naxes : int
+                Number of axes of the regular grid.
+        """
+        return (np.size(self.para)-1)//2
+
+    def zerocenter(self):
+        """
+            Returns information on the centering of the axes.
+
+            Returns
+            -------
+            zerocenter : numpy.ndarray
+                Whether the grid is centered on zero for each axis or not.
+        """
+        return self.para[-(np.size(self.para)-1)//2:][::-1].astype(np.bool)
+
+    def dist(self):
+        """
+            Returns the distances between grid points along each axis.
+
+            Returns
+            -------
+            dist : np.ndarray
+                Distances between two grid points on each axis.
+        """
+        return self.vol[::-1]
+
+    def dim(self,split=False):
+        """
+            Computes the dimension of the space, i.e.\  the number of pixels.
+
+            Parameters
+            ----------
+            split : bool, *optional*
+                Whether to return the dimension split up, i.e. the numbers of
+                pixels along each axis, or their product (default: False).
+
+            Returns
+            -------
+            dim : {int, numpy.ndarray}
+                Dimension(s) of the space. If ``split==True``, a
+                one-dimensional array with an entry for each axis is returned.
+        """
+        ## dim = product(n)
+        if(split):
+            return self.para[:(np.size(self.para)-1)//2]
+        else:
+            return np.prod(self.para[:(np.size(self.para)-1)//2],axis=0,dtype=None,out=None)
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def dof(self):
+        """
+            Computes the number of degrees of freedom of the space, i.e.\  the
+            number of grid points multiplied with one or two, depending on
+            complex-valuedness and hermitian symmetry of the fields.
+
+            Returns
+            -------
+            dof : int
+                Number of degrees of freedom of the space.
+        """
+        ## dof ~ dim
+        if(self.para[(np.size(self.para)-1)//2]<2):
+            return np.prod(self.para[:(np.size(self.para)-1)//2],axis=0,dtype=None,out=None)
+        else:
+            return 2*np.prod(self.para[:(np.size(self.para)-1)//2],axis=0,dtype=None,out=None)
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def enforce_power(self,spec,size=None,**kwargs):
+        """
+            Provides a valid power spectrum array from a given object.
+
+            Parameters
+            ----------
+            spec : {float, list, numpy.ndarray, nifty.field, function}
+                Fiducial power spectrum from which a valid power spectrum is to
+                be calculated. Scalars are interpreted as constant power
+                spectra.
+
+            Returns
+            -------
+            spec : numpy.ndarray
+                Valid power spectrum.
+
+            Other parameters
+            ----------------
+            size : int, *optional*
+                Number of bands the power spectrum shall have (default: None).
+            kindex : numpy.ndarray, *optional*
+                Scale of each band.
+            codomain : nifty.space, *optional*
+                A compatible codomain for power indexing (default: None).
+            log : bool, *optional*
+                Flag specifying if the spectral binning is performed on logarithmic
+                scale or not; if set, the number of used bins is set
+                automatically (if not given otherwise); by default no binning
+                is done (default: None).
+            nbin : integer, *optional*
+                Number of used spectral bins; if given `log` is set to ``False``;
+                integers below the minimum of 3 induce an automatic setting;
+                by default no binning is done (default: None).
+            binbounds : {list, array}, *optional*
+                User specific inner boundaries of the bins, which are preferred
+                over the above parameters; by default no binning is done
+                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
+                Lower limit of the uniform distribution if ``random == "uni"``
+                (default: 0).
+
+        """
+        if(size is None)or(callable(spec)):
+            ## explicit kindex
+            kindex = kwargs.get("kindex",None)
+            if(kindex is None):
+                ## quick kindex
+                if(self.fourier)and(not hasattr(self,"power_indices"))and(len(kwargs)==0):
+                    kindex = gp.nklength(gp.nkdict_fast(self.para[:(np.size(self.para)-1)//2],self.vol,fourier=True))
+                ## implicit kindex
+                else:
+                    try:
+                        self.set_power_indices(**kwargs)
+                    except:
+                        codomain = kwargs.get("codomain",self.get_codomain())
+                        codomain.set_power_indices(**kwargs)
+                        kindex = codomain.power_indices.get("kindex")
+                    else:
+                        kindex = self.power_indices.get("kindex")
+            size = len(kindex)
+
+        if(isinstance(spec,field)):
+            spec = spec.val.astype(self.datatype)
+        elif(callable(spec)):
+            try:
+                spec = np.array(spec(kindex),dtype=self.datatype)
+            except:
+                raise TypeError(about._errors.cstring("ERROR: invalid power spectra function.")) ## exception in ``spec(kindex)``
+        elif(np.isscalar(spec)):
+            spec = np.array([spec],dtype=self.datatype)
+        else:
+            spec = np.array(spec,dtype=self.datatype)
+
+        ## drop imaginary part
+        spec = np.real(spec)
+        ## check finiteness
+        if(not np.all(np.isfinite(spec))):
+            about.warnings.cprint("WARNING: infinite value(s).")
+        ## check positivity (excluding null)
+        if(np.any(spec<0)):
+            raise ValueError(about._errors.cstring("ERROR: nonpositive value(s)."))
+        elif(np.any(spec==0)):
+            about.warnings.cprint("WARNING: nonpositive value(s).")
+
+        ## extend
+        if(np.size(spec)==1):
+            spec = spec*np.ones(size,dtype=spec.dtype,order='C')
+        ## size check
+        elif(np.size(spec)<size):
+            raise ValueError(about._errors.cstring("ERROR: size mismatch ( "+str(np.size(spec))+" < "+str(size)+" )."))
+        elif(np.size(spec)>size):
+            about.warnings.cprint("WARNING: power spectrum cut to size ( == "+str(size)+" ).")
+            spec = spec[:size]
+
+        return spec
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def set_power_indices(self,**kwargs):
+        """
+            Sets the (un)indexing objects for spectral indexing internally.
+
+            Parameters
+            ----------
+            log : bool
+                Flag specifying if the binning is performed on logarithmic
+                scale or not; if set, the number of used bins is set
+                automatically (if not given otherwise); by default no binning
+                is done (default: None).
+            nbin : integer
+                Number of used bins; if given `log` is set to ``False``;
+                integers below the minimum of 3 induce an automatic setting;
+                by default no binning is done (default: None).
+            binbounds : {list, array}
+                User specific inner boundaries of the bins, which are preferred
+                over the above parameters; by default no binning is done
+                (default: None).
+
+            Returns
+            -------
+            None
+
+            See Also
+            --------
+            get_power_indices
+
+            Raises
+            ------
+            AttributeError
+                If ``self.fourier == False``.
+            ValueError
+                If the binning leaves one or more bins empty.
+
+        """
+        if(not self.fourier):
+            raise AttributeError(about._errors.cstring("ERROR: power spectra indexing ill-defined."))
+        ## check storage
+        if(hasattr(self,"power_indices")):
+            config = self.power_indices.get("config")
+            ## check configuration
+            redo = False
+            if(config.get("log")!=kwargs.get("log",config.get("log"))):
+                config["log"] = kwargs.get("log")
+                redo = True
+            if(config.get("nbin")!=kwargs.get("nbin",config.get("nbin"))):
+                config["nbin"] = kwargs.get("nbin")
+                redo = True
+            if(np.any(config.get("binbounds")!=kwargs.get("binbounds",config.get("binbounds")))):
+                config["binbounds"] = kwargs.get("binbounds")
+                redo = True
+            if(not redo):
+                return None
+        else:
+            config = {"binbounds":kwargs.get("binbounds",None),"log":kwargs.get("log",None),"nbin":kwargs.get("nbin",None)}
+        ## power indices
+        about.infos.cflush("INFO: setting power indices ...")
+        pindex,kindex,rho = gp.get_power_indices2(self.para[:(np.size(self.para)-1)//2],self.vol,self.para[-((np.size(self.para)-1)//2):].astype(np.bool),fourier=True)
+        ## bin if ...
+        if(config.get("log") is not None)or(config.get("nbin") is not None)or(config.get("binbounds") is not None):
+            pindex,kindex,rho = gp.bin_power_indices(pindex,kindex,rho,**config)
+            ## check binning
+            if(np.any(rho==0)):
+                raise ValueError(about._errors.cstring("ERROR: empty bin(s).")) ## binning too fine
+        ## power undex
+        pundex = np.unique(pindex,return_index=True,return_inverse=False)[1]
+        ## storage
+        self.power_indices = {"config":config,"kindex":kindex,"pindex":pindex,"pundex":pundex,"rho":rho} ## alphabetical
+        about.infos.cprint(" done.")
+        return None
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def enforce_values(self,x,extend=True):
+        """
+            Computes valid field values from a given object, taking care of
+            data types, shape, and symmetry.
+
+            Parameters
+            ----------
+            x : {float, numpy.ndarray, nifty.field}
+                Object to be transformed into an array of valid field values.
+
+            Returns
+            -------
+            x : numpy.ndarray
+                Array containing the valid field values.
+
+            Other parameters
+            ----------------
+            extend : bool, *optional*
+                Whether a scalar is extented to a constant array or not
+                (default: True).
+        """
+        if(isinstance(x,field)):
+            if(self==x.domain):
+                if(self.datatype is not x.domain.datatype):
+                    raise TypeError(about._errors.cstring("ERROR: inequal data types ( '"+str(np.result_type(self.datatype))+"' <> '"+str(np.result_type(x.domain.datatype))+"' )."))
+                else:
+                    x = np.copy(x.val)
+            else:
+                raise ValueError(about._errors.cstring("ERROR: inequal domains."))
+        else:
+            if(np.size(x)==1):
+                if(extend):
+                    x = self.datatype(x)*np.ones(self.dim(split=True),dtype=self.datatype,order='C')
+                else:
+                    if(np.isscalar(x)):
+                        x = np.array([x],dtype=self.datatype)
+                    else:
+                        x = np.array(x,dtype=self.datatype)
+            else:
+                x = self.enforce_shape(np.array(x,dtype=self.datatype))
+
+        ## hermitianize if ...
+        if(about.hermitianize.status)and(np.size(x)!=1)and(self.para[(np.size(self.para)-1)//2]==1):
+            x = gp.nhermitianize_fast(x,self.para[-((np.size(self.para)-1)//2):].astype(np.bool),special=False)
+
+        ## check finiteness
+        if(not np.all(np.isfinite(x))):
+            about.warnings.cprint("WARNING: infinite value(s).")
+
+        return x
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def get_random_values(self,**kwargs):
+        """
+            Generates random field values according to the specifications given
+            by the parameters, taking into account possible complex-valuedness
+            and hermitian symmetry.
+
+            Returns
+            -------
+            x : numpy.ndarray
+                Valid field values.
+
+            Other parameters
+            ----------------
+            random : string, *optional*
+                Specifies the probability distribution from which the random
+                numbers are to be drawn.
+                Supported distributions are:
+
+                - "pm1" (uniform distribution over {+1,-1} or {+1,+i,-1,-i}
+                - "gau" (normal distribution with zero-mean and a given standard
+                    deviation or variance)
+                - "syn" (synthesizes from a given power spectrum)
+                - "uni" (uniform distribution over [vmin,vmax[)
+
+                (default: None).
+            dev : float, *optional*
+                Standard deviation (default: 1).
+            var : float, *optional*
+                Variance, overriding `dev` if both are specified
+                (default: 1).
+            spec : {scalar, list, numpy.ndarray, nifty.field, function}, *optional*
+                Power spectrum (default: 1).
+            pindex : numpy.ndarray, *optional*
+                Indexing array giving the power spectrum index of each band
+                (default: None).
+            kindex : numpy.ndarray, *optional*
+                Scale of each band (default: None).
+            codomain : nifty.rg_space, *optional*
+                A compatible codomain with power indices (default: None).
+            log : bool, *optional*
+                Flag specifying if the spectral binning is performed on logarithmic
+                scale or not; if set, the number of used bins is set
+                automatically (if not given otherwise); by default no binning
+                is done (default: None).
+            nbin : integer, *optional*
+                Number of used spectral bins; if given `log` is set to ``False``;
+                integers below the minimum of 3 induce an automatic setting;
+                by default no binning is done (default: None).
+            binbounds : {list, array}, *optional*
+                User specific inner boundaries of the bins, which are preferred
+                over the above parameters; by default no binning is done
+                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
+                Lower limit of the uniform distribution if ``random == "uni"``
+                (default: 0).            vmin : float, *optional*
+                Lower limit for a uniform distribution (default: 0).
+            vmax : float, *optional*
+                Upper limit for a uniform distribution (default: 1).
+        """
+        arg = random.arguments(self,**kwargs)
+
+        if(arg is None):
+            return np.zeros(self.dim(split=True),dtype=self.datatype,order='C')
+
+        elif(arg[0]=="pm1"):
+            if(about.hermitianize.status)and(self.para[(np.size(self.para)-1)//2]==1):
+                return gp.random_hermitian_pm1(self.datatype,self.para[-((np.size(self.para)-1)//2):].astype(np.bool),self.dim(split=True)) ## special case
+            else:
+                x = random.pm1(datatype=self.datatype,shape=self.dim(split=True))
+
+        elif(arg[0]=="gau"):
+            x = random.gau(datatype=self.datatype,shape=self.dim(split=True),mean=None,dev=arg[2],var=arg[3])
+
+        elif(arg[0]=="syn"):
+            naxes = (np.size(self.para)-1)//2
+            x = gp.draw_vector_nd(self.para[:naxes],self.vol,arg[1],symtype=self.para[naxes],fourier=self.fourier,zerocentered=self.para[-naxes:].astype(np.bool),kpack=arg[2])
+            ## correct for 'ifft'
+            if(not self.fourier):
+                x = self.calc_weight(x,power=-1)
+            return x
+
+        elif(arg[0]=="uni"):
+            x = random.uni(datatype=self.datatype,shape=self.dim(split=True),vmin=arg[1],vmax=arg[2])
+
+        else:
+            raise KeyError(about._errors.cstring("ERROR: unsupported random key '"+str(arg[0])+"'."))
+
+        ## hermitianize if ...
+        if(about.hermitianize.status)and(self.para[(np.size(self.para)-1)//2]==1):
+            x = gp.nhermitianize_fast(x,self.para[-((np.size(self.para)-1)//2):].astype(np.bool),special=(arg[0] in ["gau","pm1"]))
+
+        return x
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def check_codomain(self,codomain):
+        """
+            Checks whether a given codomain is compatible to the space or not.
+
+            Parameters
+            ----------
+            codomain : nifty.space
+                Space to be checked for compatibility.
+
+            Returns
+            -------
+            check : bool
+                Whether or not the given codomain is compatible to the space.
+        """
+        if(not isinstance(codomain,space)):
+            raise TypeError(about._errors.cstring("ERROR: invalid input."))
+
+        elif(isinstance(codomain,rg_space)):
+            ##                       naxes==naxes
+            if((np.size(codomain.para)-1)//2==(np.size(self.para)-1)//2):
+                naxes = (np.size(self.para)-1)//2
+                ##                            num'==num
+                if(np.all(codomain.para[:naxes]==self.para[:naxes])):
+                    ##                 typ'==typ             ==2
+                    if(codomain.para[naxes]==self.para[naxes]==2):
+                        ##                                         dist'~=1/(num*dist)
+                        if(np.all(np.absolute(self.para[:naxes]*self.vol*codomain.vol-1)<self.epsilon)):
+                            return True
+                        ##           fourier'==fourier
+                        elif(codomain.fourier==self.fourier):
+                            ##                           dist'~=dist
+                            if(np.all(np.absolute(codomain.vol/self.vol-1)<self.epsilon)):
+                                return True
+                            else:
+                                about.warnings.cprint("WARNING: unrecommended codomain.")
+                    ##   2!=                typ'!=typ             !=2                                             dist'~=1/(num*dist)
+                    elif(2!=codomain.para[naxes]!=self.para[naxes]!=2)and(np.all(np.absolute(self.para[:naxes]*self.vol*codomain.vol-1)<self.epsilon)):
+                        return True
+                    ##                   typ'==typ             !=2
+                    elif(codomain.para[naxes]==self.para[naxes]!=2)and(codomain.fourier==self.fourier):
+                        ##                           dist'~=dist
+                        if(np.all(np.absolute(codomain.vol/self.vol-1)<self.epsilon)):
+                            return True
+                        else:
+                            about.warnings.cprint("WARNING: unrecommended codomain.")
+
+        return False
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def get_codomain(self,coname=None,cozerocenter=None,**kwargs):
+        """
+            Generates a compatible codomain to which transformations are
+            reasonable, i.e.\  either a shifted grid or a Fourier conjugate
+            grid.
+
+            Parameters
+            ----------
+            coname : string, *optional*
+                String specifying a desired codomain (default: None).
+            cozerocenter : {bool, numpy.ndarray}, *optional*
+                Whether or not the grid is zerocentered for each axis or not
+                (default: None).
+
+            Returns
+            -------
+            codomain : nifty.rg_space
+                A compatible codomain.
+
+            Notes
+            -----
+            Possible arguments for `coname` are ``'f'`` in which case the
+            codomain arises from a Fourier transformation, ``'i'`` in which case
+            it arises from an inverse Fourier transformation, and ``'?'`` in
+            which case it arises from a simple shift. If no `coname` is given,
+            the Fourier conjugate grid is produced.
+        """
+        naxes = (np.size(self.para)-1)//2
+        if(cozerocenter is None):
+            cozerocenter = self.para[-naxes:][::-1]
+        elif(np.isscalar(cozerocenter)):
+            cozerocenter = bool(cozerocenter)
+        else:
+            cozerocenter = np.array(cozerocenter,dtype=np.bool)
+            if(np.size(cozerocenter)==1):
+                cozerocenter = np.asscalar(cozerocenter)
+            elif(np.size(cozerocenter)!=naxes):
+                raise ValueError(about._errors.cstring("ERROR: size mismatch ( "+str(np.size(cozerocenter))+" <> "+str(naxes)+" )."))
+
+        if(coname is None):
+            return rg_space(self.para[:naxes][::-1],naxes=naxes,zerocenter=cozerocenter,hermitian=bool(self.para[naxes]<2),purelyreal=bool(self.para[naxes]==1),dist=1/(self.para[:naxes]*self.vol)[::-1],fourier=bool(not self.fourier)) ## dist',fourier' = 1/(num*dist),NOT fourier
+
+        elif(coname[0]=='f'):
+            return rg_space(self.para[:naxes][::-1],naxes=naxes,zerocenter=cozerocenter,hermitian=bool(self.para[naxes]<2),purelyreal=bool(self.para[naxes]==1),dist=1/(self.para[:naxes]*self.vol)[::-1],fourier=True) ## dist',fourier' = 1/(num*dist),True
+
+        elif(coname[0]=='i'):
+            return rg_space(self.para[:naxes][::-1],naxes=naxes,zerocenter=cozerocenter,hermitian=bool(self.para[naxes]<2),purelyreal=bool(self.para[naxes]==1),dist=1/(self.para[:naxes]*self.vol)[::-1],fourier=False) ## dist',fourier' = 1/(num*dist),False
+
+        else:
+            return rg_space(self.para[:naxes][::-1],naxes=naxes,zerocenter=cozerocenter,hermitian=bool(self.para[naxes]<2),purelyreal=bool(not self.para[naxes]),dist=self.vol[::-1],fourier=self.fourier) ## dist',fourier' = dist,fourier
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def get_meta_volume(self,total=False):
+        """
+            Calculates the meta volumes.
+
+            The meta volumes are the volumes associated with each component of
+            a field, taking into account field components that are not
+            explicitly included in the array of field values but are determined
+            by symmetry conditions. In the case of an :py:class:`rg_space`, the
+            meta volumes are simply the pixel volumes.
+
+            Parameters
+            ----------
+            total : bool, *optional*
+                Whether to return the total meta volume of the space or the
+                individual ones of each pixel (default: False).
+
+            Returns
+            -------
+            mol : {numpy.ndarray, float}
+                Meta volume of the pixels or the complete space.
+        """
+        if(total):
+            return self.dim(split=False)*np.prod(self.vol,axis=0,dtype=None,out=None)
+        else:
+            mol = np.ones(self.dim(split=True),dtype=self.vol.dtype,order='C')
+            return self.calc_weight(mol,power=1)
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def calc_weight(self,x,power=1):
+        """
+            Weights a given array with the pixel volumes to a given power.
+
+            Parameters
+            ----------
+            x : numpy.ndarray
+                Array to be weighted.
+            power : float, *optional*
+                Power of the pixel volumes to be used (default: 1).
+
+            Returns
+            -------
+            y : numpy.ndarray
+                Weighted array.
+        """
+        x = self.enforce_shape(np.array(x,dtype=self.datatype))
+        ## weight
+        return x*np.prod(self.vol,axis=0,dtype=None,out=None)**power
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def calc_dot(self,x,y):
+        """
+            Computes the discrete inner product of two given arrays.
+
+            Parameters
+            ----------
+            x : numpy.ndarray
+                First array
+            y : numpy.ndarray
+                Second array
+
+            Returns
+            -------
+            dot : scalar
+                Inner product of the two arrays.
+        """
+        x = self.enforce_shape(np.array(x,dtype=self.datatype))
+        y = self.enforce_shape(np.array(y,dtype=self.datatype))
+        ## inner product
+        dot = np.dot(np.conjugate(x.flatten(order='C')),y.flatten(order='C'),out=None)
+        if(np.isreal(dot)):
+            return np.asscalar(np.real(dot))
+        elif(self.para[(np.size(self.para)-1)//2]!=2):
+                ## check imaginary part
+                if(np.absolute(dot.imag)>self.epsilon**2*np.absolute(dot.real)):
+                    about.warnings.cprint("WARNING: discarding considerable imaginary part.")
+                return np.asscalar(np.real(dot))
+        else:
+            return dot
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def calc_transform(self,x,codomain=None,**kwargs):
+        """
+            Computes the transform of a given array of field values.
+
+            Parameters
+            ----------
+            x : numpy.ndarray
+                Array to be transformed.
+            codomain : nifty.rg_space, *optional*
+                Target space to which the transformation shall map
+                (default: None).
+
+            Returns
+            -------
+            Tx : numpy.ndarray
+                Transformed array
+        """
+        x = self.enforce_shape(np.array(x,dtype=self.datatype))
+
+        if(codomain is None):
+            return x ## T == id
+
+        ## mandatory(!) codomain check
+        if(isinstance(codomain,rg_space))and(self.check_codomain(codomain)):
+            naxes = (np.size(self.para)-1)//2
+            ## select machine
+            if(np.all(np.absolute(self.para[:naxes]*self.vol*codomain.vol-1)<self.epsilon)):
+                if(codomain.fourier):
+                    ftmachine = "fft"
+                    ## correct for 'fft'
+                    x = self.calc_weight(x,power=1)
+                else:
+                    ftmachine = "ifft"
+                    ## correct for 'ifft'
+                    x = self.calc_weight(x,power=1)
+                    x *= self.dim(split=False)
+            else:
+                ftmachine = "none"
+            ## transform
+            if(self.datatype==np.float64):
+                Tx = gf.gfft(x.astype(np.complex128),in_ax=[],out_ax=[],ftmachine=ftmachine,in_zero_center=self.para[-naxes:].astype(np.bool).tolist(),out_zero_center=codomain.para[-naxes:].astype(np.bool).tolist(),enforce_hermitian_symmetry=bool(codomain.para[naxes]==1),W=-1,alpha=-1,verbose=False)
+            else:
+                Tx = gf.gfft(x,in_ax=[],out_ax=[],ftmachine=ftmachine,in_zero_center=self.para[-naxes:].astype(np.bool).tolist(),out_zero_center=codomain.para[-naxes:].astype(np.bool).tolist(),enforce_hermitian_symmetry=bool(codomain.para[naxes]==1),W=-1,alpha=-1,verbose=False)
+            ## check complexity
+            if(not codomain.para[naxes]): ## purely real
+                ## check imaginary part
+                if(np.any(Tx.imag!=0))and(np.dot(Tx.imag.flatten(order='C'),Tx.imag.flatten(order='C'),out=None)>self.epsilon**2*np.dot(Tx.real.flatten(order='C'),Tx.real.flatten(order='C'),out=None)):
+                    about.warnings.cprint("WARNING: discarding considerable imaginary part.")
+                Tx = np.real(Tx)
+
+        else:
+            raise ValueError(about._errors.cstring("ERROR: unsupported transformation."))
+
+        return Tx.astype(codomain.datatype)
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def calc_smooth(self,x,sigma=0,**kwargs):
+        """
+            Smoothes an array of field values by convolution with a Gaussian
+            kernel.
+
+            Parameters
+            ----------
+            x : numpy.ndarray
+                Array of field values to be smoothed.
+            sigma : float, *optional*
+                Standard deviation of the Gaussian kernel, specified in units
+                of length in position space; for testing: a sigma of -1 will be
+                reset to a reasonable value (default: 0).
+
+            Returns
+            -------
+            Gx : numpy.ndarray
+                Smoothed array.
+        """
+        x = self.enforce_shape(np.array(x,dtype=self.datatype))
+        naxes = (np.size(self.para)-1)//2
+
+        ## check sigma
+        if(sigma==0):
+            return x
+        elif(sigma==-1):
+            about.infos.cprint("INFO: invalid sigma reset.")
+            if(self.fourier):
+                sigma = 1.5/np.min(self.para[:naxes]*self.vol) ## sqrt(2)*max(dist)
+            else:
+                sigma = 1.5*np.max(self.vol) ## sqrt(2)*max(dist)
+        elif(sigma<0):
+            raise ValueError(about._errors.cstring("ERROR: invalid sigma."))
+        ## smooth
+        Gx = gs.smooth_field(x,self.fourier,self.para[-naxes:].astype(np.bool).tolist(),bool(self.para[naxes]==1),self.vol,smooth_length=sigma)
+        ## check complexity
+        if(not self.para[naxes]): ## purely real
+            ## check imaginary part
+            if(np.any(Gx.imag!=0))and(np.dot(Gx.imag.flatten(order='C'),Gx.imag.flatten(order='C'),out=None)>self.epsilon**2*np.dot(Gx.real.flatten(order='C'),Gx.real.flatten(order='C'),out=None)):
+                about.warnings.cprint("WARNING: discarding considerable imaginary part.")
+            Gx = np.real(Gx)
+        return Gx
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def calc_power(self,x,**kwargs):
+        """
+            Computes the power of an array of field values.
+
+            Parameters
+            ----------
+            x : numpy.ndarray
+                Array containing the field values of which the power is to be
+                calculated.
+
+            Returns
+            -------
+            spec : numpy.ndarray
+                Power contained in the input array.
+
+            Other parameters
+            ----------------
+            pindex : numpy.ndarray, *optional*
+                Indexing array assigning the input array components to
+                components of the power spectrum (default: None).
+            kindex : numpy.ndarray, *optional*
+                Scale corresponding to each band in the power spectrum
+                (default: None).
+            rho : numpy.ndarray, *optional*
+                Number of degrees of freedom per band (default: None).
+            codomain : nifty.space, *optional*
+                A compatible codomain for power indexing (default: None).
+            log : bool, *optional*
+                Flag specifying if the spectral binning is performed on logarithmic
+                scale or not; if set, the number of used bins is set
+                automatically (if not given otherwise); by default no binning
+                is done (default: None).
+            nbin : integer, *optional*
+                Number of used spectral bins; if given `log` is set to ``False``;
+                integers below the minimum of 3 induce an automatic setting;
+                by default no binning is done (default: None).
+            binbounds : {list, array}, *optional*
+                User specific inner boundaries of the bins, which are preferred
+                over the above parameters; by default no binning is done
+                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
+                Lower limit of the uniform distribution if ``random == "uni"``
+                (default: 0).
+
+        """
+        x = self.enforce_shape(np.array(x,dtype=self.datatype))
+        ## correct for 'fft'
+        if(not self.fourier):
+            x = self.calc_weight(x,power=1)
+        ## explicit power indices
+        pindex,kindex,rho = kwargs.get("pindex",None),kwargs.get("kindex",None),kwargs.get("rho",None)
+        ## implicit power indices
+        if(pindex is None)or(kindex is None)or(rho is None):
+            try:
+                self.set_power_indices(**kwargs)
+            except:
+                codomain = kwargs.get("codomain",self.get_codomain())
+                codomain.set_power_indices(**kwargs)
+                pindex,kindex,rho = codomain.power_indices.get("pindex"),codomain.power_indices.get("kindex"),codomain.power_indices.get("rho")
+            else:
+                pindex,kindex,rho = self.power_indices.get("pindex"),self.power_indices.get("kindex"),self.power_indices.get("rho")
+        ## power spectrum
+        return gp.calc_ps_fast(x,self.para[:(np.size(self.para)-1)//2],self.vol,self.para[-((np.size(self.para)-1)//2):].astype(np.bool),fourier=self.fourier,pindex=pindex,kindex=kindex,rho=rho)
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def get_plot(self,x,title="",vmin=None,vmax=None,power=None,unit="",norm=None,cmap=None,cbar=True,other=None,legend=False,mono=True,**kwargs):
+        """
+            Creates a plot of field values according to the specifications
+            given by the parameters.
+
+            Parameters
+            ----------
+            x : numpy.ndarray
+                Array containing the field values.
+
+            Returns
+            -------
+            None
+
+            Other parameters
+            ----------------
+            title : string, *optional*
+                Title of the plot (default: "").
+            vmin : float, *optional*
+                Minimum value to be displayed (default: ``min(x)``).
+            vmax : float, *optional*
+                Maximum value to be displayed (default: ``max(x)``).
+            power : bool, *optional*
+                Whether to plot the power contained in the field or the field
+                values themselves (default: False).
+            unit : string, *optional*
+                Unit of the field values (default: "").
+            norm : string, *optional*
+                Scaling of the field values before plotting (default: None).
+            cmap : matplotlib.colors.LinearSegmentedColormap, *optional*
+                Color map to be used for two-dimensional plots (default: None).
+            cbar : bool, *optional*
+                Whether to show the color bar or not (default: True).
+            other : {single object, tuple of objects}, *optional*
+                Object or tuple of objects to be added, where objects can be
+                scalars, arrays, or fields (default: None).
+            legend : bool, *optional*
+                Whether to show the legend or not (default: False).
+            mono : bool, *optional*
+                Whether to plot the monopole or not (default: True).
+            save : string, *optional*
+                Valid file name where the figure is to be stored, by default
+                the figure is not saved (default: False).
+            error : {float, numpy.ndarray, nifty.field}, *optional*
+                Object indicating some confidence interval to be plotted
+                (default: None).
+            kindex : numpy.ndarray, *optional*
+                Scale corresponding to each band in the power spectrum
+                (default: None).
+            codomain : nifty.space, *optional*
+                A compatible codomain for power indexing (default: None).
+            log : bool, *optional*
+                Flag specifying if the spectral binning is performed on logarithmic
+                scale or not; if set, the number of used bins is set
+                automatically (if not given otherwise); by default no binning
+                is done (default: None).
+            nbin : integer, *optional*
+                Number of used spectral bins; if given `log` is set to ``False``;
+                integers below the minimum of 3 induce an automatic setting;
+                by default no binning is done (default: None).
+            binbounds : {list, array}, *optional*
+                User specific inner boundaries of the bins, which are preferred
+                over the above parameters; by default no binning is done
+                (default: None).            vmin : {scalar, list, ndarray, field}, *optional*
+                Lower limit of the uniform distribution if ``random == "uni"``
+                (default: 0).
+
+        """
+        if(not pl.isinteractive())and(not bool(kwargs.get("save",False))):
+            about.warnings.cprint("WARNING: interactive mode off.")
+
+        naxes = (np.size(self.para)-1)//2
+        if(power is None):
+            power = bool(self.para[naxes])
+
+        if(power):
+            x = self.calc_power(x,**kwargs)
+
+            fig = pl.figure(num=None,figsize=(6.4,4.8),dpi=None,facecolor="none",edgecolor="none",frameon=False,FigureClass=pl.Figure)
+            ax0 = fig.add_axes([0.12,0.12,0.82,0.76])
+
+            ## explicit kindex
+            xaxes = kwargs.get("kindex",None)
+            ## implicit kindex
+            if(xaxes is None):
+                try:
+                    self.set_power_indices(**kwargs)
+                except:
+                    codomain = kwargs.get("codomain",self.get_codomain())
+                    codomain.set_power_indices(**kwargs)
+                    xaxes = codomain.power_indices.get("kindex")
+                else:
+                    xaxes = self.power_indices.get("kindex")
+
+            if(norm is None)or(not isinstance(norm,int)):
+                norm = naxes
+            if(vmin is None):
+                vmin = np.min(x[:mono].tolist()+(xaxes**norm*x)[1:].tolist(),axis=None,out=None)
+            if(vmax is None):
+                vmax = np.max(x[:mono].tolist()+(xaxes**norm*x)[1:].tolist(),axis=None,out=None)
+            ax0.loglog(xaxes[1:],(xaxes**norm*x)[1:],color=[0.0,0.5,0.0],label="graph 0",linestyle='-',linewidth=2.0,zorder=1)
+            if(mono):
+                ax0.scatter(0.5*(xaxes[1]+xaxes[2]),x[0],s=20,color=[0.0,0.5,0.0],marker='o',cmap=None,norm=None,vmin=None,vmax=None,alpha=None,linewidths=None,verts=None,zorder=1)
+
+            if(other is not None):
+                if(isinstance(other,tuple)):
+                    other = list(other)
+                    for ii in xrange(len(other)):
+                        if(isinstance(other[ii],field)):
+                            other[ii] = other[ii].power(**kwargs)
+                        else:
+                            other[ii] = self.enforce_power(other[ii],size=np.size(xaxes),kindex=xaxes)
+                elif(isinstance(other,field)):
+                    other = [other.power(**kwargs)]
+                else:
+                    other = [self.enforce_power(other,size=np.size(xaxes),kindex=xaxes)]
+                imax = max(1,len(other)-1)
+                for ii in xrange(len(other)):
+                    ax0.loglog(xaxes[1:],(xaxes**norm*other[ii])[1:],color=[max(0.0,1.0-(2*ii/imax)**2),0.5*((2*ii-imax)/imax)**2,max(0.0,1.0-(2*(ii-imax)/imax)**2)],label="graph "+str(ii+1),linestyle='-',linewidth=1.0,zorder=-ii)
+                    if(mono):
+                        ax0.scatter(0.5*(xaxes[1]+xaxes[2]),other[ii][0],s=20,color=[max(0.0,1.0-(2*ii/imax)**2),0.5*((2*ii-imax)/imax)**2,max(0.0,1.0-(2*(ii-imax)/imax)**2)],marker='o',cmap=None,norm=None,vmin=None,vmax=None,alpha=None,linewidths=None,verts=None,zorder=-ii)
+                if(legend):
+                    ax0.legend()
+
+            ax0.set_xlim(xaxes[1],xaxes[-1])
+            ax0.set_xlabel(r"$|k|$")
+            ax0.set_ylim(vmin,vmax)
+            ax0.set_ylabel(r"$|k|^{%i} P_k$"%norm)
+            ax0.set_title(title)
+
+        else:
+            x = self.enforce_shape(np.array(x))
+
+            if(naxes==1):
+                fig = pl.figure(num=None,figsize=(6.4,4.8),dpi=None,facecolor="none",edgecolor="none",frameon=False,FigureClass=pl.Figure)
+                ax0 = fig.add_axes([0.12,0.12,0.82,0.76])
+
+                xaxes = (np.arange(self.para[0],dtype=np.int)+self.para[2]*(self.para[0]//2))*self.vol
+                if(vmin is None):
+                    if(np.iscomplexobj(x)):
+                        vmin = min(np.min(np.absolute(x),axis=None,out=None),np.min(np.real(x),axis=None,out=None),np.min(np.imag(x),axis=None,out=None))
+                    else:
+                        vmin = np.min(x,axis=None,out=None)
+                if(vmax is None):
+                    if(np.iscomplexobj(x)):
+                        vmax = max(np.max(np.absolute(x),axis=None,out=None),np.max(np.real(x),axis=None,out=None),np.max(np.imag(x),axis=None,out=None))
+                    else:
+                        vmax = np.max(x,axis=None,out=None)
+                if(norm=="log"):
+                    ax0graph = ax0.semilogy
+                    if(vmin<=0):
+                        raise ValueError(about._errors.cstring("ERROR: nonpositive value(s)."))
+                else:
+                    ax0graph = ax0.plot
+
+                if(np.iscomplexobj(x)):
+                    ax0graph(xaxes,np.absolute(x),color=[0.0,0.5,0.0],label="graph (absolute)",linestyle='-',linewidth=2.0,zorder=1)
+                    ax0graph(xaxes,np.real(x),color=[0.0,0.5,0.0],label="graph (real part)",linestyle="--",linewidth=1.0,zorder=0)
+                    ax0graph(xaxes,np.imag(x),color=[0.0,0.5,0.0],label="graph (imaginary part)",linestyle=':',linewidth=1.0,zorder=0)
+                    if(legend):
+                        ax0.legend()
+                elif(other is not None):
+                    ax0graph(xaxes,x,color=[0.0,0.5,0.0],label="graph 0",linestyle='-',linewidth=2.0,zorder=1)
+                    if(isinstance(other,tuple)):
+                        other = [self.enforce_values(xx,extend=True) for xx in other]
+                    else:
+                        other = [self.enforce_values(other,extend=True)]
+                    imax = max(1,len(other)-1)
+                    for ii in xrange(len(other)):
+                        ax0graph(xaxes,other[ii],color=[max(0.0,1.0-(2*ii/imax)**2),0.5*((2*ii-imax)/imax)**2,max(0.0,1.0-(2*(ii-imax)/imax)**2)],label="graph "+str(ii+1),linestyle='-',linewidth=1.0,zorder=-ii)
+                    if("error" in kwargs):
+                        error = self.enforce_values(np.absolute(kwargs.get("error")),extend=True)
+                        ax0.fill_between(xaxes,x-error,x+error,color=[0.8,0.8,0.8],label="error 0",zorder=-len(other))
+                    if(legend):
+                        ax0.legend()
+                else:
+                    ax0graph(xaxes,x,color=[0.0,0.5,0.0],label="graph 0",linestyle='-',linewidth=2.0,zorder=1)
+                    if("error" in kwargs):
+                        error = self.enforce_values(np.absolute(kwargs.get("error")),extend=True)
+                        ax0.fill_between(xaxes,x-error,x+error,color=[0.8,0.8,0.8],label="error 0",zorder=0)
+
+                ax0.set_xlim(xaxes[0],xaxes[-1])
+                ax0.set_xlabel("coordinate")
+                ax0.set_ylim(vmin,vmax)
+                if(unit):
+                    unit = " ["+unit+"]"
+                ax0.set_ylabel("values"+unit)
+                ax0.set_title(title)
+
+            elif(naxes==2):
+                if(np.iscomplexobj(x)):
+                    about.infos.cprint("INFO: absolute values and phases are plotted.")
+                    if(title):
+                        title += " "
+                    if(bool(kwargs.get("save",False))):
+                        save_ = os.path.splitext(os.path.basename(str(kwargs.get("save"))))
+                        kwargs.update(save=save_[0]+"_absolute"+save_[1])
+                    self.get_plot(np.absolute(x),title=title+"(absolute)",vmin=vmin,vmax=vmax,power=False,unit=unit,norm=norm,cmap=cmap,cbar=cbar,other=None,legend=False,**kwargs)
+#                    self.get_plot(np.real(x),title=title+"(real part)",vmin=vmin,vmax=vmax,power=False,unit=unit,norm=norm,cmap=cmap,cbar=cbar,other=None,legend=False,**kwargs)
+#                    self.get_plot(np.imag(x),title=title+"(imaginary part)",vmin=vmin,vmax=vmax,power=False,unit=unit,norm=norm,cmap=cmap,cbar=cbar,other=None,legend=False,**kwargs)
+                    if(unit):
+                        unit = "rad"
+                    if(cmap is None):
+                        cmap = pl.cm.hsv_r
+                    if(bool(kwargs.get("save",False))):
+                        kwargs.update(save=save_[0]+"_phase"+save_[1])
+                    self.get_plot(np.angle(x,deg=False),title=title+"(phase)",vmin=-3.1416,vmax=3.1416,power=False,unit=unit,norm=None,cmap=cmap,cbar=cbar,other=None,legend=False,**kwargs) ## values in [-pi,pi]
+                    return None ## leave method
+                else:
+                    if(vmin is None):
+                        vmin = np.min(x,axis=None,out=None)
+                    if(vmax is None):
+                        vmax = np.max(x,axis=None,out=None)
+                    if(norm=="log")and(vmin<=0):
+                        raise ValueError(about._errors.cstring("ERROR: nonpositive value(s)."))
+
+                    s_ = np.array([self.para[1]*self.vol[1]/np.max(self.para[:naxes]*self.vol,axis=None,out=None),self.para[0]*self.vol[0]/np.max(self.para[:naxes]*self.vol,axis=None,out=None)*(1.0+0.159*bool(cbar))])
+                    fig = pl.figure(num=None,figsize=(6.4*s_[0],6.4*s_[1]),dpi=None,facecolor="none",edgecolor="none",frameon=False,FigureClass=pl.Figure)
+                    ax0 = fig.add_axes([0.06/s_[0],0.06/s_[1],1.0-0.12/s_[0],1.0-0.12/s_[1]])
+
+                    xaxes = (np.arange(self.para[1]+1,dtype=np.int)-0.5+self.para[4]*(self.para[1]//2))*self.vol[1]
+                    yaxes = (np.arange(self.para[0]+1,dtype=np.int)-0.5+self.para[3]*(self.para[0]//2))*self.vol[0]
+                    if(norm=="log"):
+                        n_ = ln(vmin=vmin,vmax=vmax)
+                    else:
+                        n_ = None
+                    sub = ax0.pcolormesh(xaxes,yaxes,x,cmap=cmap,norm=n_,vmin=vmin,vmax=vmax)
+                    ax0.set_xlim(xaxes[0],xaxes[-1])
+                    ax0.set_xticks([0],minor=False)
+                    ax0.set_ylim(yaxes[0],yaxes[-1])
+                    ax0.set_yticks([0],minor=False)
+                    ax0.set_aspect("equal")
+                    if(cbar):
+                        if(norm=="log"):
+                            f_ = lf(10,labelOnlyBase=False)
+                            b_ = sub.norm.inverse(np.linspace(0,1,sub.cmap.N+1))
+                            v_ = np.linspace(sub.norm.vmin,sub.norm.vmax,sub.cmap.N)
+                        else:
+                            f_ = None
+                            b_ = None
+                            v_ = None
+                        cb0 = fig.colorbar(sub,ax=ax0,orientation="horizontal",fraction=0.1,pad=0.05,shrink=0.75,aspect=20,ticks=[vmin,vmax],format=f_,drawedges=False,boundaries=b_,values=v_)
+                        cb0.ax.text(0.5,-1.0,unit,fontdict=None,withdash=False,transform=cb0.ax.transAxes,horizontalalignment="center",verticalalignment="center")
+                    ax0.set_title(title)
+
+            else:
+                raise ValueError(about._errors.cstring("ERROR: unsupported number of axes ( "+str(naxes)+" > 2 )."))
+
+        if(bool(kwargs.get("save",False))):
+            fig.savefig(str(kwargs.get("save")),dpi=None,facecolor="none",edgecolor="none",orientation="portrait",papertype=None,format=None,transparent=False,bbox_inches=None,pad_inches=0.1)
+            pl.close(fig)
+        else:
+            fig.canvas.draw()
+
+    ##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    def __repr__(self):
+        return "<nifty_rg.rg_space>"
+
+    def __str__(self):
+        naxes = (np.size(self.para)-1)//2
+        num = self.para[:naxes][::-1].tolist()
+        zerocenter = self.para[-naxes:][::-1].astype(np.bool).tolist()
+        dist = self.vol[::-1].tolist()
+        return "nifty_rg.rg_space instance\n- num        = "+str(num)+"\n- naxes      = "+str(naxes)+"\n- hermitian  = "+str(bool(self.para[naxes]<2))+"\n- purelyreal = "+str(bool(not self.para[naxes]))+"\n- zerocenter = "+str(zerocenter)+"\n- dist       = "+str(dist)+"\n- fourier    = "+str(self.fourier)
+
+##-----------------------------------------------------------------------------
+
diff --git a/powerspectrum.py b/rg/powerspectrum.py
similarity index 100%
rename from powerspectrum.py
rename to rg/powerspectrum.py
diff --git a/smoothing.py b/rg/smoothing.py
similarity index 100%
rename from smoothing.py
rename to rg/smoothing.py
-- 
GitLab