Source code for polymesh.utils.tet

import numpy as np
from numpy import ndarray
from numba import njit, prange

__cache = True


[docs]@njit(nogil=True, cache=__cache) def vol_tet(ecoords: ndarray) -> ndarray: """ Calculates volumes of several tetrahedra. Parameters ---------- ecoords: numpy.ndarray A 3d float array of shape (nE, nNE, 3) of nodal coordinates for several elements. Here nE is the number of nodes and nNE is the number of nodes per element. Returns ------- numpy.ndarray 1d float array of volumes. Note ---- This only returns exact results for linear cells. For nonlinear cells, use objects that calculate the volumes using numerical integration. """ v1 = ecoords[1] - ecoords[0] v2 = ecoords[2] - ecoords[0] v3 = ecoords[3] - ecoords[0] return np.dot(np.cross(v1, v2), v3) / 6
[docs]@njit(nogil=True, parallel=True, cache=__cache) def vol_tet_bulk(ecoords: ndarray) -> ndarray: """ Calculates volumes of several tetrahedra. Parameters ---------- ecoords: numpy.ndarray A 3d float array of shape (nE, nNE, 3) of nodal coordinates for several elements. Here nE is the number of nodes and nNE is the number of nodes per element. Returns ------- numpy.ndarray 1d float array of volumes. Note ---- This only returns exact results for linear cells. For nonlinear cells, use objects that calculate the volumes using numerical integration. """ nE = len(ecoords) res = np.zeros(nE, dtype=ecoords.dtype) for i in prange(nE): res[i] = vol_tet(ecoords[i]) return np.abs(res)
[docs]@njit(nogil=True, cache=__cache) def glob_to_nat_tet(gcoord: ndarray, ecoords: ndarray) -> ndarray: """ Transformation from global to natural coordinates within a tetrahedron. Notes ----- This function is numba-jittable in 'nopython' mode. """ ecoords_ = np.zeros_like(ecoords) ecoords_[:, :] = ecoords[:, :] V = vol_tet(ecoords) ecoords_[0, :] = gcoord v1 = vol_tet(ecoords_) / V ecoords_[0, :] = ecoords[0, :] ecoords_[1, :] = gcoord v2 = vol_tet(ecoords_) / V ecoords_[1, :] = ecoords[1, :] ecoords_[2, :] = gcoord v3 = vol_tet(ecoords_) / V ecoords_[2, :] = ecoords[2, :] return np.array([v1, v2, v3, 1 - v1 - v2 - v3], dtype=gcoord.dtype)
@njit(nogil=True, parallel=True, cache=__cache) def _glob_to_nat_tet_bulk_(points: ndarray, ecoords: ndarray) -> ndarray: nE = ecoords.shape[0] nP = points.shape[0] res = np.zeros((nP, nE, 4), dtype=points.dtype) for i in prange(nP): for j in prange(nE): res[i, j, :] = glob_to_nat_tet(points[i], ecoords[j]) return res @njit(nogil=True, parallel=True, cache=__cache) def __pip_tet_bulk__(nat: ndarray, tol: float = 1e-12) -> ndarray: nP, nE = nat.shape[:2] res = np.zeros((nP, nE), dtype=np.bool_) for i in prange(nP): for j in prange(nE): c1 = np.all(nat[i, j] > (-tol)) c2 = np.all(nat[i, j] < (1 + tol)) res[i, j] = c1 & c2 return res @njit(nogil=True, cache=__cache) def _pip_tet_bulk_(points: ndarray, ecoords: ndarray, tol: float = 1e-12) -> ndarray: nat = _glob_to_nat_tet_bulk_(points, ecoords) return __pip_tet_bulk__(nat, tol) @njit(nogil=True, cache=__cache) def _pip_tet_bulk_knn_( points: ndarray, ecoords: ndarray, neighbours: ndarray, tol: float = 1e-12 ) -> ndarray: nat = _glob_to_nat_tet_bulk_knn_(points, ecoords, neighbours) return __pip_tet_bulk__(nat, tol) @njit(nogil=True, parallel=True, cache=__cache) def _glob_to_nat_tet_bulk_knn_( points: ndarray, ecoords: ndarray, neighbours: ndarray ) -> ndarray: kE = neighbours.shape[1] nP = points.shape[0] res = np.zeros((nP, kE, 4), dtype=points.dtype) for i in prange(nP): for k in prange(kE): res[i, k, :] = glob_to_nat_tet(points[i], ecoords[neighbours[i, k]]) return res
[docs]@njit(nogil=True, cache=__cache) def lcoords_tet() -> ndarray: """ Returns coordinates of the master element of a simplex in 3d. """ return np.array( [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]] )
[docs]@njit(nogil=True, cache=__cache) def nat_to_loc_tet(acoord: np.ndarray) -> ndarray: """ Transformation from natural to local coordinates within a tetrahedra. Notes ----- This function is numba-jittable in 'nopython' mode. """ return acoord.T @ lcoords_tet()