Source code for g3d.mesh.geo.face

"""mesh building block - Face class definition"""
import os
from typing import Any, Union, Tuple, IO

if os.environ.get('__USE_CUDA', '0') == '1':
    import cupy as np
    from cupy import ndarray
else:
    import numpy as np
    from numpy import ndarray

import re

from g3d.defs import G3DWorld
from g3d.defs import FaceOrientation
from g3d.defs import INTFTypes
from g3d.defs import AngleType
from g3d.defs import FunctionByPass

from g3d.mesh.geo import Coordinates
from g3d.mesh.geo import Coord

from g3d.flow.placeholders import FMP


[docs] class Face(Coordinates): def __init__(self, *args: Any, **kwargs: Any) -> None: self._it = None self._face_type = None self._check = "not checked" self._alpha = 0. self._delta = Coord() self._im = 0 self._i0 = 0 self._j0 = 0 self._k0 = 0 self._idir = 0 self._jdir = 0 self._npi = 0 self._npj = 0 super().__init__(*args, **kwargs) self.__reset_FMP() def _set_from_args(self, *args: Any, **kwargs: Any) -> ndarray: bps = self._get_function_evaluate_status(**kwargs) if bps is FunctionByPass.SELF: args_stat = np.ones(len(args)) else: args_stat = super()._set_from_args(*args, bps=FunctionByPass.BYPASS) if bps in [FunctionByPass.EVALUATE, FunctionByPass.SELF]: if np.sum(args_stat) > 0: face_def = [] for i in range(len(args)): if args_stat[i] == 1: arg = args[i] if type(arg) in [int, np.int64, np.int32]: args_stat[i] = 0 if type(arg) in [np.int64, np.int32]: face_def.append(arg.item()) else: face_def.append(arg) elif type(arg) is Face: # if caught by a super class, the child class instance of copy will be used args_stat[i] = 0 self.copy(arg) elif type(arg) is list: args_stat[i] = 0 if self._list_is_all_ints(arg): self.__init_def(arg) if len(face_def) >= 8: # will be caught by the for-loop below in a sub call to _set_from_args self.__init_def(face_def) return args_stat def __init_def(self, fd: list) -> None: if len(fd) == 8: self._im, self._i0, self._j0, self._k0, self._idir, self._jdir, self._npi, self._npj = fd elif len(fd) == 9: # rotation angle specified self._im, self._i0, self._j0, self._k0, self._idir, self._jdir, self._npi, self._npj, self._alpha = fd elif len(fd) == 11: # translation data specified self._im, self._i0, self._j0, self._k0, self._idir, self._jdir, self._npi, self._npj, \ self._delta.x, self._delta.y, self._delta.z = fd def _set_default(self) -> None: self.__reset_def() super()._set_default() self._tag = 'g3d_face' def __reset_def(self) -> None: self._im = 0 self._i0 = 0 self._j0 = 0 self._k0 = 0 self._idir = 0 self._jdir = 0 self._npi = 0 self._npj = 0 def __reset_FMP(self) -> None: self._FMP = FMP()
[docs] def set_from_key_value(self, key: str, value: Any) -> bool: if super().set_from_key_value(key, value): return True elif key == 'delta_x': self._delta.x = value return True elif key == 'delta_y': self._delta.y = value return True elif key == 'delta_z': self._delta.z = value return True elif key == 'alpha': self._alpha = value return True elif key == 'it': self._it = value return True elif key == 'face_type': self._face_type = value return True return False
def __initFace(self, f: Union['Face', list] = None) -> None: if f is not None: if type(f) is Face: self.copy(f) elif len(f) == 8: self._im, self._i0, self._j0, self._k0, self._idir, self._jdir, self._npi, self._npj = f elif len(f) == 9: # rotation angle specified self._im, self._i0, self._j0, self._k0, self._idir, self._jdir, self._npi, self._npj, self._alpha = f elif len(f) == 11: # translation data specified self._im, self._i0, self._j0, self._k0, self._idir, self._jdir, self._npi, self._npj, \ self._delta.x, self._delta.y, self._delta.z = f else: self._im, self._i0, self._j0, self._k0, self._idir, self._jdir, self._npi, self._npj = [0, 0, 0, 0, 0, 0, 0, 0] else: self._im, self._i0, self._j0, self._k0, self._idir, self._jdir, self._npi, self._npj = [0, 0, 0, 0, 0, 0, 0, 0]
[docs] def allocate_XYZ(self, N: int = None) -> None: self._size = self._npi * self._npj super().allocate_XYZ(N)
@property def im(self) -> int: """ :return: """ return self._im @im.setter def im(self, i_val: int) -> None: self._im = i_val @property def i0(self) -> int: """ :return: """ return self._i0 @i0.setter def i0(self, i_val: int) -> None: self._i0 = i_val @property def j0(self) -> int: """ :return: """ return self._j0 @j0.setter def j0(self, i_val: int) -> None: self._j0 = i_val @property def k0(self) -> int: """ :return: """ return self._k0 @k0.setter def k0(self, i_val: int) -> None: self._k0 = i_val @property def idir(self) -> int: """ :return: """ return self._idir @idir.setter def idir(self, i_val: int) -> None: self._idir = i_val @property def jdir(self) -> int: """ :return: """ return self._jdir @jdir.setter def jdir(self, i_val: int) -> None: self._jdir = i_val @property def npi(self) -> int: """ :return: """ return self._npi @npi.setter def npi(self, i_val: int) -> None: self._npi = i_val @property def npj(self) -> int: """ :return: """ return self._npj @npj.setter def npj(self, i_val: int) -> None: self._npj = i_val @property def it(self) -> Union[int, None]: """ :return: """ return self._it @it.setter def it(self, i_val: int) -> None: self._it = i_val @property def face_type(self) -> str: """ :return: """ return self._face_type @face_type.setter def face_type(self, val: str) -> None: self._face_type = val @property def check(self) -> str: """ :return: """ return self._check @check.setter def check(self, cs: str) -> None: self._check = cs @property def alpha(self) -> float: """ :return: """ return self._alpha @alpha.setter def alpha(self, a: float) -> None: self._alpha = a @property def delta(self) -> Coord: """ :return: """ return self._delta @property def FMP(self) -> FMP: """ :return: """ return self._FMP @property def FMP_size(self) -> int: """ :return: """ return self._FMP.size
[docs] def set_def(self, f: Union['Face', list] = None) -> None: """ :param f: """ self.__initFace(f)
[docs] def read_def_from_file(self, f: IO[str]) -> None: """ :param f: """ regex_face_def = re.compile(r'^\s*(?P<im>\d+)\s+(?P<i0>\d+)\s+(?P<j0>\d+)\s+(?P<k0>\d+)' r'\s+(?P<idir>\d+)\s+(?P<jdir>\d+)\s+(?P<npi>\d+)\s+(?P<npj>\d+)') while True: line = f.readline() match = regex_face_def.search(line) if match: self._im = int(match.group('im')) self._i0 = int(match.group('i0')) self._j0 = int(match.group('j0')) self._k0 = int(match.group('k0')) self._idir = int(match.group('idir')) self._jdir = int(match.group('jdir')) self._npi = int(match.group('npi')) self._npj = int(match.group('npj')) break
[docs] def print(self) -> None: print(' face type: %s' % self._face_type) print(' face tag : %s' % self._tag) print(' im=%4d, i0=%4d, j0=%4d, k0=%4d, idir=%3d, jdir=%3d, npi=%4d, npj=%4d' % (self._im, self._i0, self._j0, self._k0, self._idir, self._jdir, self._npi, self._npj)) print(' check status: %s' % self._check)
[docs] def get_face_count(self) -> int: """ :return: """ return (self._npi - 1) * (self._npj - 1)
[docs] def get_node_count(self) -> int: """ :return: """ return self._npi * self._npj
[docs] def get_cell_count(self) -> int: """ :return: """ return self.get_face_count()
[docs] def swap_normal(self) -> None: """ """ tmp = self._idir self._idir = self._jdir self._jdir = tmp tmp = self._npi self._npi = self._npj self._npj = tmp
[docs] def copy(self, f: 'Face') -> None: super().copy(f) self.copy_def(f) self._it = f.it self._face_type = f.face_type if f.size > 0: self.allocate_XYZ() self.copy_XYZ(f)
[docs] def copy_def(self, f: 'Face') -> None: """ :param f: """ self._im = f.im self._i0 = f.i0 self._j0 = f.j0 self._k0 = f.k0 self._idir = f.idir self._jdir = f.jdir self._npi = f.npi self._npj = f.npj
[docs] def get_def(self, normal: Any = FaceOrientation.OUTWARD_FACING_NORMAL) -> Tuple[int, ...]: """ :param normal: :return: """ if normal == FaceOrientation.INWARD_FACING_NORMAL: return self._im, self._i0, self._j0, self._k0, self._jdir, self._idir, self._npj, self._npi else: return self._im, self._i0, self._j0, self._k0, self._idir, self._jdir, self._npi, self._npj
[docs] def get_delta(self) -> list[float]: """ :return: """ return [self._delta.x, self._delta.y, self._delta.z]
def __get_lp(self, i: int, j: int) -> int: # local 0-based indices return i + self._npi * j
[docs] def get_node(self, i: int, j: int) -> int: """ :param i: :param j: :return: """ return self.__get_lp(i, j)
[docs] def get_index(self, i: int, j: int) -> int: # local 1-based indices """ :param i: :param j: :return: """ return self.__get_lp(i - 1, j - 1)
[docs] def generate_offset_Face(self, offset: float) -> 'Face': """ :param offset: :return: """ b = Face(self) N = len(self._X) nx = np.zeros(N) ny = np.zeros(N) nz = np.zeros(N) for jp in range(self._npj - 1): for ip in range(self._npi - 1): lp = ip + jp * self._npi x1 = self._X[lp] y1 = self._Y[lp] z1 = self._Z[lp] x2 = self._X[lp + 1] y2 = self._Y[lp + 1] z2 = self._Z[lp + 1] x3 = self._X[lp + self._npi] y3 = self._Y[lp + self._npi] z3 = self._Z[lp + self._npi] x4 = self._X[lp + 1 + self._npi] y4 = self._Y[lp + 1 + self._npi] z4 = self._Z[lp + 1 + self._npi] nx[lp] += (y2 - y1) * (z3 - z1) - (y3 - y1) * (z2 - z1) ny[lp] += (x3 - x1) * (z2 - z1) - (x2 - x1) * (z3 - z1) nz[lp] += (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1) nx[lp + 1] += (y4 - y2) * (z1 - z2) - (y1 - y2) * (z4 - z2) ny[lp + 1] += (x1 - x2) * (z4 - z2) - (x4 - x2) * (z1 - z2) nz[lp + 1] += (x4 - x2) * (y1 - y2) - (x1 - x2) * (y4 - y2) nx[lp + self._npi] += (y1 - y3) * (z4 - z3) - (y4 - y3) * (z1 - z3) ny[lp + self._npi] += (x4 - x3) * (z1 - z3) - (x1 - x3) * (z4 - z3) nz[lp + self._npi] += (x1 - x3) * (y4 - y3) - (x4 - x3) * (y1 - y3) nx[lp + self._npi + 1] += (y3 - y4) * (z2 - z4) - (z3 - z4) * (y2 - y4) ny[lp + self._npi + 1] += (x2 - x4) * (z3 - z4) - (x3 - x4) * (z2 - z4) nz[lp + self._npi + 1] += (x3 - x4) * (y2 - y4) - (x2 - x4) * (y3 - y4) X_offset, Y_offset, Z_offset = b.get_XYZ() for jp in range(self._npj): for ip in range(self._npi): lp = ip + jp * self._npi r = np.sqrt(nx[lp] ** 2 + ny[lp] ** 2 + nz[lp] ** 2) r = max(r, 1.e-20) X_offset[lp] = self._X[lp] + offset * nx[lp] / r Y_offset[lp] = self._Y[lp] + offset * ny[lp] / r Z_offset[lp] = self._Z[lp] + offset * nz[lp] / r return b
[docs] def shift(self, **kwargs: Any) -> None: """ :param kwargs: :return: """ x_shift = 0. y_shift = 0. z_shift = 0. if len(kwargs) != 0: g3d_world = G3DWorld() for key, value in kwargs.items(): if g3d_world.display.verbose: print('%s == %s' % (key, str(value))) if key == 'x_shift': x_shift = value elif key == 'y_shift': y_shift = value elif key == 'z_shift': z_shift = value else: print('warning! parameter %s is not defined' % key) if x_shift == 0. and y_shift == 0. and z_shift == 0.: print('warning! no shift specified') return for jp in range(self._npj): for ip in range(self._npi): lp = self.__get_lp(ip, jp) self._X[lp] += x_shift self._Y[lp] += y_shift self._Z[lp] += z_shift
[docs] def rotate(self, **kwargs: Any) -> None: """ :param kwargs: :return: """ alpha = 0. beta = 0. gamma = 0. angle_dim = AngleType.DEGREES if len(kwargs) != 0: g3d_world = G3DWorld() for key, value in kwargs.items(): if g3d_world.display.verbose: print('%s == %s' % (key, str(value))) if key == 'alpha': alpha = value elif key == 'beta': beta = value elif key == 'gamma': gamma = value elif key == 'angle_dim': angle_dim = value else: print('warning! parameter %s is not defined' % key) if alpha == 0. and beta == 0. and gamma == 0.: print('warning! no rotation angle specified') return if angle_dim == AngleType.DEGREES: alpha *= np.pi / 180. beta *= np.pi / 180. gamma *= np.pi / 180. eps = 1.e-6 csa = np.cos(alpha) ssa = np.sin(alpha) csb = np.cos(beta) ssb = np.sin(beta) csg = np.cos(gamma) ssg = np.sin(gamma) for jp in range(self._npj): for ip in range(self._npi): lp = self.__get_lp(ip, jp) if np.abs(alpha) > eps: yy = self._Y[lp] zz = self._Z[lp] self._Y[lp] = csa * yy - ssa * zz self._Z[lp] = ssa * yy + csa * zz if np.abs(beta) > eps: xx = self._X[lp] zz = self._Z[lp] self._Z[lp] = csb * zz + ssb * xx self._X[lp] = -ssb * zz + csb * xx if np.abs(gamma) > eps: xx = self._X[lp] yy = self._Y[lp] self._X[lp] = csg * xx - ssg * yy self._Y[lp] = ssg * xx + csg * yy
# FluxMolecule related functions
[docs] def allocate_FMP(self, mf: int = 2) -> None: """ :param mf: """ self._FMP.allocate(size=self.get_face_count() * mf)
[docs] def deallocate_FMP(self) -> None: """ """ self.__reset_FMP()
[docs] def check_FMP_cell_metrics(self, ic: int, check_sum: Union[list, ndarray]) -> None: """ :param ic: :param check_sum: """ print(' face tag: %s' % self._tag) self._FMP.check_cell_metrics(ic, check_sum)
[docs] class Glue: """ """ def __init__(self, face_def_A: Union['Face', list] = None, face_def_B: Union['Face', list] = None) -> None: self.__A = Face(face_def_A) self.__B = Face(face_def_B) self._type = INTFTypes.UNDEFINED if self.__A.alpha != 0. or self.__B.alpha != 0.: self._type = INTFTypes.ROTPERINT if self.__A.delta.length() != 0 or self.__B.delta.length() != 0: self._type = INTFTypes.TRANSPERINT @property def type(self) -> Any: """ :return: """ return self._type
[docs] def get_face_defs(self) -> Tuple[Face, Face]: """ :return: """ return self.__A, self.__B
[docs] def set_face_defs(self, face_def_A: Union['Face', list] = None, face_def_B: Union['Face', list] = None) -> None: """ :param face_def_A: :param face_def_B: """ self.__A.set_def(face_def_A) self.__B.set_def(face_def_B)