line_energy.py 3.73 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 19


Martin Reinecke's avatar
Martin Reinecke committed
20
class LineEnergy:
21 22 23 24
    """ 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.
25 26 27

    Parameters
    ----------
Martin Reinecke's avatar
Martin Reinecke committed
28 29 30
    linepos : float
        Defines the full spatial position of this energy via
        self.energy.position = zero_point + linepos*line_direction
Jakob Knollmueller's avatar
Jakob Knollmueller committed
31
    energy : Energy
32
        The Energy object which will be evaluated along the given direction.
Martin Reinecke's avatar
Martin Reinecke committed
33 34 35 36 37 38
    linedir : Field
        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.).
39 40 41

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

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

    Notes
    -----
63 64 65 66
    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.
67 68

    """
69

Martin Reinecke's avatar
Martin Reinecke committed
70 71 72
    def __init__(self, linepos, energy, linedir, offset=0.):
        self._linepos = float(linepos)
        self._linedir = linedir
73

Martin Reinecke's avatar
Martin Reinecke committed
74 75
        pos = energy.position + (self._linepos-float(offset))*self._linedir
        self.energy = energy.at(position=pos)
76

Martin Reinecke's avatar
Martin Reinecke committed
77
    def at(self, linepos):
78
        """ Returns LineEnergy at new position, memorizing the zero point.
Jakob Knollmueller's avatar
Jakob Knollmueller committed
79 80 81

        Parameters
        ----------
Martin Reinecke's avatar
Martin Reinecke committed
82
        linepos : float
83
            Parameter for the new position on the line direction.
Jakob Knollmueller's avatar
Jakob Knollmueller committed
84 85 86

        Returns
        -------
87
            LineEnergy object at new position with same zero point as `self`.
Jakob Knollmueller's avatar
Jakob Knollmueller committed
88 89

        """
90

Martin Reinecke's avatar
Martin Reinecke committed
91
        return self.__class__(linepos,
92
                              self.energy,
Martin Reinecke's avatar
Martin Reinecke committed
93 94
                              self.linedir,
                              offset=self.linepos)
95 96 97 98 99 100

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

    @property
Martin Reinecke's avatar
Martin Reinecke committed
101 102 103 104 105 106
    def linepos(self):
        return self._linepos

    @property
    def linedir(self):
        return self._linedir
107 108

    @property
Martin Reinecke's avatar
Martin Reinecke committed
109
    def dd(self):
Martin Reinecke's avatar
Martin Reinecke committed
110
        res = self.energy.gradient.vdot(self.linedir)
Martin Reinecke's avatar
Martin Reinecke committed
111 112 113
        if abs(res.imag)/max(abs(res.real),1.)>1e-12:
               print "directional derivative has non-negligible " \
                     "imaginary part:", res
Martin Reinecke's avatar
Martin Reinecke committed
114
        return res.real