Source code for pySDC.implementations.datatype_classes.container

from pySDC.core.errors import DataError


[docs] class MultiComponentContainer(object): r""" Datatype with multiple components, each one an object of its own. This is the counterpart of ``MultiComponentMeshMixin`` for backends whose data cannot simply grow an axis: a FEniCS ``Function`` lives on a ``FunctionSpace`` and a PETSc ``Vec`` on a ``DMDA``, so the components cannot be views into one contiguous array and have to be separate objects instead. To make a specific multi-component datatype, derive from this class, list the components as strings in ``components``, and say what a single component is in ``component_type``. An example: .. code-block:: python class rhs_fenics_mesh(MultiComponentContainer): components = ['impl', 'expl'] component_type = fenics_mesh Instantiating such a datatype builds one component of ``component_type`` per name, either by copying the components of another instance or by passing ``init`` and ``val`` on to each of them. The arithmetic is applied component by component, so the component type is what decides which operands it accepts. """ components = [] component_type = None def __init__(self, init, val=0.0): """ Initialization routine Args: init: either another instance of this datatype, or whatever ``component_type`` accepts val: value to initialize the components with, if they are not copied """ if isinstance(init, type(self)): for name in self.components: setattr(self, name, self.component_type(getattr(init, name))) else: for name in self.components: setattr(self, name, self.component_type(init, val=val)) def _apply(self, other, operation): """ Apply ``operation`` to each component of this datatype and the matching one of ``other``. Args: other: another instance of this datatype operation (callable): takes the two components and returns the new one Returns: a new instance of this datatype """ if not isinstance(other, type(self)): raise DataError(f'Type error: cannot combine {type(other)} with {type(self)}') me = type(self)(self) for name in self.components: setattr(me, name, operation(getattr(self, name), getattr(other, name))) return me def __add__(self, other): """ Overloading the addition operator Args: other: datatype of the same type to be added Raises: DataError: if other is not of the same type Returns: sum of caller and other, component by component """ return self._apply(other, lambda a, b: a + b) def __sub__(self, other): """ Overloading the subtraction operator Args: other: datatype of the same type to be subtracted Raises: DataError: if other is not of the same type Returns: difference between caller and other, component by component """ return self._apply(other, lambda a, b: a - b) def __rmul__(self, other): """ Overloading the right multiply by factor operator Args: other (float): factor Raises: DataError: if the component type does not accept the factor Returns: copy of the caller scaled by the factor """ me = type(self)(self) for name in self.components: setattr(me, name, other * getattr(self, name)) return me