Commit baccf4fd authored by Philipp Arras's avatar Philipp Arras
Browse files

Add plotting for EnergyHistory

parent 06f0a797
Pipeline #75207 failed with stages
in 3 minutes and 7 seconds
...@@ -177,7 +177,8 @@ class NewtonCG(DescentMinimizer): ...@@ -177,7 +177,8 @@ class NewtonCG(DescentMinimizer):
self._nreset = nreset self._nreset = nreset
self._max_cg_iterations = max_cg_iterations self._max_cg_iterations = max_cg_iterations
self._alpha = energy_reduction_factor self._alpha = energy_reduction_factor
self._history = [] if activate_logging else None from .iteration_controllers import EnergyHistory
self._history = EnergyHistory() if activate_logging else None
def get_descent_direction(self, energy, old_value=None): def get_descent_direction(self, energy, old_value=None):
if old_value is None: if old_value is None:
...@@ -187,7 +188,7 @@ class NewtonCG(DescentMinimizer): ...@@ -187,7 +188,7 @@ class NewtonCG(DescentMinimizer):
ic = AbsDeltaEnergyController( ic = AbsDeltaEnergyController(
ediff, iteration_limit=self._max_cg_iterations, name=self._name) ediff, iteration_limit=self._max_cg_iterations, name=self._name)
if self._history is not None: if self._history is not None:
ic.activate_logging() ic.enable_logging()
e = QuadraticEnergy(0*energy.position, energy.metric, energy.gradient) e = QuadraticEnergy(0*energy.position, energy.metric, energy.gradient)
p = None p = None
if self._napprox > 1: if self._napprox > 1:
...@@ -195,15 +196,12 @@ class NewtonCG(DescentMinimizer): ...@@ -195,15 +196,12 @@ class NewtonCG(DescentMinimizer):
p = makeOp(approximation2endo(met, self._napprox)).inverse p = makeOp(approximation2endo(met, self._napprox)).inverse
e, conv = ConjugateGradient(ic, nreset=self._nreset)(e, p) e, conv = ConjugateGradient(ic, nreset=self._nreset)(e, p)
if self._history is not None: if self._history is not None:
self._history.extend(ic.pop_history()) self._history += ic.history
return -e.position return -e.position
def pop_inversion_energy_history(self): @property
if self._history is None: def inversion_history(self):
raise RuntimeError('Logging has not been enabled.') return self._history
hist = self._history
self._history = []
return hist
class L_BFGS(DescentMinimizer): class L_BFGS(DescentMinimizer):
......
...@@ -43,7 +43,7 @@ class IterationController(metaclass=NiftyMeta): ...@@ -43,7 +43,7 @@ class IterationController(metaclass=NiftyMeta):
For analyzing minimization procedures IterationControllers can log energy For analyzing minimization procedures IterationControllers can log energy
values together with the respective time stamps. In order to activate this values together with the respective time stamps. In order to activate this
feature `activate_and_reset_logging()` needs to be called. feature `activate_logging()` needs to be called.
""" """
CONVERGED, CONTINUE, ERROR = list(range(3)) CONVERGED, CONTINUE, ERROR = list(range(3))
...@@ -79,38 +79,64 @@ class IterationController(metaclass=NiftyMeta): ...@@ -79,38 +79,64 @@ class IterationController(metaclass=NiftyMeta):
""" """
raise NotImplementedError raise NotImplementedError
def pop_history(self): def enable_logging(self):
"""Returns the collected history of energy values and resets the """Enables the logging functionality. If the log has been populated
history afterwards. before, it stays as it is."""
Returns
-------
list : List of (unix timestamp, energy values) tuples
"""
if self._history is None: if self._history is None:
raise RuntimeError('No history was taken') self._history = EnergyHistory()
res = self._history
self._history = [] def disable_logging(self):
return res """Disables the logging functionality. If the log has been populated
before, it is dropped."""
self._history = None
def activate_and_reset_logging(self): @property
"""Activates the logging functionality. If the log has been populated def history(self):
before, it is reset.""" return self._history
self._history = []
def activate_logging(self):
"""Activates the logging functionality. If the log has been populated class EnergyHistory(object):
before, it stays as it is.""" def __init__(self):
if self._history is None: self._lst = []
self._history = []
def append(self, x):
if len(x) != 2:
raise ValueError
self._lst.append((float(x[0]), float(x[1])))
def pop_all(self):
lst = self._lst
self._lst = []
return lst
@property
def timestamps(self):
return [x for x, _ in self._lst]
@property
def energy_values(self):
return [x for _, x in self._lst]
def __add__(self, other):
if not isinstance(other, EnergyHistory):
return NotImplemented
res = EnergyHistory()
res._lst = self._lst + other._lst
return res
def __iadd__(self, other):
if not isinstance(other, EnergyHistory):
return NotImplemented
self._lst += other._lst
return self
def append_history(func): def append_history(func):
@functools.wraps(func) @functools.wraps(func)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
if args[0]._history is not None: hist = args[0].history
energy_val = args[1].value if isinstance(hist, EnergyHistory):
args[0]._history.append((time(), energy_val)) hist.append((time(), args[1].value))
return func(*args, **kwargs) return func(*args, **kwargs)
return wrapper return wrapper
......
...@@ -16,14 +16,17 @@ ...@@ -16,14 +16,17 @@
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik. # NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
import os import os
from datetime import datetime as dt
import numpy as np import numpy as np
from matplotlib.dates import DateFormatter, date2num
from .domains.gl_space import GLSpace from .domains.gl_space import GLSpace
from .domains.hp_space import HPSpace from .domains.hp_space import HPSpace
from .domains.power_space import PowerSpace from .domains.power_space import PowerSpace
from .domains.rg_space import RGSpace from .domains.rg_space import RGSpace
from .field import Field from .field import Field
from .minimization.iteration_controllers import EnergyHistory
# relevant properties: # relevant properties:
# - x/y size # - x/y size
...@@ -261,6 +264,38 @@ def _register_cmaps(): ...@@ -261,6 +264,38 @@ def _register_cmaps():
plt.register_cmap(cmap=LinearSegmentedColormap("Plus Minus", pm_cmap)) plt.register_cmap(cmap=LinearSegmentedColormap("Plus Minus", pm_cmap))
def _plot_history(f, ax, **kwargs):
import matplotlib.pyplot as plt
for i, fld in enumerate(f):
if not isinstance(fld, EnergyHistory):
raise TypeError
label = kwargs.pop("label", None)
if not isinstance(label, list):
label = [label] * len(f)
alpha = kwargs.pop("alpha", None)
if not isinstance(alpha, list):
alpha = [alpha] * len(f)
color = kwargs.pop("color", None)
if not isinstance(color, list):
color = [color] * len(f)
ax.set_title(kwargs.pop("title", ""))
ax.set_xlabel(kwargs.pop("xlabel", ""))
ax.set_ylabel(kwargs.pop("ylabel", ""))
plt.xscale(kwargs.pop("xscale", "linear"))
plt.yscale(kwargs.pop("yscale", "linear"))
for i, fld in enumerate(f):
xcoord = fld.timestamps
# xcoord = date2num([dt.fromtimestamp(ts) for ts in xcoord])
# xfmt = DateFormatter('%H:%M')
# ax.xaxis.set_major_formatter(xfmt)
ycoord = fld.energy_values
ax.scatter(xcoord, ycoord, label=label[i], alpha=alpha[i],
color=color[i])
_limit_xy(**kwargs)
if label != ([None]*len(f)):
plt.legend()
def _plot1D(f, ax, **kwargs): def _plot1D(f, ax, **kwargs):
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
...@@ -421,11 +456,14 @@ def _plot2D(f, ax, **kwargs): ...@@ -421,11 +456,14 @@ def _plot2D(f, ax, **kwargs):
def _plot(f, ax, **kwargs): def _plot(f, ax, **kwargs):
_register_cmaps() _register_cmaps()
if isinstance(f, Field): if isinstance(f, Field) or isinstance(f, EnergyHistory):
f = [f] f = [f]
f = list(f) f = list(f)
if len(f) == 0: if len(f) == 0:
raise ValueError("need something to plot") raise ValueError("need something to plot")
if isinstance(f[0], EnergyHistory):
_plot_history(f, ax, **kwargs)
return
if not isinstance(f[0], Field): if not isinstance(f[0], Field):
raise TypeError("incorrect data type") raise TypeError("incorrect data type")
dom1 = f[0].domain dom1 = f[0].domain
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment