Source code for ensembler.conditions.box_conditions

import numpy as np

from ensembler.conditions._basicCondition import _conditionCls
from ensembler.util.ensemblerTypes import systemCls as systemType, Iterable, Number, Union


[docs]class _boundaryCondition(_conditionCls): """ This parent class is defining some functions for the actual box conditions. """ lowerbounds: Iterable[Number] higherbounds: Iterable[Number] def __str__(self) -> str: msg = self.name + "\n" msg += "\tDimensions: " + str(self.nDim) + "\n" msg += "\n" msg += "\tapply every step: " + str(self.nDim) + "\n" msg += "\tHigher bounds: " + str(self.higherbounds) + "\n" msg += "\tLower bounds: " + str(self.lowerbounds) + "\n" return msg def _parse_boundary(self, boundary: Union[Number, Iterable[Number]]) -> bool: if (isinstance(boundary, Iterable)): if (all([isinstance(x, Number) for x in boundary])): self.higherbounds = np.array(np.max(boundary), ndmin=1) self.lowerbounds = np.array(np.min(boundary), ndmin=1) elif (all([isinstance(x, Iterable) and [isinstance(y, Number) for y in x] for x in boundary])): self.higherbounds = np.max(boundary, axis=1) self.lowerbounds = np.min(boundary, axis=1) else: raise Exception("Could not read the Boundary Condition! : " + str(boundary)) self.nDim = len(self.higherbounds) return True
[docs]class boxBoundaryCondition(_boundaryCondition): name: str = "Box Boundary Condition"
[docs] def __init__(self, boundary: Union[Iterable[Number], Iterable[Iterable[Number]]], every_step: int = 1, system: systemType = None, verbose: bool=False): """ box boundary condition This class can be used to define a box, which is restrictiring the phase space to its boundaries. Warning: This is not a very useful condition in most cases as the hard boundary leads to box effects in the simulation. We rather suggest the using the periodic boundary condition. Useage: Add this class as condition to a system. Parameters ---------- boundary: Union[Iterable[Number], Iterable[Iterable[Number]]] defines the bounds of the system (in 3D-MD = box). Give here for each dimension the extrem coordinates. system: systemType, optional here a system can be given, normally this argument is not needed, as the system is coupling itself, if the condition is passed on construction to the system. """ super().__init__(system=system, tau=every_step, verbose=verbose) self._parse_boundary(boundary=boundary)
[docs] def apply(self, current_position: Union[Iterable[Number], Number], current_velocity: Union[Iterable[Number], Number]) -> ( Union[Iterable[Number], Number], Union[Iterable[Number], Number]): if self.verbose: print("box boundary_condition: before: ", current_position) current_position = np.array(current_position, ndmin=1) if self.verbose: print("CurrPos: ", current_position) for dim in range(len(current_position)): if self.verbose: print("DIM: ", dim) if (current_position[dim] < self.lowerbounds[dim]): diff = abs(current_position[dim] - self.lowerbounds[dim]) if self.verbose: print("Lower:", diff, "Vel: ", current_velocity) current_position[dim] = (self.lowerbounds[dim] + diff) if(not isinstance(current_velocity, type(None))): current_velocity[dim] = np.nan if (current_velocity == np.nan) else -current_velocity[dim] elif (current_position[dim] > self.higherbounds[dim]): diff = abs(current_position[dim] - self.higherbounds[dim]) if self.verbose: print("Higher:", diff) current_position[dim] = (self.higherbounds[dim] - diff) if(not isinstance(current_velocity, type(None))): current_velocity = np.nan if (current_velocity == np.nan) else -current_velocity[dim] if self.verbose: print("box boundary_condition: after: ", current_position) return np.squeeze(current_position), np.squeeze(current_velocity)
[docs] def apply_coupled(self): """ Applies the box Condition to the coupled system. """ if (self.system.step % self._tau == 0): newCurrentPosition, newCurrentVelocity = self.apply(current_position=self.system._currentPosition, current_velocity=self.system._currentVelocities) self.system._currentPosition = np.squeeze(newCurrentPosition) self.system._currentVelocity = np.squeeze(newCurrentVelocity)
[docs]class periodicBoundaryCondition(_boundaryCondition): name: str = "Periodic Boundary Condition" verbose: bool = False
[docs] def __init__(self, boundary: Union[Iterable[Number], Iterable[Iterable[Number]]], every_step: int = 1, system: systemType = None, verbose:bool =False): """ periodic boundary condition This class allows to enable sampling in mirror images and projects the coordinates to the restricted space. Add this class as condition to a system. Useage: Add this class as condition to a system. Parameters ---------- boundary: Union[Iterable[Number], Iterable[Iterable[Number]]] defines the bounds of the system (in 3D-MD = box). Give here for each dimension the extrem coordinates. system: systemType, optional here a system can be given, normally this argument is not needed, as the system is coupling itself, if the condition is passed on construction to the system. """ super().__init__(system=system, tau=every_step, verbose=verbose) self._parse_boundary(boundary)
[docs] def apply(self, current_position: Union[Iterable[Number], Number]) -> Union[Iterable[Number], Number]: """ apply the periodic boundary condition Parameters ---------- current_position: Union[Iterable[Number], Number] current system position current_velocity: Union[Iterable[Number], Number] current systems velocity Returns ------- Union[Iterable[Number], Number] new position a new position in the defined space """ if self.verbose: print("periodic boundary_condition: before: ", current_position) current_position = np.array(current_position, ndmin=1) for dim in range(self.nDim): if (current_position[dim] < self.lowerbounds[dim]): if self.verbose: print("LOWER") current_position[dim] = self.higherbounds[dim] - (self.lowerbounds[dim] - current_position[dim]) elif (current_position[dim] > self.higherbounds[dim]): if self.verbose: print("UPPER") current_position[dim] = self.lowerbounds[dim] + (current_position[dim] - self.higherbounds[dim]) if self.verbose: print("periodic boundary_condition: after: ", current_position) return current_position
[docs] def apply_coupled(self): """ Applies the box Condition to the coupled system. """ if (self.system.step % self._tau == 0): newCurrentPosition = self.apply(current_position=self.system._currentPosition) self.system._currentPosition = np.squeeze(newCurrentPosition)