# -*- coding: utf-8 -*- """ @author: Laura C. Kühle """ from abc import ABC, abstractmethod import numpy as np class InitialCondition(ABC): """Abstract class for initial condition function. Methods ------- get_name() Returns string of class name. is_smooth() Returns flag whether function is smooth. induce_adjustment(value) Adjusts x-value of function. randomize(config) Sets all non-determined instance variables to random value. calculate(x) Evaluates function at given x-value. """ def __init__(self, config): """Initializes InitialCondition. Parameters ---------- config : dict Additional parameters for initial condition. """ self._reset(config) def _reset(self, config): """Resets instance variables. Parameters ---------- config : dict Additional parameters for initial condition. """ pass def get_name(self): """Returns string of class name.""" return self.__class__.__name__ def is_smooth(self): """Returns flag that function is smooth.""" return True def induce_adjustment(self, value): """Adjusts x-value of function. Parameters ---------- value : float Value of adjustment on x-axis in right direction. """ pass def randomize(self, config): """Sets all non-determined instance variables to random value. Parameters ---------- config : dict Fixed parameters for initial condition. """ pass def calculate(self, x, mesh=None): """Evaluates function at given x-value. If a mesh is given, the x-value is projected into its periodic interval before evaluating the function. Parameters ---------- x : float Evaluation point of function. mesh : Mesh, optional Mesh for calculation. Default: None. Returns ------- float Value of function evaluates at x-value. """ if mesh is not None: left_bound, right_bound = mesh.bounds while x < left_bound: x += mesh.interval_len while x > right_bound: x -= mesh.interval_len return self._get_point(x) @abstractmethod def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ pass class Sine(InitialCondition): """Class for the sine wave. Attributes ---------- factor : float Factor by which is the evaluation point is multiplied before applying sine. Methods ------- randomize(config) Sets all non-determined instance variables to random value. """ def _reset(self, config): """Resets instance variables. Parameters ---------- config : dict Additional parameters for initial condition. """ super()._reset(config) # Unpack necessary configurations self._factor = config.pop('factor', 2) def randomize(self, config): """Sets all non-determined instance variables to random value. Parameters ---------- config : dict Fixed parameters for initial condition. """ factor = config.pop('factor', np.random.uniform(low=-100, high=100)) config = {'factor': factor} self._reset(config) def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ return np.sin(self._factor * np.pi * x) class Box(InitialCondition): """Class for a continuous function with two jumps (forming a box). Methods ------- is_smooth() Returns flag whether function is smooth. """ def is_smooth(self): """Returns flag that function is not smooth.""" return False def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ if x < -1: x += 2 if x > 1: x -= 2 if (x >= -0.5) & (x <= 0.5): return 1 else: return 0 class FourPeakWave(InitialCondition): """Class for a function with four peaks. The function is defined piece-by-piece and consists of a Gaussian function, a box function, a symmetric absolute function, and an elliptic function. Attributes ---------- alpha : float Factor used for the elliptic function. delta : float Value used to adjust z for the Gaussian function. beta : float Factor used for the Gaussian function. a : float Value for x-value adjustment for elliptic function. z : float Value for x-value adjustment for Gaussian function. Methods ------- is_smooth() Returns flag whether function is smooth. """ def _reset(self, config): """Resets instance variables. Parameters ---------- config : dict Additional parameters for initial condition. """ super()._reset(config) # Set additional necessary parameter self._alpha = 10 self._delta = 0.005 self._beta = np.log(2) / (36 * self._delta**2) self._a = 0.5 self._z = -0.7 def is_smooth(self): """Returns flag that function is not smooth.""" return False def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ if (x >= -0.8) & (x <= -0.6): return 1/6 * (self._gaussian_function(x, self._z-self._delta) + self._gaussian_function(x, self._z+self._delta) + 4 * self._gaussian_function(x, self._z)) if (x >= -0.4) & (x <= -0.2): return 1 if (x >= 0) & (x <= 0.2): return 1 - abs(10 * (x-0.1)) if (x >= 0.4) & (x <= 0.6): return 1/6 * (self._elliptic_function(x, self._a-self._delta) + self._elliptic_function(x, self._a+self._delta) + 4 * self._elliptic_function(x, self._a)) return 0 def _gaussian_function(self, x, z): """Evaluates Gaussian function. Parameters ---------- x : float Evaluation point of function. z : float Value for x-value adjustment. Returns ------- float Value of function evaluates at x-value. """ return np.exp(-self._beta * (x-z)**2) def _elliptic_function(self, x, a): """Evaluates elliptic function. Parameters ---------- x : float Evaluation point of function. a : float Value for x-value adjustment. Returns ------- float Value of function evaluates at x-value. """ return np.sqrt(max(1 - self._alpha**2 * (x-a)**2, 0)) class Linear(InitialCondition): """Class for the linear function. Attributes ---------- factor : float Factor by which is the evaluation point is multiplied. Methods ------- randomize(config) Sets all non-determined instance variables to random value. """ def _reset(self, config): """Resets instance variables. Parameters ---------- config : dict Additional parameters for initial condition. """ super()._reset(config) # Unpack necessary configurations self._factor = config.pop('factor', 1) def randomize(self, config): """Sets all non-determined instance variables to random value. Parameters ---------- config : dict Fixed parameters for initial condition. """ factor = config.pop('factor', np.random.uniform(low=-100, high=100)) config = {'factor': factor} self._reset(config) def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ return self._factor * x class LinearAbsolut(InitialCondition): """Class for the absolute values of the linear function. Attributes ---------- factor : float Factor by which is the evaluation point is multiplied. Methods ------- is_smooth() Returns flag whether function is smooth. randomize(config) Sets all non-determined instance variables to random value. """ def _reset(self, config): """Resets instance variables. Parameters ---------- config : dict Additional parameters for initial condition. """ super()._reset(config) # Unpack necessary configurations self._factor = config.pop('factor', 1) def is_smooth(self): """Returns flag that function is not smooth.""" return False def randomize(self, config): """Sets all non-determined instance variables to random value. Parameters ---------- config : dict Fixed parameters for initial condition. """ factor = config.pop('factor', np.random.uniform(low=-100, high=100)) config = {'factor': factor} self._reset(config) def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ return self._factor * abs(x) class DiscontinuousConstant(InitialCondition): """Class for the otherwise continuous function with one jump. Attributes ---------- x0 : float X-value where jump is induced. left_factor : float Factor by which is the evaluation point is multiplied before the jump. right_factor : float Factor by which is the evaluation point is multiplied after the jump. Methods ------- is_smooth() Returns flag whether function is smooth. """ def _reset(self, config): """Resets instance variables. Parameters ---------- config : dict Additional parameters for initial condition. """ super()._reset(config) # Unpack necessary configurations self._x0 = config.pop('x0', 0) self._left_factor = config.pop('left_factor', 1) self._right_factor = config.pop('right_factor', 0.5) def is_smooth(self): """Returns flag that function is not smooth.""" return False def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ return self._left_factor * (x <= self._x0) \ + self._right_factor * (x > self._x0) class Polynomial(InitialCondition): """Class for the polynomial function. Attributes ---------- factor : float Factor by which is the evaluation point is multiplied. exponential : int Degree of the polynomial. Methods ------- randomize(config) Sets all non-determined instance variables to random value. """ def _reset(self, config): """Resets instance variables. Parameters ---------- config : dict Additional parameters for initial condition. """ super()._reset(config) # Unpack necessary configurations self._factor = config.pop('factor', 1) self._exponential = config.pop('exponential', 2) def randomize(self, config): """Sets all non-determined instance variables to random value. Parameters ---------- config : dict Fixed parameters for initial condition. """ factor = config.pop('factor', np.random.uniform(low=-100, high=100)) exponential = config.pop('exponential', np.random.randint(2, high=6)) config = {'factor': factor, 'exponential': exponential} self._reset(config) def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ return self._factor * (x ** self._exponential) class Continuous(InitialCondition): """Class for the continuous function. Attributes ---------- factor : float Factor by which is the evaluation point is multiplied. Methods ------- randomize(config) Sets all non-determined instance variables to random value. """ def _reset(self, config): """Resets instance variables. Parameters ---------- config : dict Additional parameters for initial condition. """ super()._reset(config) # Unpack necessary configurations self._factor = config.pop('factor', 1) def randomize(self, config): """Sets all non-determined instance variables to random value. Parameters ---------- config : dict Fixed parameters for initial condition. """ factor = config.pop('factor', np.random.uniform(low=-100, high=100)) config = {'factor': factor} self._reset(config) def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ return self._factor class HeavisideOneSided(InitialCondition): """Class for the one-sided heaviside function. Attributes ---------- factor : float Factor by which is the evaluation point is multiplied. Methods ------- is_smooth() Returns flag whether function is smooth. randomize(config) Sets all non-determined instance variables to random value. """ def _reset(self, config): """Resets instance variables. Parameters ---------- config : dict Additional parameters for initial condition. """ super()._reset(config) # Unpack necessary configurations self._factor = config.pop('factor', -1) def is_smooth(self): """Returns flag that function is not smooth.""" return False def randomize(self, config): """Sets all non-determined instance variables to random value. Parameters ---------- config : dict Fixed parameters for initial condition. """ factor = config.pop('factor', np.random.choice([-1, 1])) config = {'factor': factor} self._reset(config) def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ return self._factor - 2 * self._factor * np.heaviside(x, 0) class HeavisideTwoSided(InitialCondition): """Class for the two-sided heaviside function. Attributes ---------- left_factor : float Factor by which is the evaluation point is multiplied before the jump. right_factor : float Factor by which is the evaluation point is multiplied after the jump. adjustment : float Extent of adjustment of evaluation point in x-direction. Methods ------- is_smooth() Returns flag whether function is smooth. induce_adjustment(value) Adjusts x-value of function. randomize(config) Sets all non-determined instance variables to random value. """ def _reset(self, config): """Resets instance variables. Parameters ---------- config : dict Additional parameters for initial condition. """ super()._reset(config) # Unpack necessary configurations self._left_factor = config.pop('left_factor', 1) self._right_factor = config.pop('right_factor', 2) self._adjustment = config.pop('adjustment', 0) def is_smooth(self): """Returns flag that function is not smooth.""" return False def induce_adjustment(self, value): """Adjusts x-value of function. Parameters ---------- value : float Value of adjustment on x-axis in right direction. """ self._adjustment = value def randomize(self, config): """Sets all non-determined instance variables to random value. Parameters ---------- config : dict Fixed parameters for initial condition. """ left_factor = config.pop('left_factor', np.random.choice([-1, 1])) right_factor = config.pop('right_factor', np.random.choice([-1, 1])) adjustment = config.pop('adjustment', np.random.uniform(low=-1, high=1)) config = {'left_factor': left_factor, 'right_factor': right_factor, 'adjustment': adjustment} self._reset(config) def _get_point(self, x): """Evaluates function at given x-value. Parameters ---------- x : float Evaluation point of function. Returns ------- float Value of function evaluates at x-value. """ return self._left_factor \ - self._left_factor * np.heaviside(x - self._adjustment, 0)\ - self._right_factor * np.heaviside(x + self._adjustment, 0)