domain_object.py 6.68 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
# 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/>.
Theo Steininger's avatar
Theo Steininger committed
13
14
15
16
17
#
# Copyright(C) 2013-2017 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik
# and financially supported by the Studienstiftung des deutschen Volkes.
18

Martin Reinecke's avatar
Martin Reinecke committed
19
from __future__ import division
20
import abc
Martin Reinecke's avatar
Martin Reinecke committed
21
from .nifty_meta import NiftyMeta
22
23
24

from keepers import Loggable,\
                    Versionable
Martin Reinecke's avatar
Martin Reinecke committed
25
from future.utils import with_metaclass
26
27


28
29
class DomainObject(with_metaclass(
        NiftyMeta, type('NewBase', (Versionable, Loggable, object), {}))):
30
    """The abstract class that can be used as a domain for a field.
31
32
33
34

    This holds all the information and functionality a field needs to know
    about its domain and how the data of the field are stored.

35
36
37
    Attributes
    ----------
    dim : int
38
        Number of pixel-dimensions of the underlying data object.
39
    shape : tuple
40
41
42
        Shape of the array that stores the degrees of freedom for any field
        on this domain.

43
    """
44

Martin Reinecke's avatar
Martin Reinecke committed
45
    def __init__(self):
46
        self._needed_for_hash = []
47

48
49
50
51
    @abc.abstractmethod
    def __repr__(self):
        raise NotImplementedError

52
53
54
    def __hash__(self):
        # Extract the identifying parts from the vars(self) dict.
        result_hash = 0
55
56
        for key in self._needed_for_hash:
            result_hash ^= hash(vars(self)[key])
57
58
59
        return result_hash

    def __eq__(self, x):
Theo Steininger's avatar
Theo Steininger committed
60
61
        """ Checks if two domain_objects are equal.

62
63
64
        Parameters
        ----------
        x: domain_object
Theo Steininger's avatar
Theo Steininger committed
65
66
            The domain_object `self` is compared to.

67
68
        Returns
        -------
Theo Steininger's avatar
Theo Steininger committed
69
70
71
        bool
            True if `self` and x describe the same manifold.

72
        """
73
        if self is x:  # shortcut for simple case
74
            return True
75
        if not isinstance(x, type(self)):
76
            return False
77
78
79
80
        for key in self._needed_for_hash:
            if vars(self)[key] != vars(x)[key]:
                return False
        return True
81
82
83
84
85
86

    def __ne__(self, x):
        return not self.__eq__(x)

    @abc.abstractproperty
    def shape(self):
Theo Steininger's avatar
Theo Steininger committed
87
        """ The domain-object's shape contribution to the underlying array.
Theo Steininger's avatar
Theo Steininger committed
88

89
90
        Returns
        -------
Theo Steininger's avatar
Theo Steininger committed
91
92
93
        tuple of ints
            The shape of the underlying array-like object.

94
95
        Raises
        ------
Theo Steininger's avatar
Theo Steininger committed
96
97
98
        NotImplementedError
            If called for this abstract class.

99
        """
Theo Steininger's avatar
Theo Steininger committed
100

101
102
103
104
105
        raise NotImplementedError(
            "There is no generic shape for DomainObject.")

    @abc.abstractproperty
    def dim(self):
Theo Steininger's avatar
Theo Steininger committed
106
107
        """ Returns the number of pixel-dimensions the object has.

108
109
        Returns
        -------
Theo Steininger's avatar
Theo Steininger committed
110
111
112
113
        int
            An Integer representing the number of pixels the discretized
            manifold has.

114
115
        Raises
        ------
Theo Steininger's avatar
Theo Steininger committed
116
117
118
        NotImplementedError
            If called for this abstract class.

119
        """
Theo Steininger's avatar
Theo Steininger committed
120

121
122
123
        raise NotImplementedError(
            "There is no generic dim for DomainObject.")

124
125
    @abc.abstractmethod
    def weight(self, x, power=1, axes=None, inplace=False):
Theo Steininger's avatar
Theo Steininger committed
126
127
128
129
130
131
132
133
        """ Weights the field on this domain with the space's 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 array's indices correspond to this domain.
134
135
136

        Parameters
        ----------
Theo Steininger's avatar
Theo Steininger committed
137
138
        x : distributed_data_object
            The fields data array.
139
        power : int, *optional*
Theo Steininger's avatar
Theo Steininger committed
140
            The power to which the volume-weight is raised (default: 1).
141
        axes : {int, tuple}, *optional*
Theo Steininger's avatar
Theo Steininger committed
142
            Specifies the axes of x which represent this domain
143
144
145
146
147
            (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,
Theo Steininger's avatar
Theo Steininger committed
148
149
150
            if it is False, x is not modified and this method returns a
            weighted copy of x (default: False).

151
152
        Returns
        -------
Theo Steininger's avatar
Theo Steininger committed
153
154
155
156
        distributed_data_object
            A weighted version of x, with volume-weights raised to the
            given power.

157
158
        Raises
        ------
Theo Steininger's avatar
Theo Steininger committed
159
160
161
        NotImplementedError
            If called for this abstract class.

162
        """
163
164
165
        raise NotImplementedError(
            "There is no generic weight-method for DomainObject.")

Theo Steininger's avatar
Theo Steininger committed
166
167
168
    def pre_cast(self, x, axes):
        """ Casts input for Field.val before Field performs the cast.

169
170
171
        Parameters
        ----------
        x : {array-like, castable}
Theo Steininger's avatar
Theo Steininger committed
172
173
174
175
            an array-like object or anything that can be cast to arrays.
        axes : tuple of ints
            Specifies the axes of x which correspond to this domain.

176
177
        Returns
        -------
Theo Steininger's avatar
Theo Steininger committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
        {array-like, castable}
            Processed input where casting that needs Space-specific knowledge
            (for example location of pixels on the manifold) was performed.


        See Also
        --------
        post_cast

        Notes
        -----
            Usually returns x, except if a power spectrum is given to a
            PowerSpace, where this spectrum is evaluated at the power indices.

192
        """
Theo Steininger's avatar
Theo Steininger committed
193

194
195
        return x

Theo Steininger's avatar
Theo Steininger committed
196
197
198
    def post_cast(self, x, axes):
        """ Performs casting operations that are done after Field's cast.

199
200
201
202
        Parameters
        ----------
        x : {array-like, castable}
            an array-like object or anything that can be cast to arrays.
Theo Steininger's avatar
Theo Steininger committed
203
204
205
        axes : tuple of ints
            Specifies the axes of x which correspond to this domain.

206
207
        See Also
        --------
Theo Steininger's avatar
Theo Steininger committed
208
209
        pre_cast

210
211
        Returns
        -------
Theo Steininger's avatar
Theo Steininger committed
212
213
214
215
        distributed_data_object
            Processed input where casting that needs Space-specific knowledge
            (for example location of pixels on the manifold) was performed.

216
        """
Theo Steininger's avatar
Theo Steininger committed
217

218
219
220
221
222
223
224
225
226
        return x

    # ---Serialization---

    def _to_hdf5(self, hdf5_group):
        return None

    @classmethod
    def _from_hdf5(cls, hdf5_group, repository):
Martin Reinecke's avatar
Martin Reinecke committed
227
        result = cls()
228
        return result