Source code for simframe.frame.intvar

import numpy as np

from simframe.frame.field import Field
from simframe.frame.heartbeat import Heartbeat
from simframe.utils.color import colorize


[docs] class IntVar(Field): """Cclass for integration variables that behaves as ``Field`` but has additional functionality with respect to stepsize management for integration. Notes ----- The ``updater`` for integration variables is calculating the stepsize. The function associated to the ``updater`` needs the parent ``Frame`` object as first positional argument and needs to return the desired stepsize. ``IntVar.update()`` does not update the integration variable. Try not to update the integration variable by hand. Let the ``Integrator`` do it for you.""" __name__ = "IntVar" def __new__(cls, owner, value=0, snapshots=[], updater=None, description="", save=True, copy=False): """Parameters ---------- owner : Frame Parent frame object to which the field belongs value : number, optional, default : 0 Initial value of the field snapshots : list, array, optional, default : [] List or array of snapshots at which an output file should be written. Has to be monotonously increasing. updater : Heartbeat, Updater, callable, optional, default : None Updater for calculating stepsize description : string, optional, default : "" Descriptive string for the field save : boolean, optional, default : True If False the integration variable is not written into output files copy : boolean, optional, default : True If True <value> will be copied, not referenced""" obj = super().__new__(cls, owner, value, updater=updater, description=description, constant=False, save=save, copy=copy) obj.snapshots = snapshots obj._prevstepsize = 0. obj._suggested = None return obj def __array_finalize__(self, obj): super().__array_finalize__(obj) self.snapshots = getattr(obj, "snapshots", []) self._prevstepsize = getattr(obj, "_prevstepsize", 0.) self._suggested = getattr(obj, "_suggested", None) def __str__(self): ret = "{}".format(str(self.__name__)) ret = super().__str__() ret += ", {}".format(colorize("Integration variable", "purple")) return ret
[docs] def update(self): """Not used for ``IntVar``.""" msg = "{}: {}".format(colorize("Warning", "yellow"), "Do not update the integration variable by hand.") print(msg)
[docs] def suggest(self, value, reset=False): """Suggest a step size For adaptive integration schemes, this function can be used to suggest a step size for the next integration step. If many vaiables are integrated this safes the smallest suggested step size in a temporary buffer accessible via ``IntVar.suggested``. Parameters ---------- value : Field Suggested step size reset : boolean, optional, default : False If True, the previous value will be discarded.""" if reset: self._suggested = None self.suggested = value if self._suggested is None else np.minimum( self._suggested, value)
@property def suggested(self): """Suggested step size.""" if self._suggested is None: raise RuntimeError("No step size has been suggested, yet.") return self._suggested @suggested.setter def suggested(self, value): if value <= 0: raise ValueError( "Suggested step size has to be greater than zero.") self._suggested = value @property def stepsize(self): '''Current stepsize.''' if isinstance(self.updater, Heartbeat): return np.minimum(self.updater.beat(self._owner), self.maxstepsize) raise RuntimeError( "You need to set an Updater for stepsize function first.") @property def snapshots(self): '''Snapshots at which output should be written. Even if no outputs are written it needs to contain at least one value that specifies the end point of the simulation.''' return self._snapshots @snapshots.setter def snapshots(self, value): snaps = np.asarray(value) if snaps.size > 1: if not all(x < y for x, y in zip(snaps, snaps[1:])): raise ValueError("Snapshots have to be strictly increasing") self._snapshots = snaps @property def nextsnapshot(self): '''Value of the next snapshot.''' if self.snapshots.size < 1: raise ValueError("Snapshots are emtpy") return self.snapshots[np.argmax(self < self.snapshots)] @property def prevsnapshot(self): '''Value of the previous snapshot.''' if self.snapshots.size < 1: raise ValueError("Snapshots are emtpy") if self < self.snapshots[0]: return None else: return self.snapshots[np.argmin(self >= self.snapshots)-1] @property def maxstepsize(self): '''Maximum possible step size, i.e., to next snapshot.''' return self.nextsnapshot - self.getfield(dtype=self.dtype) @property def prevstepsize(self): """Previously taken step size.""" return self._prevstepsize