Source code for bumps.monitor

# This program is in the public domain
"""
Progress monitors.

Process monitors accept a :class:`bumps.history.History` object each cycle
and perform some sort of work.

Monitors have a :meth:`Monitor.config_history` method which calls
*history.requires()* to set the amount of history it needs and a 
*Monitor.__call__* method which takes the updated history and
generates the monitor output.

Most monitors are subclassed from :class:`TimedUpdate` to set a minimum
time between updates and to only show updates when there is an improvement.
The *TimedUpdate* subclasses must override :meth:`TimedUpdate.show_progress`
and :meth:`TimedUpdate.show_improvement` to control the output form. History
must be updated with time, value, point and step. The
bumps.fitters.MonitorRunner class manages history and updates.
"""
from __future__ import print_function

__all__ = ['Monitor', 'Logger', 'TimedUpdate']

from numpy import inf


[docs] class Monitor(object): """ Base class for monitors. """
[docs] def config_history(self, history): """ Indicate which fields are needed by the monitor and for what duration. """ pass
def __call__(self, history): """ Give the monitor a new piece of history to work with. """ pass
def _getfield(history, field): """ Return the last value in the trace, or None if there is no last value or no trace. """ trace = getattr(history, field, []) try: return trace[0] except IndexError: return None
[docs] class Logger(Monitor): """ Keeps a record of all values for the desired fields. *fields* is a list of history fields to store. *table* is an object with a *store(field=value,...)* method, which gets the current value of each field every time the history is updated. Call :meth:`config_history` with the :class:`bumps.history.History` object before starting so that the correct fields are stored. """ def __init__(self, fields=(), table=None): self.fields = fields self.table = table
[docs] def config_history(self, history): """ Make sure history records each logged field. """ kwargs = dict((key, 1) for key in self.fields) history.requires(**kwargs)
def __call__(self, history): """ Record the next piece of history. """ record = dict((f, _getfield(history, f)) for f in self.fields) self.table.store(**record)
[docs] class TimedUpdate(Monitor): """ Indicate progress every n seconds. The process should provide time, value, point, and step to the history update. Call :meth:`config_history` with the :class:`bumps.history.History` object before starting so that these fields are stored. *progress* is the number of seconds to go before showing progress, such as time or step number. *improvement* is the number of seconds to go before showing improvements to value. By default, the update only prints step number and improved value. Subclass TimedUpdate with replaced :meth:`show_progress` and :meth:`show_improvement` to trigger GUI updates or show parameter values. """ def __init__(self, progress=60, improvement=5): self.progress_delta = progress self.improvement_delta = improvement self.progress_time = -inf self.improvement_time = -inf self.value = inf self.improved = False
[docs] def config_history(self, history): history.requires(time=1, value=1, point=1, step=1)
[docs] def show_improvement(self, history): print("step", history.step, "value", history.value)
[docs] def show_progress(self, history): pass
def __call__(self, history): t = history.time[0] v = history.value[0] if v < self.value: self.improved = True if t > self.progress_time + self.progress_delta: self.progress_time = t self.show_progress(history) if self.improved and t > self.improvement_time + self.improvement_delta: self.improved = False self.improvement_time = t self.show_improvement(history)