Commit 54f203dd authored by Theo Steininger's avatar Theo Steininger
Browse files

Merge branch ''docu_power_space'' into 'master'

added all the docstrings for PowerSpace and changed PowerSpace.log to PowerSpace…

See merge request !95
parents 61a68dca 4e08ce82
Pipeline #12260 passed with stages
in 12 minutes and 27 seconds
...@@ -167,7 +167,7 @@ class Field(Loggable, Versionable, object): ...@@ -167,7 +167,7 @@ class Field(Loggable, Versionable, object):
# ---Powerspectral methods--- # ---Powerspectral methods---
def power_analyze(self, spaces=None, log=False, nbin=None, binbounds=None, def power_analyze(self, spaces=None, logarithmic=False, nbin=None, binbounds=None,
decompose_power=False): decompose_power=False):
# check if all spaces in `self.domain` are either harmonic or # check if all spaces in `self.domain` are either harmonic or
# power_space instances # power_space instances
...@@ -210,10 +210,10 @@ class Field(Loggable, Versionable, object): ...@@ -210,10 +210,10 @@ class Field(Loggable, Versionable, object):
self.val.get_axes_local_distribution_strategy( self.val.get_axes_local_distribution_strategy(
self.domain_axes[space_index]) self.domain_axes[space_index])
harmonic_domain = self.domain[space_index] harmonic_partner = self.domain[space_index]
power_domain = PowerSpace(harmonic_domain=harmonic_domain, power_domain = PowerSpace(harmonic_partner=harmonic_partner,
distribution_strategy=distribution_strategy, distribution_strategy=distribution_strategy,
log=log, nbin=nbin, binbounds=binbounds) logarithmic=logarithmic, nbin=nbin, binbounds=binbounds)
# extract pindex and rho from power_domain # extract pindex and rho from power_domain
pindex = power_domain.pindex pindex = power_domain.pindex
...@@ -221,7 +221,7 @@ class Field(Loggable, Versionable, object): ...@@ -221,7 +221,7 @@ class Field(Loggable, Versionable, object):
if decompose_power: if decompose_power:
hermitian_part, anti_hermitian_part = \ hermitian_part, anti_hermitian_part = \
harmonic_domain.hermitian_decomposition( harmonic_partner.hermitian_decomposition(
self.val, self.val,
axes=self.domain_axes[space_index]) axes=self.domain_axes[space_index])
...@@ -322,8 +322,8 @@ class Field(Loggable, Versionable, object): ...@@ -322,8 +322,8 @@ class Field(Loggable, Versionable, object):
result_domain = list(self.domain) result_domain = list(self.domain)
for power_space_index in spaces: for power_space_index in spaces:
power_space = self.domain[power_space_index] power_space = self.domain[power_space_index]
harmonic_domain = power_space.harmonic_domain harmonic_partner = power_space.harmonic_partner
result_domain[power_space_index] = harmonic_domain result_domain[power_space_index] = harmonic_partner
# create random samples: one or two, depending on whether the # create random samples: one or two, depending on whether the
# power spectrum is real or complex # power spectrum is real or complex
...@@ -365,8 +365,8 @@ class Field(Loggable, Versionable, object): ...@@ -365,8 +365,8 @@ class Field(Loggable, Versionable, object):
if real_signal: if real_signal:
for power_space_index in spaces: for power_space_index in spaces:
harmonic_domain = result_domain[power_space_index] harmonic_partner = result_domain[power_space_index]
result_val_list = [harmonic_domain.hermitian_decomposition( result_val_list = [harmonic_partner.hermitian_decomposition(
result_val, result_val,
axes=result.domain_axes[power_space_index], axes=result.domain_axes[power_space_index],
preserve_gaussian_variance=True)[0] preserve_gaussian_variance=True)[0]
......
...@@ -24,15 +24,17 @@ class _PowerIndexFactory(object): ...@@ -24,15 +24,17 @@ class _PowerIndexFactory(object):
self.power_indices_storage = {} self.power_indices_storage = {}
def get_power_index(self, domain, distribution_strategy, def get_power_index(self, domain, distribution_strategy,
log=False, nbin=None, binbounds=None): logarithmic=False, nbin=None, binbounds=None):
key = (domain, distribution_strategy) key = (domain, distribution_strategy)
if key not in self.power_indices_storage: if key not in self.power_indices_storage:
self.power_indices_storage[key] = \ self.power_indices_storage[key] = \
PowerIndices(domain, distribution_strategy, PowerIndices(domain, distribution_strategy,
log=log, nbin=nbin, binbounds=binbounds) logarithmic=logarithmic,
nbin=nbin,
binbounds=binbounds)
power_indices = self.power_indices_storage[key] power_indices = self.power_indices_storage[key]
power_index = power_indices.get_index_dict(log=log, power_index = power_indices.get_index_dict(logarithmic=logarithmic,
nbin=nbin, nbin=nbin,
binbounds=binbounds) binbounds=binbounds)
return power_index return power_index
......
...@@ -26,7 +26,7 @@ from d2o.config import configuration as d2o_config ...@@ -26,7 +26,7 @@ from d2o.config import configuration as d2o_config
class PowerIndices(object): class PowerIndices(object):
def __init__(self, domain, distribution_strategy, def __init__(self, domain, distribution_strategy,
log=False, nbin=None, binbounds=None): logarithmic=False, nbin=None, binbounds=None):
""" """
Returns an instance of the PowerIndices class. Given the shape and Returns an instance of the PowerIndices class. Given the shape and
the density of a underlying rectangular grid it provides the user the density of a underlying rectangular grid it provides the user
...@@ -42,7 +42,7 @@ class PowerIndices(object): ...@@ -42,7 +42,7 @@ class PowerIndices(object):
dgrid : tuple, list, ndarray dgrid : tuple, list, ndarray
Array-like object which specifies the step-width of the Array-like object which specifies the step-width of the
underlying grid underlying grid
log : bool *optional* logarithmic : bool *optional*
Flag specifying if the binning of the default indices is Flag specifying if the binning of the default indices is
performed on logarithmic scale. performed on logarithmic scale.
nbin : integer *optional* nbin : integer *optional*
...@@ -59,7 +59,7 @@ class PowerIndices(object): ...@@ -59,7 +59,7 @@ class PowerIndices(object):
# Initialize the dictionary which stores all individual index-dicts # Initialize the dictionary which stores all individual index-dicts
self.global_dict = {} self.global_dict = {}
# Set self.default_parameters # Set self.default_parameters
self.set_default(config_dict={'log': log, self.set_default(config_dict={'logarithmic': logarithmic,
'nbin': nbin, 'nbin': nbin,
'binbounds': binbounds}) 'binbounds': binbounds})
...@@ -88,7 +88,7 @@ class PowerIndices(object): ...@@ -88,7 +88,7 @@ class PowerIndices(object):
Parameters Parameters
---------- ----------
log : bool logarithmic : bool
Flag specifying if the binning is performed on logarithmic Flag specifying if the binning is performed on logarithmic
scale. scale.
nbin : integer nbin : integer
...@@ -113,24 +113,25 @@ class PowerIndices(object): ...@@ -113,24 +113,25 @@ class PowerIndices(object):
return self._cast_config_helper(**temp_config_dict) return self._cast_config_helper(**temp_config_dict)
else: else:
defaults = self.default_parameters defaults = self.default_parameters
temp_log = kwargs.get("log", defaults['log']) temp_logarithmic = kwargs.get("logarithmic",
defaults['logarithmic'])
temp_nbin = kwargs.get("nbin", defaults['nbin']) temp_nbin = kwargs.get("nbin", defaults['nbin'])
temp_binbounds = kwargs.get("binbounds", defaults['binbounds']) temp_binbounds = kwargs.get("binbounds", defaults['binbounds'])
return self._cast_config_helper(log=temp_log, return self._cast_config_helper(logarithmic=temp_logarithmic,
nbin=temp_nbin, nbin=temp_nbin,
binbounds=temp_binbounds) binbounds=temp_binbounds)
def _cast_config_helper(self, log, nbin, binbounds): def _cast_config_helper(self, logarithmic, nbin, binbounds):
""" """
internal helper function which sets the defaults for the internal helper function which sets the defaults for the
_cast_config function _cast_config function
""" """
try: try:
temp_log = bool(log) temp_logarithmic = bool(logarithmic)
except(TypeError): except(TypeError):
temp_log = False temp_logarithmic = False
try: try:
temp_nbin = int(nbin) temp_nbin = int(nbin)
...@@ -142,7 +143,7 @@ class PowerIndices(object): ...@@ -142,7 +143,7 @@ class PowerIndices(object):
except(TypeError): except(TypeError):
temp_binbounds = None temp_binbounds = None
temp_dict = {"log": temp_log, temp_dict = {"logarithmic": temp_logarithmic,
"nbin": temp_nbin, "nbin": temp_nbin,
"binbounds": temp_binbounds} "binbounds": temp_binbounds}
return temp_dict return temp_dict
...@@ -158,7 +159,7 @@ class PowerIndices(object): ...@@ -158,7 +159,7 @@ class PowerIndices(object):
store : bool store : bool
Flag specifying if the calculated index dictionary should be Flag specifying if the calculated index dictionary should be
stored in the global_dict for future use. stored in the global_dict for future use.
log : bool logarithmic : bool
Flag specifying if the binning is performed on logarithmic Flag specifying if the binning is performed on logarithmic
scale. scale.
nbin : integer nbin : integer
...@@ -210,7 +211,7 @@ class PowerIndices(object): ...@@ -210,7 +211,7 @@ class PowerIndices(object):
""" """
# if no binning is requested, compute the indices, build the dict, # if no binning is requested, compute the indices, build the dict,
# and return it straight. # and return it straight.
if not config_dict["log"] and config_dict["nbin"] is None and \ if not config_dict["logarithmic"] and config_dict["nbin"] is None and \
config_dict["binbounds"] is None: config_dict["binbounds"] is None:
(temp_pindex, temp_kindex, temp_rho, temp_pundex) =\ (temp_pindex, temp_kindex, temp_rho, temp_pundex) =\
self._compute_indices(self.k_array) self._compute_indices(self.k_array)
...@@ -222,7 +223,7 @@ class PowerIndices(object): ...@@ -222,7 +223,7 @@ class PowerIndices(object):
# Get the unbinned indices # Get the unbinned indices
temp_unbinned_indices = self.get_index_dict(nbin=None, temp_unbinned_indices = self.get_index_dict(nbin=None,
binbounds=None, binbounds=None,
log=False, logarithmic=False,
store=False) store=False)
# Bin them # Bin them
(temp_pindex, temp_kindex, temp_rho, temp_pundex) = \ (temp_pindex, temp_kindex, temp_rho, temp_pundex) = \
...@@ -344,7 +345,7 @@ class PowerIndices(object): ...@@ -344,7 +345,7 @@ class PowerIndices(object):
Array of all k-vector lengths. Array of all k-vector lengths.
rho : ndarray rho : ndarray
Degeneracy factor of the individual k-vectors. Degeneracy factor of the individual k-vectors.
log : bool logarithmic : bool
Flag specifying if the binning is performed on logarithmic Flag specifying if the binning is performed on logarithmic
scale. scale.
nbin : integer nbin : integer
...@@ -361,7 +362,7 @@ class PowerIndices(object): ...@@ -361,7 +362,7 @@ class PowerIndices(object):
""" """
# Cast the given config # Cast the given config
temp_config_dict = self._cast_config(**kwargs) temp_config_dict = self._cast_config(**kwargs)
log = temp_config_dict['log'] logarithmic = temp_config_dict['logarithmic']
nbin = temp_config_dict['nbin'] nbin = temp_config_dict['nbin']
binbounds = temp_config_dict['binbounds'] binbounds = temp_config_dict['binbounds']
...@@ -375,9 +376,9 @@ class PowerIndices(object): ...@@ -375,9 +376,9 @@ class PowerIndices(object):
binbounds = np.sort(binbounds) binbounds = np.sort(binbounds)
# equal binning # equal binning
else: else:
if(log is None): if(logarithmic is None):
log = False logarithmic = False
if(log): if(logarithmic):
k = np.r_[0, np.log(kindex[1:])] k = np.r_[0, np.log(kindex[1:])]
else: else:
k = kindex k = kindex
...@@ -391,7 +392,7 @@ class PowerIndices(object): ...@@ -391,7 +392,7 @@ class PowerIndices(object):
dk = (k[-1] - 0.5 * (k[2] + k[1])) / (nbin - 2.5) dk = (k[-1] - 0.5 * (k[2] + k[1])) / (nbin - 2.5)
binbounds = np.r_[0.5 * (3 * k[1] - k[2]), binbounds = np.r_[0.5 * (3 * k[1] - k[2]),
0.5 * (k[1] + k[2]) + dk * np.arange(nbin - 2)] 0.5 * (k[1] + k[2]) + dk * np.arange(nbin - 2)]
if(log): if(logarithmic):
binbounds = np.exp(binbounds) binbounds = np.exp(binbounds)
# reordering # reordering
reorder = np.searchsorted(binbounds, kindex) reorder = np.searchsorted(binbounds, kindex)
......
...@@ -27,34 +27,76 @@ from nifty.spaces.rg_space import RGSpace ...@@ -27,34 +27,76 @@ from nifty.spaces.rg_space import RGSpace
class PowerSpace(Space): class PowerSpace(Space):
""" NIFTY class for spaces of power spectra.
Parameters
----------
harmonic_partner : Space
The harmonic Space of which this is the power space.
distribution_strategy : str *optional*
The distribution strategy used for the distributed_data_objects
derived from this PowerSpace, e.g. the pindex.
(default : 'not')
logarithmic : bool *optional*
True if logarithmic binning should be used (default : False).
nbin : {int, None} *optional*
The number of bins that should be used for power spectrum binning
(default : None).
if nbin == None, then nbin is set to the length of kindex.
binbounds : {list, array-like} *optional*
Array-like inner boundaries of the used bins of the default
indices.
(default : None)
if binbounds == None :
Calculates the bounds from the kindex while applying the
logarithmic and nbin keywords.
Attributes
----------
pindex : distributed_data_object
TODO add description
kindex : numpy.ndarray
TODO add description
pundex : numpy.ndarray
TODO add description
rho : numpy.ndarray
The amount of k-modes that get mapped to one power bin is given by
rho.
Notes
-----
A power space is the result of a projection of a harmonic space where
k-modes of equal length get mapped to one power index.
"""
# ---Overwritten properties and methods--- # ---Overwritten properties and methods---
def __init__(self, harmonic_domain=RGSpace((1,)), def __init__(self, harmonic_partner=RGSpace((1,)),
distribution_strategy='not', distribution_strategy='not',
log=False, nbin=None, binbounds=None): logarithmic=False, nbin=None, binbounds=None):
super(PowerSpace, self).__init__() super(PowerSpace, self).__init__()
self._ignore_for_hash += ['_pindex', '_kindex', '_rho', '_pundex', self._ignore_for_hash += ['_pindex', '_kindex', '_rho', '_pundex',
'_k_array'] '_k_array']
if not isinstance(harmonic_domain, Space): if not isinstance(harmonic_partner, Space):
raise ValueError( raise ValueError(
"harmonic_domain must be a Space.") "harmonic_partner must be a Space.")
if not harmonic_domain.harmonic: if not harmonic_partner.harmonic:
raise ValueError( raise ValueError(
"harmonic_domain must be a harmonic space.") "harmonic_partner must be a harmonic space.")
self._harmonic_domain = harmonic_domain self._harmonic_partner = harmonic_partner
power_index = PowerIndexFactory.get_power_index( power_index = PowerIndexFactory.get_power_index(
domain=self.harmonic_domain, domain=self.harmonic_partner,
distribution_strategy=distribution_strategy, distribution_strategy=distribution_strategy,
log=log, logarithmic=logarithmic,
nbin=nbin, nbin=nbin,
binbounds=binbounds) binbounds=binbounds)
config = power_index['config'] config = power_index['config']
self._log = config['log'] self._logarithmic = config['logarithmic']
self._nbin = config['nbin'] self._nbin = config['nbin']
self._binbounds = config['binbounds'] self._binbounds = config['binbounds']
...@@ -65,6 +107,28 @@ class PowerSpace(Space): ...@@ -65,6 +107,28 @@ class PowerSpace(Space):
self._k_array = power_index['k_array'] self._k_array = power_index['k_array']
def pre_cast(self, x, axes): def pre_cast(self, x, axes):
""" Casts power spectrum functions to discretized power spectra.
This function takes an array or a function. If it is an array it does
nothing, otherwise it interpretes the function as power spectrum and
evaluates it at every k-mode.
Parameters
----------
x : {array-like, function array-like -> array-like}
power spectrum given either in discretized form or implicitly as a
function
axes : tuple of ints
Specifies the axes of x which correspond to this space. For
explicifying the power spectrum function, this is ignored.
Returns
-------
array-like
discretized power spectrum
"""
if callable(x): if callable(x):
return x(self.kindex) return x(self.kindex)
else: else:
...@@ -91,9 +155,9 @@ class PowerSpace(Space): ...@@ -91,9 +155,9 @@ class PowerSpace(Space):
def copy(self): def copy(self):
distribution_strategy = self.pindex.distribution_strategy distribution_strategy = self.pindex.distribution_strategy
return self.__class__(harmonic_domain=self.harmonic_domain, return self.__class__(harmonic_partner=self.harmonic_partner,
distribution_strategy=distribution_strategy, distribution_strategy=distribution_strategy,
log=self.log, logarithmic=self.logarithmic,
nbin=self.nbin, nbin=self.nbin,
binbounds=self.binbounds) binbounds=self.binbounds)
...@@ -127,39 +191,61 @@ class PowerSpace(Space): ...@@ -127,39 +191,61 @@ class PowerSpace(Space):
# ---Added properties and methods--- # ---Added properties and methods---
@property @property
def harmonic_domain(self): def harmonic_partner(self):
return self._harmonic_domain """ Returns the Space of which this is the power space.
"""
return self._harmonic_partner
@property @property
def log(self): def logarithmic(self):
return self._log """ Returns True if logarithmic binning is used.
"""
return self._logarithmic
@property @property
def nbin(self): def nbin(self):
""" Returns the number of power bins if specfied during initialization.
"""
return self._nbin return self._nbin
@property @property
def binbounds(self): def binbounds(self):
""" Inner boundaries of the used bins if specfied during initialization.
"""
return self._binbounds return self._binbounds
@property @property
def pindex(self): def pindex(self):
""" A distributed_data_objects having the shape of the harmonic partner
space containing the indices of the power bin a pixel belongs to.
"""
return self._pindex return self._pindex
@property @property
def kindex(self): def kindex(self):
""" Sorted array of all k-modes.
"""
return self._kindex return self._kindex
@property @property
def rho(self): def rho(self):
"""Degeneracy factor of the individual k-vectors.
"""
return self._rho return self._rho
@property @property
def pundex(self): def pundex(self):
""" An array for which the n-th entry gives the flat index of the
first occurence of a k-vector with length==kindex[n] in the
k_array.
"""
return self._pundex return self._pundex
@property @property
def k_array(self): def k_array(self):
""" An array containing distances to the grid center (i.e. zero-mode)
for every k-mode in the grid of the harmonic partner space.
"""
return self._k_array return self._k_array
# ---Serialization--- # ---Serialization---
...@@ -168,13 +254,13 @@ class PowerSpace(Space): ...@@ -168,13 +254,13 @@ class PowerSpace(Space):
hdf5_group['kindex'] = self.kindex hdf5_group['kindex'] = self.kindex
hdf5_group['rho'] = self.rho hdf5_group['rho'] = self.rho
hdf5_group['pundex'] = self.pundex hdf5_group['pundex'] = self.pundex
hdf5_group['log'] = self.log hdf5_group['logarithmic'] = self.logarithmic
# Store nbin as string, since it can be None # Store nbin as string, since it can be None
hdf5_group.attrs['nbin'] = str(self.nbin) hdf5_group.attrs['nbin'] = str(self.nbin)
hdf5_group.attrs['binbounds'] = str(self.binbounds) hdf5_group.attrs['binbounds'] = str(self.binbounds)
return { return {
'harmonic_domain': self.harmonic_domain, 'harmonic_partner': self.harmonic_partner,
'pindex': self.pindex, 'pindex': self.pindex,
'k_array': self.k_array 'k_array': self.k_array
} }
...@@ -188,8 +274,9 @@ class PowerSpace(Space): ...@@ -188,8 +274,9 @@ class PowerSpace(Space):
# call instructor so that classes are properly setup # call instructor so that classes are properly setup
super(PowerSpace, new_ps).__init__() super(PowerSpace, new_ps).__init__()
# set all values # set all values
new_ps._harmonic_domain = repository.get('harmonic_domain', hdf5_group) new_ps._harmonic_partner = repository.get('harmonic_partner',
new_ps._log = hdf5_group['log'][()] hdf5_group)
new_ps._logarithmic = hdf5_group['logarithmic'][()]
exec('new_ps._nbin = ' + hdf5_group.attrs['nbin']) exec('new_ps._nbin = ' + hdf5_group.attrs['nbin'])
exec('new_ps._binbounds = ' + hdf5_group.attrs['binbounds']) exec('new_ps._binbounds = ' + hdf5_group.attrs['binbounds'])
......
...@@ -28,8 +28,8 @@ from nifty import PowerSpace, RGSpace, Space ...@@ -28,8 +28,8 @@ from nifty import PowerSpace, RGSpace, Space
from types import NoneType from types import NoneType
from test.common import expand from test.common import expand