line_energy.py 4.11 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 print_function
20
21


22
class LineEnergy(object):
23
24
25
26
    """ Evaluates an underlying Energy along a certain line direction.

    Given an Energy class and a line direction, its position is parametrized by
    a scalar step size along the descent direction relative to a zero point.
27
28
29

    Parameters
    ----------
30
    line_position : float
Martin Reinecke's avatar
Martin Reinecke committed
31
        Defines the full spatial position of this energy via
32
        self.energy.position = zero_point + line_position*line_direction
Jakob Knollmueller's avatar
Jakob Knollmueller committed
33
    energy : Energy
34
35
        The Energy object which will be evaluated along the given direction.
    line_direction : Field
Martin Reinecke's avatar
Martin Reinecke committed
36
37
38
39
40
        Direction used for line evaluation. Does not have to be normalized.
    offset :  float *optional*
        Indirectly defines the zero point of the line via the equation
        energy.position = zero_point + offset*line_direction
        (default : 0.).
41
42
43

    Attributes
    ----------
44
    line_position : float
45
        The position along the given line direction relative to the zero point.
46
    value : float
Martin Reinecke's avatar
Martin Reinecke committed
47
        The value of the energy functional at the given position
48
    directional_derivative : float
Martin Reinecke's avatar
Martin Reinecke committed
49
        The directional derivative at the given position
Jakob Knollmueller's avatar
Jakob Knollmueller committed
50
    line_direction : Field
51
52
        Direction along which the movement is restricted. Does not have to be
        normalized.
53
    energy : Energy
Martin Reinecke's avatar
Martin Reinecke committed
54
        The underlying Energy at the given position
55

Jakob Knollmueller's avatar
Jakob Knollmueller committed
56
57
58
59
    Raises
    ------
    NotImplementedError
        Raised if
60
61
            * value, gradient or curvature of the attribute energy are not
              implemented.
Jakob Knollmueller's avatar
Jakob Knollmueller committed
62
63
64

    Notes
    -----
65
66
67
68
    The LineEnergy is used in minimization schemes in order perform line
    searches. It describes an underlying Energy which is restricted along one
    direction, only requiring the step size parameter to determine a new
    position.
69
70

    """
71

72
    def __init__(self, line_position, energy, line_direction, offset=0.):
73
        super(LineEnergy, self).__init__()
74
75
        self._line_position = float(line_position)
        self._line_direction = line_direction
76

77
78
79
80
81
82
        if self._line_position==float(offset):
            self.energy = energy
        else:
            pos = energy.position \
                + (self._line_position-float(offset))*self._line_direction
            self.energy = energy.at(position=pos)
83

84
    def at(self, line_position):
85
        """ Returns LineEnergy at new position, memorizing the zero point.
Jakob Knollmueller's avatar
Jakob Knollmueller committed
86
87
88

        Parameters
        ----------
89
        line_position : float
90
            Parameter for the new position on the line direction.
Jakob Knollmueller's avatar
Jakob Knollmueller committed
91
92
93

        Returns
        -------
94
            LineEnergy object at new position with same zero point as `self`.
Jakob Knollmueller's avatar
Jakob Knollmueller committed
95
96

        """
97

98
        return self.__class__(line_position,
99
100
                              self.energy,
                              self.line_direction,
101
                              offset=self.line_position)
102
103
104
105
106
107

    @property
    def value(self):
        return self.energy.value

    @property
108
109
    def line_position(self):
        return self._line_position
Martin Reinecke's avatar
Martin Reinecke committed
110
111

    @property
112
113
    def line_direction(self):
        return self._line_direction
114
115

    @property
116
117
118
    def directional_derivative(self):
        res = self.energy.gradient.vdot(self.line_direction)
        if abs(res.imag) / max(abs(res.real), 1.) > 1e-12:
Martin Reinecke's avatar
Martin Reinecke committed
119
120
            print ("directional derivative has non-negligible "
                  "imaginary part:", res)
Martin Reinecke's avatar
Martin Reinecke committed
121
        return res.real