Commit addc84e3 authored by Reimar H Leike's avatar Reimar H Leike
Browse files

Changed RGSpace fft smoothing kernel to be Gaussian, added some

Docstrings
parent 68823ce1
Pipeline #12225 failed with stage
in 4 minutes and 30 seconds
......@@ -40,6 +40,15 @@ class DomainObject(Versionable, Loggable, object):
return result_hash
def __eq__(self, x):
"""Checks if this domain_object represents the same thing as another domain_object.
Parameters
----------
x: domain_object
The domain_object it is compared to.
Returns
-------
bool : True if they this and x represent the same thing.
"""
if isinstance(x, type(self)):
for key in vars(self).keys():
item1 = vars(self)[key]
......@@ -57,23 +66,76 @@ class DomainObject(Versionable, Loggable, object):
@abc.abstractproperty
def shape(self):
"""Returns the shape of the underlying array-like object.
Returns
-------
(int, tuple) : A tuple representing the shape of the underlying array-like object
Raises
------
NotImplementedError : If it is called for an abstract class, all non-abstract child-classes should
implement this.
"""
raise NotImplementedError(
"There is no generic shape for DomainObject.")
@abc.abstractproperty
def dim(self):
"""Returns the number of pixel-dimensions the object has.
Returns
-------
int : An Integer representing the number of pixels the discretized space has.
Raises
------
NotImplementedError : If it is called for an abstract class, all non-abstract child-classes should
implement this.
"""
raise NotImplementedError(
"There is no generic dim for DomainObject.")
@abc.abstractmethod
def weight(self, x, power=1, axes=None, inplace=False):
""" Weights a field living on this domain with a specified amount of volume-weights.
Weights hereby refer to integration weights, as they appear in discretized integrals.
Per default, this function mutliplies each bin of the field x by its volume, which lets
it behave like a density (top form). However, different powers of the volume can be applied
with the power parameter. The axes parameter specifies which of the field indices represent this
domain.
Parameters
----------
x : Field
A field with this space as domain to be weighted.
power : int, *optional*
The power to which the volume-weight is raised.
(default: 1).
axes : {int, tuple}, *optional*
Specifies the axes of x which represent this domain.
(default: None).
If axes==None:
weighting is applied with respect to all axes
inplace : bool, *optional*
If this is True, the weighting is done on the values of x,
if it is False, x is not modified and this method returns a
weighted copy of x
(default: False).
Returns
-------
Field
A weighted version of x, with volume-weights raised to power.
Raises
------
NotImplementedError : If it is called for an abstract class, all non-abstract child-classes should
implement this.
"""
raise NotImplementedError(
"There is no generic weight-method for DomainObject.")
def pre_cast(self, x, axes=None):
# FIXME This does nothing and non of the children override this. Why does this exist?!
return x
def post_cast(self, x, axes=None):
# FIXME This does nothing and non of the children override this. Why does this exist?!
return x
# ---Serialization---
......
......@@ -43,8 +43,8 @@ class GLSpace(Space):
----------
nlat : int
Number of latitudinal bins, or rings.
nlon : int
Number of longitudinal bins.
nlon : int, *optional*
Number of longitudinal bins (default: ``2*nlat - 1``).
See Also
--------
......@@ -82,9 +82,7 @@ class GLSpace(Space):
Raises
------
ValueError
If input `nlat` is invalid.
ImportError
If the pyHealpix module is not available
If input `nlat` or `nlon` is invalid.
"""
if 'pyHealpix' not in gdi:
......@@ -100,6 +98,12 @@ class GLSpace(Space):
@property
def harmonic(self):
"""True if this can be regarded as a harmonic space.
Returns
-------
bool : False
Always returns False as the GLSpace cannot be regarded as harmonic space.
"""
return False
@property
......@@ -119,6 +123,39 @@ class GLSpace(Space):
nlon=self.nlon)
def weight(self, x, power=1, axes=None, inplace=False):
""" Weights a field living on this space with a specified amount of volume-weights.
Weights hereby refer to integration weights, as they appear in discretized integrals.
Per default, this function mutliplies each bin of the field x by its volume, which lets
it behave like a density (top form). However, different powers of the volume can be applied
with the power parameter. If only certain axes are specified via the axes parameter,
the weights are only applied with respect to these dimensions, yielding an object that
behaves like a lower degree form.
Parameters
----------
x : Field
A field with this space as domain to be weighted.
power : int, *optional*
The power to which the volume-weight is raised.
(default: 1).
axes : {int, tuple}, *optional*
Specifies for which axes the weights should be applied.
(default: None).
If axes==None:
weighting is applied with respect to all axes
inplace : bool, *optional*
If this is True, the weighting is done on the values of x,
if it is False, x is not modified and this method returns a
weighted copy of x
(default: False).
Returns
-------
Field
A weighted version of x, with volume-weights raised to power.
"""
nlon = self.nlon
nlat = self.nlat
vol = pyHealpix.GL_weights(nlat, nlon) ** power
......@@ -141,9 +178,23 @@ class GLSpace(Space):
return result_x
def get_distance_array(self, distribution_strategy):
"""This should not be used, it just raises an error when called.
Raises
------
NotImplementedError
Always when called.
"""
raise NotImplementedError
def get_fft_smoothing_kernel_function(self, sigma):
"""This should not be used, it just raises an error when called.
Raises
------
NotImplementedError
Always when called.
"""
raise NotImplementedError
# ---Added properties and methods---
......
......@@ -60,7 +60,7 @@ class HPSpace(Space):
def __init__(self, nside):
"""
Sets the attributes for a HPSpace class instance.
Sets the attributes for a hp_space class instance.
Parameters
----------
......@@ -102,9 +102,43 @@ class HPSpace(Space):
return 4 * np.pi
def copy(self):
"""Returns a copied version of this HPSpace.
Returns
-------
HPSpace : A copy of this object.
"""
return self.__class__(nside=self.nside)
def weight(self, x, power=1, axes=None, inplace=False):
""" Weights a field living on this space with a specified amount of volume-weights.
Weights hereby refer to integration weights, as they appear in discretized integrals.
Per default, this function mutliplies each bin of the field x by its volume, which lets
it behave like a density (top form). However, different powers of the volume can be applied
with the power parameter.
Parameters
----------
x : Field
A field with this space as domain to be weighted.
power : int, *optional*
The power to which the volume-weight is raised.
(default: 1).
axes : {int, tuple}, *optional*
This should not be used. It does nothing.
inplace : bool, *optional*
If this is True, the weighting is done on the values of x,
if it is False, x is not modified and this method returns a
weighted copy of x
(default: False).
Returns
-------
Field
A weighted version of x, with volume-weights raised to power.
"""
weight = ((4 * np.pi) / (12 * self.nside**2))**power
if inplace:
......@@ -116,9 +150,23 @@ class HPSpace(Space):
return result_x
def get_distance_array(self, distribution_strategy):
"""This should not be used, it just raises an error when called.
Raises
------
NotImplementedError
Always when called.
"""
raise NotImplementedError
def get_fft_smoothing_kernel_function(self, sigma):
"""This should not be used, it just raises an error when called.
Raises
------
NotImplementedError
Always when called.
"""
raise NotImplementedError
# ---Added properties and methods---
......
......@@ -43,17 +43,19 @@ class LMSpace(Space):
Maximum :math:`\ell`-value up to which the spherical harmonics
coefficients are to be used.
Notes:
------
This implementation implicitly sets the mmax parameter to lmax.
See Also
--------
hp_space : A class for the HEALPix discretization of the sphere [#]_.
gl_space : A class for the Gauss-Legendre discretization of the
sphere [#]_.
Notes
-----
Hermitian symmetry, i.e. :math:`a_{\ell -m} = \overline{a}_{\ell m}` is
always assumed for the spherical harmonics components, i.e. only fields
on the two-sphere with real-valued representations in position space
can be handled.
References
----------
.. [#] K.M. Gorski et al., 2005, "HEALPix: A Framework for
......@@ -77,6 +79,11 @@ class LMSpace(Space):
Returns
-------
None.
Raises
------
ValueError
If lmax is negative.
"""
......@@ -117,15 +124,65 @@ class LMSpace(Space):
return np.float64(self.dim)
def copy(self):
"""Returns a copied version of this LMSpace.
Returns
-------
LMSpace : A copy of this object.
"""
return self.__class__(lmax=self.lmax)
def weight(self, x, power=1, axes=None, inplace=False):
""" Weights a field living on this space with a specified amount of volume-weights.
Weights hereby refer to integration weights, as they appear in discretized integrals.
Per default, this function mutliplies each bin of the field x by its volume, which lets
it behave like a density (top form). All volume-weights are 1, thus nothing happens.
Parameters
----------
x : Field
A field with this space as domain to be weighted.
power : int, *optional*
The power to which the volume-weight is raised. It does nothing.
(default: 1).
axes : {int, tuple}, *optional*
This should not be used. It does nothing.
inplace : bool, *optional*
If this is True, the weighting is done on the values of x,
if it is False, x is not modified and this method returns a
weighted copy of x
(default: False).
Returns
-------
Field
x or a copy of x.
"""
if inplace:
return x
else:
return x.copy()
def get_distance_array(self, distribution_strategy):
"""Returns the distance of the bins to zero.
Calculates an 2-dimensional array with its entries being the
lengths of the k-vectors from the zero point of the grid.
Parameters
----------
distribution_strategy :
Returns
-------
nkdict : distributed_data_object
Raises
------
ValueError
The distribution_strategy is neither slicing nor not.
"""
dists = arange(start=0, stop=self.shape[0],
distribution_strategy=distribution_strategy)
......@@ -144,6 +201,7 @@ class LMSpace(Space):
return res
def get_fft_smoothing_kernel_function(self, sigma):
# FIXME why x(x+1) ? add reference to paper!
return lambda x: np.exp(-0.5 * x * (x + 1) * sigma**2)
# ---Added properties and methods---
......
......@@ -16,13 +16,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import numpy as np
from d2o import distributed_data_object,\
STRATEGIES as DISTRIBUTION_STRATEGIES
from d2o.config import dependency_injector as d2o_di
from d2o.config import configuration as d2o_config
class PowerIndices(object):
def __init__(self, domain, distribution_strategy,
......@@ -313,7 +312,8 @@ class PowerIndices(object):
# Store the individual pundices in the local_pundex array
local_pundex[temp_uniqued_pindex] = local_temp_pundex
# Extract the MPI module from the global_pindex d2o
MPI = d2o_di[d2o_config['mpi_module']]
MPI_name = global_pindex.comm.__class__.__module__
MPI = sys.modules[MPI_name]
# Use Allreduce to find the first occurences/smallest pundices
global_pindex.comm.Allreduce(local_pundex,
global_pundex,
......
......@@ -101,6 +101,24 @@ class RGSpace(Space):
def hermitian_decomposition(self, x, axes=None,
preserve_gaussian_variance=False):
"""Separates the hermitian and antihermitian part of a field.
This is a function which is called by the field in order to separate itself for
each of its domains.
Parameters
----------
x: Field
Field to be decomposed.
axes: {int, tuple}, *optional*
Specifies which indices of the field belongs to this RGSpace. If None, it
takes the first dimensions of the field.
(default: None)
preserve_gaussian_variance: bool, *optional*
(default: False)
"""
# compute the hermitian part
flipped_x = self._hermitianize_inverter(x, axes=axes)
flipped_x = flipped_x.conjugate()
......@@ -190,12 +208,50 @@ class RGSpace(Space):
return self.dim * reduce(lambda x, y: x*y, self.distances)
def copy(self):
"""Returns a copied version of this RGSpace.
Returns
-------
RGSpace : A copy of this object.
"""
return self.__class__(shape=self.shape,
zerocenter=self.zerocenter,
distances=self.distances,
harmonic=self.harmonic)
def weight(self, x, power=1, axes=None, inplace=False):
""" Weights a field living on this space with a specified amount of volume-weights.
Weights hereby refer to integration weights, as they appear in discretized integrals.
Per default, this function mutliplies each bin of the field x by its volume, which lets
it behave like a density (top form). However, different powers of the volume can be applied
with the power parameter. If only certain axes are specified via the axes parameter,
the weights are only applied with respect to these dimensions, yielding an object that
behaves like a lower degree form.
Parameters
----------
x : Field
A field with this space as domain to be weighted.
power : int, *optional*
The power to which the volume-weight is raised.
(default: 1).
axes : {int, tuple}, *optional*
Specifies for which axes the weights should be applied.
(default: None).
If axes==None:
weighting is applied with respect to all axes
inplace : bool, *optional*
If this is True, the weighting is done on the values of x,
if it is False, x is not modified and this method returns a
weighted copy of x
(default: False).
Returns
-------
Field
A weighted version of x, with volume-weights raised to power.
"""
weight = reduce(lambda x, y: x*y, self.distances)**power
if inplace:
x *= weight
......@@ -205,19 +261,25 @@ class RGSpace(Space):
return result_x
def get_distance_array(self, distribution_strategy):
"""
Calculates an n-dimensional array with its entries being the
lengths of the k-vectors from the zero point of the grid.
MR FIXME: Since this is about k-vectors, it might make sense to
throw NotImplementedError if harmonic==False.
Parameters
----------
None : All information is taken from the parent object.
Returns
-------
nkdict : distributed_data_object
"""Returns the distance of the bins to zero.
Calculates an n-dimensional array with its entries being the
lengths of the k-vectors from the zero point of the grid.
MR FIXME: Since this is about k-vectors, it might make sense to
throw NotImplementedError if harmonic==False.
Parameters
----------
None : All information is taken from the parent object.
Returns
-------
nkdict : distributed_data_object
Raises
------
ValueError
The distribution_strategy is neither slicing nor not.
"""
shape = self.shape
# prepare the distributed_data_object
......@@ -263,11 +325,12 @@ class RGSpace(Space):
dists = np.sqrt(dists)
return dists
def get_fft_smoothing_kernel_function(self, sigma):
def get_fft_smoothing_kernel_function(self, sigma):
if sigma is None:
sigma = np.sqrt(2) * np.max(self.distances)
return lambda x: np.exp(-2. * np.pi**2 * x**2 * sigma**2)
return lambda x: np.exp(-0.5 * np.pi**2 * x**2 * sigma**2)
# ---Added properties and methods---
......
......@@ -16,49 +16,146 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
.. __ ____ __
.. /__/ / _/ / /_
.. __ ___ __ / /_ / _/ __ __
.. / _ | / / / _/ / / / / / /
.. / / / / / / / / / /_ / /_/ /
.. /__/ /__/ /__/ /__/ \___/ \___ / core
.. /______/
.. The NIFTY project homepage is http://www.mpa-garching.mpg.de/ift/nifty/
NIFTY [#]_, "Numerical Information Field Theory", is a versatile
library designed to enable the development of signal inference algorithms
that operate regardless of the underlying spatial grid and its resolution.
Its object-oriented framework is written in Python, although it accesses
libraries written in Cython, C++, and C for efficiency.
NIFTY offers a toolkit that abstracts discretized representations of
continuous spaces, fields in these spaces, and operators acting on fields
into classes. Thereby, the correct normalization of operations on fields is
taken care of automatically without concerning the user. This allows for an
abstract formulation and programming of inference algorithms, including
those derived within information field theory. Thus, NIFTY permits its user
to rapidly prototype algorithms in 1D and then apply the developed code in
higher-dimensional settings of real world problems. The set of spaces on
which NIFTY operates comprises point sets, n-dimensional regular grids,
spherical spaces, their harmonic counterparts, and product spaces
constructed as combinations of those.
References
----------
.. [#] Selig et al., "NIFTY -- Numerical Information Field Theory --
a versatile Python library for signal inference",
`A&A, vol. 554, id. A26 <http://dx.doi.org/10.1051/0004-6361/201321236>`_,
2013; `arXiv:1301.4499 <http://www.arxiv.org/abs/1301.4499>`_
Class & Feature Overview
------------------------
The NIFTY library features three main classes: **spaces** that represent
certain grids, **fields** that are defined on spaces, and **operators**
that apply to fields.
.. Overview of all (core) classes:
..
.. - switch
.. - notification
.. - _about
.. - random
.. - space
.. - point_space
.. - rg_space
.. - lm_space
.. - gl_space
.. - hp_space
.. - nested_space
.. - field
.. - operator
.. - diagonal_operator
.. - power_operator
.. - projection_operator
.. - vecvec_operator
.. - response_operator
.. - probing
.. - trace_probing
.. - diagonal_probing
Overview of the main classes and functions:
.. automodule:: nifty
- :py:class:`space`
- :py:class:`point_space`
- :py:class:`rg_space`
- :py:class:`lm_space`
- :py:class:`gl_space`
- :py:class:`hp_space`
- :py:class:`nested_space`
- :py:class:`field`
- :py:class:`operator`
- :py:class:`diagonal_operator`
- :py:class:`power_operator`
- :py:class:`projection_operator`
- :py:class:`vecvec_operator`
- :py:class:`response_operator`
.. currentmodule:: nifty.nifty_tools
- :py:class:`invertible_operator`
- :py:class:`propagator_operator`
.. currentmodule:: nifty.nifty_explicit
- :py:class:`explicit_operator`
.. automodule:: nifty
- :py:class:`probing`
- :py:class:`trace_probing`
- :py:class:`diagonal_probing`
.. currentmodule:: nifty.nifty_explicit