line_energy.py 3.67 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
#
Martin Reinecke's avatar
Martin Reinecke committed
14
# Copyright(C) 2013-2018 Max-Planck-Society
Theo Steininger's avatar
Theo Steininger committed
15
16
17
#
# 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 absolute_import, division, print_function
20

Martin Reinecke's avatar
Martin Reinecke committed
21
22
from ..compat import *

23

24
class LineEnergy(object):
25
26
27
28
    """ 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.
29
30
31

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

Jakob Knollmueller's avatar
Jakob Knollmueller committed
44
45
    Notes
    -----
46
47
48
49
    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.
50
    """
51

52
    def __init__(self, line_position, energy, line_direction, offset=0.):
53
        super(LineEnergy, self).__init__()
54
        self._line_position = float(line_position)
55
        self._line_direction = line_direction
56

Martin Reinecke's avatar
PEP8  
Martin Reinecke committed
57
        if self._line_position == float(offset):
Martin Reinecke's avatar
Martin Reinecke committed
58
            self._energy = energy
59
60
61
        else:
            pos = energy.position \
                + (self._line_position-float(offset))*self._line_direction
Martin Reinecke's avatar
Martin Reinecke committed
62
            self._energy = energy.at(position=pos)
63

64
    def at(self, line_position):
65
        """ Returns LineEnergy at new position, memorizing the zero point.
Jakob Knollmueller's avatar
Jakob Knollmueller committed
66
67
68

        Parameters
        ----------
69
        line_position : float
70
            Parameter for the new position on the line direction.
Jakob Knollmueller's avatar
Jakob Knollmueller committed
71
72
73

        Returns
        -------
74
            LineEnergy object at new position with same zero point as `self`.
Jakob Knollmueller's avatar
Jakob Knollmueller committed
75
76

        """
77

Martin Reinecke's avatar
Martin Reinecke committed
78
79
        return LineEnergy(line_position, self._energy, self._line_direction,
                          offset=self._line_position)
80
81

    @property
Martin Reinecke's avatar
Martin Reinecke committed
82
83
    def energy(self):
        """
Martin Reinecke's avatar
Martin Reinecke committed
84
        Energy : The underlying Energy object
Martin Reinecke's avatar
Martin Reinecke committed
85
86
        """
        return self._energy
Martin Reinecke's avatar
Martin Reinecke committed
87
88

    @property
Martin Reinecke's avatar
Martin Reinecke committed
89
90
    def value(self):
        """
Martin Reinecke's avatar
Martin Reinecke committed
91
        float : The value of the energy functional at given `position`.
Martin Reinecke's avatar
Martin Reinecke committed
92
93
        """
        return self._energy.value
94
95

    @property
96
    def directional_derivative(self):
Martin Reinecke's avatar
Martin Reinecke committed
97
        """
Martin Reinecke's avatar
Martin Reinecke committed
98
        float : The directional derivative at the given `position`.
Martin Reinecke's avatar
Martin Reinecke committed
99
100
        """
        res = self._energy.gradient.vdot(self._line_direction)
101
        if abs(res.imag) / max(abs(res.real), 1.) > 1e-12:
Martin Reinecke's avatar
Martin Reinecke committed
102
            from ..logger import logger
Martin Reinecke's avatar
Martin Reinecke committed
103
            logger.warning("directional derivative has non-negligible "
104
                           "imaginary part: {}".format(res))
Martin Reinecke's avatar
Martin Reinecke committed
105
        return res.real