diff --git a/scripts/tcd/ANN_Data_Generator.py b/scripts/tcd/ANN_Data_Generator.py index 07b88e21c1c2c9c5267d1b429f35f5e83e13b85b..33f7cf3ab1d7d70d2de2d9c8156b2a84f1c8ea57 100644 --- a/scripts/tcd/ANN_Data_Generator.py +++ b/scripts/tcd/ANN_Data_Generator.py @@ -8,7 +8,7 @@ import time import numpy as np from .DG_Approximation import do_initial_projection -from .projection_utils import Mesh +from .Mesh import Mesh from .Quadrature import Gauss from .Basis_Function import OrthonormalLegendre diff --git a/scripts/tcd/DG_Approximation.py b/scripts/tcd/DG_Approximation.py index 4a98383ffdb69d77fbd1a515bbf474403585ce19..0b07bb2771fd22c24dd1ce3dc709d4f5f885143d 100644 --- a/scripts/tcd/DG_Approximation.py +++ b/scripts/tcd/DG_Approximation.py @@ -16,7 +16,7 @@ from . import Quadrature from . import Update_Scheme from .Basis_Function import OrthonormalLegendre from .encoding_utils import encode_ndarray -from .projection_utils import Mesh +from .Mesh import Mesh x = Symbol('x') sns.set() diff --git a/scripts/tcd/Mesh.py b/scripts/tcd/Mesh.py new file mode 100644 index 0000000000000000000000000000000000000000..ca15ed8ae2b055a637d61f92be882b6bf0fd047b --- /dev/null +++ b/scripts/tcd/Mesh.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- +""" +@author: Laura C. Kühle + +""" +from __future__ import annotations +import math +import numpy as np +from numpy import ndarray +from typing import Tuple +from functools import cache + + +class Mesh: + """Class for mesh. + + Each cell is characterized by its center. + + Attributes + ---------- + mode : str + Mode for mesh use. Either 'training' or 'evaluation'. + num_cells : int + Number of cells in the mesh (ghost cells notwithstanding). Usually + exponential of 2. + bounds : Tuple[float, float] + Left and right boundary of the mesh interval. + interval_len : float + Length of the mesh interval. + cell_len : float + Length of a mesh cell. + cells : ndarray + Array of cell centers in mesh. + + Methods + ------- + create_data_dict() + Return dictionary with data necessary to construct mesh. + random_stencil(stencil_len) + Return random stencil. + + """ + + def __init__(self, num_cells: int, num_ghost_cells: int, + left_bound: float, right_bound: float, + training_data_mode: bool = False) -> None: + """Initialize Mesh. + + Parameters + ---------- + num_cells : int + Number of cells in the mesh (ghost cells notwithstanding). Has + to be an exponential of 2. + num_ghost_cells : int + Number of ghost cells on each side of the mesh. + left_bound : float + Left boundary of the mesh interval. + right_bound : float + Right boundary of the mesh interval. + training_data_mode : bool, optional + Flag indicating whether the mesh is used for training data + generation. Default: False. + + Raises + ------ + ValueError + If number of cells is not exponential of 2. + + """ + self._num_cells = num_cells + self._mode = 'training' if training_data_mode else 'evaluation' + if not training_data_mode: + if not math.log(self._num_cells, 2).is_integer(): + raise ValueError('The number of cells in the mesh has to be ' + 'an exponential of 2') + self._num_ghost_cells = num_ghost_cells + self._left_bound = left_bound + self._right_bound = right_bound + + @property + def mode(self) -> str: + """Return mode ('training' or 'evaluation').""" + return self._mode + + @property + def num_cells(self) -> int: + """Return number of mesh cells.""" + return self._num_cells + + @property + def bounds(self) -> Tuple[float, float]: + """Return left and right boundary of the mesh interval.""" + return self._left_bound, self._right_bound + + @property + def interval_len(self) -> float: + """Return the length of the mesh interval.""" + return self._right_bound - self._left_bound + + @property + def cell_len(self) -> float: + """Return the length of a mesh cell.""" + return self.interval_len/self.num_cells + + @property + @cache + def cells(self) -> ndarray: + """Return the cell centers of the mesh (including ghost cells).""" + return np.arange( + self._left_bound - (self._num_ghost_cells*2-1)/2*self.cell_len, + self._right_bound + (self._num_ghost_cells*2+1)/2*self.cell_len, + self.cell_len) + + @property + def non_ghost_cells(self) -> ndarray: + """Return the cell centers of the mesh (excluding ghost cells).""" + return self.cells[self._num_ghost_cells:-self._num_ghost_cells] + + def create_data_dict(self) -> dict: + """Return dictionary with data necessary to construct mesh.""" + return {'num_cells': self._num_cells, + 'left_bound': self._left_bound, + 'right_bound': self._right_bound, + 'num_ghost_cells': self._num_ghost_cells} + + def random_stencil(self, stencil_len: int) -> Mesh: + """Return random stencil. + + Build mesh with given number of cell centers around a random point + in the underlying interval. + + Returns + ------- + Mesh object + Mesh of given size around random point. + + """ + # Pick random point between left and right bound + point = np.random.uniform(self._left_bound, self._right_bound) + + # Adjust mesh spacing to be within interval if necessary + mesh_spacing = self.cell_len + max_spacing = 2/stencil_len*min(point-self._left_bound, + self._right_bound-point) + while mesh_spacing > max_spacing: + mesh_spacing /= 2 + + # Return new mesh instance + return Mesh(left_bound=point - stencil_len/2 * mesh_spacing, + right_bound=point + stencil_len/2 * mesh_spacing, + num_cells=stencil_len, num_ghost_cells=2, + training_data_mode=True) \ No newline at end of file diff --git a/scripts/tcd/Plotting.py b/scripts/tcd/Plotting.py index 43dcaa3b725da8afb6f48b8073ca4352b8646374..908292df7a815925c4275dfb74d8ddf032c77a69 100644 --- a/scripts/tcd/Plotting.py +++ b/scripts/tcd/Plotting.py @@ -18,7 +18,8 @@ from .Quadrature import Quadrature from .Initial_Condition import InitialCondition from .Basis_Function import Basis, OrthonormalLegendre from .projection_utils import calculate_exact_solution,\ - calculate_approximate_solution, Mesh + calculate_approximate_solution +from .Mesh import Mesh from .encoding_utils import decode_ndarray diff --git a/scripts/tcd/Troubled_Cell_Detector.py b/scripts/tcd/Troubled_Cell_Detector.py index 52f4cc2b4c475f8d1c90961fdb06e2a1391efe68..c84e2820407940cf59666efde8bba57928bee1f7 100644 --- a/scripts/tcd/Troubled_Cell_Detector.py +++ b/scripts/tcd/Troubled_Cell_Detector.py @@ -8,7 +8,7 @@ import numpy as np import torch from . import ANN_Model -from .projection_utils import Mesh +from .Mesh import Mesh class TroubledCellDetector(ABC): diff --git a/scripts/tcd/projection_utils.py b/scripts/tcd/projection_utils.py index 4f4b099eaf3bba5044c219830a1f8a8bfd338ed4..c6b710b2e98e8df12190a401d2342b910180b17b 100644 --- a/scripts/tcd/projection_utils.py +++ b/scripts/tcd/projection_utils.py @@ -4,14 +4,12 @@ """ -from __future__ import annotations -from functools import cache from typing import Tuple -import math import numpy as np from numpy import ndarray from sympy import Symbol +from .Mesh import Mesh from .Quadrature import Quadrature from .Initial_Condition import InitialCondition @@ -19,147 +17,6 @@ from .Initial_Condition import InitialCondition x = Symbol('x') -class Mesh: - """Class for mesh. - - Each cell is characterized by its center. - - Attributes - ---------- - mode : str - Mode for mesh use. Either 'training' or 'evaluation'. - num_cells : int - Number of cells in the mesh (ghost cells notwithstanding). Usually - exponential of 2. - bounds : Tuple[float, float] - Left and right boundary of the mesh interval. - interval_len : float - Length of the mesh interval. - cell_len : float - Length of a mesh cell. - cells : ndarray - Array of cell centers in mesh. - - Methods - ------- - create_data_dict() - Return dictionary with data necessary to construct mesh. - random_stencil(stencil_len) - Return random stencil. - - """ - - def __init__(self, num_cells: int, num_ghost_cells: int, - left_bound: float, right_bound: float, - training_data_mode: bool = False) -> None: - """Initialize Mesh. - - Parameters - ---------- - num_cells : int - Number of cells in the mesh (ghost cells notwithstanding). Has - to be an exponential of 2. - num_ghost_cells : int - Number of ghost cells on each side of the mesh. - left_bound : float - Left boundary of the mesh interval. - right_bound : float - Right boundary of the mesh interval. - training_data_mode : bool, optional - Flag indicating whether the mesh is used for training data - generation. Default: False. - - Raises - ------ - ValueError - If number of cells is not exponential of 2. - - """ - self._num_cells = num_cells - self._mode = 'training' if training_data_mode else 'evaluation' - if not training_data_mode: - if not math.log(self._num_cells, 2).is_integer(): - raise ValueError('The number of cells in the mesh has to be ' - 'an exponential of 2') - self._num_ghost_cells = num_ghost_cells - self._left_bound = left_bound - self._right_bound = right_bound - - @property - def mode(self) -> str: - """Return mode ('training' or 'evaluation').""" - return self._mode - - @property - def num_cells(self) -> int: - """Return number of mesh cells.""" - return self._num_cells - - @property - def bounds(self) -> Tuple[float, float]: - """Return left and right boundary of the mesh interval.""" - return self._left_bound, self._right_bound - - @property - def interval_len(self) -> float: - """Return the length of the mesh interval.""" - return self._right_bound - self._left_bound - - @property - def cell_len(self) -> float: - """Return the length of a mesh cell.""" - return self.interval_len/self.num_cells - - @property - @cache - def cells(self) -> ndarray: - """Return the cell centers of the mesh (including ghost cells).""" - return np.arange( - self._left_bound - (self._num_ghost_cells*2-1)/2*self.cell_len, - self._right_bound + (self._num_ghost_cells*2+1)/2*self.cell_len, - self.cell_len) - - @property - def non_ghost_cells(self) -> ndarray: - """Return the cell centers of the mesh (excluding ghost cells).""" - return self.cells[self._num_ghost_cells:-self._num_ghost_cells] - - def create_data_dict(self) -> dict: - """Return dictionary with data necessary to construct mesh.""" - return {'num_cells': self._num_cells, - 'left_bound': self._left_bound, - 'right_bound': self._right_bound, - 'num_ghost_cells': self._num_ghost_cells} - - def random_stencil(self, stencil_len: int) -> Mesh: - """Return random stencil. - - Build mesh with given number of cell centers around a random point - in the underlying interval. - - Returns - ------- - Mesh object - Mesh of given size around random point. - - """ - # Pick random point between left and right bound - point = np.random.uniform(self._left_bound, self._right_bound) - - # Adjust mesh spacing to be within interval if necessary - mesh_spacing = self.cell_len - max_spacing = 2/stencil_len*min(point-self._left_bound, - self._right_bound-point) - while mesh_spacing > max_spacing: - mesh_spacing /= 2 - - # Return new mesh instance - return Mesh(left_bound=point - stencil_len/2 * mesh_spacing, - right_bound=point + stencil_len/2 * mesh_spacing, - num_cells=stencil_len, num_ghost_cells=2, - training_data_mode=True) - - def calculate_approximate_solution( projection: ndarray, points: ndarray, polynomial_degree: int, basis: ndarray) -> ndarray: