"""Flux molecule placeholder (FMP class definition)"""
from typing import Any, Union, Tuple, TextIO
import os
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
from g3d.defs import G3DWorld
from g3d.defs import DIMMode
from g3d.defs import FMPTypes
from g3d.defs import G3DEntity
from g3d.defs import FunctionByPass
[docs]
class FMP(G3DEntity):
"""Definition of class FMP: Flux Molecule Pointers - cell/node pointers and metrics data container"""
def __init__(self, *args: Any, **kwargs: Any) -> None:
self._size = 0
self._type = FMPTypes.UNDEFINED
self._fctj = 0.25 * np.ones(self._size)
self._fctk = 0.25 * np.ones(self._size)
self._kc = np.zeros((self._size, 12), dtype=np.int64)
self._kp = np.zeros((self._size, 12), dtype=np.int64)
self._sl = np.zeros(self._size)
self._voli = np.ones(self._size)
self._s = np.zeros((self._size, 3))
self._sx = np.zeros((self._size, 3))
self._sy = np.zeros((self._size, 3))
self._sz = np.zeros((self._size, 3))
self._si = np.zeros((self._size, 3))
self._y_norm = np.zeros(self._size)
self._tmp = np.zeros(self._size)
super().__init__(*args, **kwargs)
self.allocate(**kwargs)
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)
if bps in [FunctionByPass.EVALUATE, FunctionByPass.SELF]:
if np.sum(args_stat) == 1:
size_set = False
for i in range(len(args)):
if args_stat[i] == 1:
arg = args[i]
if type(arg) is int and not size_set:
args_stat[i] = 0
self._size = arg
size_set = True
return args_stat
def _set_default(self) -> None:
super()._set_default()
self._tag = 'g3d_flux_molecule'
[docs]
def set_from_key_value(self, key: str, value: Any) -> bool:
"""Sets data from key-value pair input
Parameters
----------
key: str :
keyword
valid class-specific keywords: 'size', 'type'
value: Any :
value corresponding to keyword
Returns
-------
bool
status - True if key is found in list of valid keywords
"""
if super().set_from_key_value(key, value):
return True
elif key == 'size':
self._size = value
return True
elif key == 'type':
self._type = value
return True
return False
[docs]
def allocate(self, **kwargs: Any) -> None:
"""Allocates data storage arrays
Parameters
----------
**kwargs: Any :
keyword-value pairs, see :func:'set_from_key_value', optional input
"""
if len(kwargs):
self.set(**kwargs)
self.__de_allocate()
if self._size > 0:
self._fctj = 0.25 * np.ones(self._size)
self._fctk = 0.25 * np.ones(self._size)
self._kc = np.zeros((self._size, 12), dtype=np.int64)
self._kp = np.zeros((self._size, 12), dtype=np.int64)
self._sl = np.zeros(self._size)
self._voli = np.ones(self._size)
self._s = np.zeros((self._size, 3))
self._sx = np.zeros((self._size, 3))
self._sy = np.zeros((self._size, 3))
self._sz = np.zeros((self._size, 3))
self._si = np.zeros((self._size, 3))
@property
def size(self) -> int:
"""Placeholder size
Returns
-------
int
size
"""
return self._size
@size.setter
def size(self, val: int) -> None:
self._size = val
@property
def type(self) -> Any:
"""Placeholder type
Returns
-------
FMPTypes
enum describing placeholder type
"""
return self._type
@type.setter
def type(self, val: Any) -> None:
if type(val) is FMPTypes:
self._type = val
@property
def fctj(self) -> ndarray:
"""Face local j-direction multiplication factor
Returns
-------
ndarray
local j-direction factors for all placeholder faces
"""
return self._fctj
@property
def fctk(self) -> ndarray:
"""Face local k-direction multiplication factor
Returns
-------
ndarray
local k-direction factors for all placeholder faces
"""
return self._fctk
@property
def kc(self) -> ndarray:
"""Cell index pointers for flux molecule cells (12 per molecule)
Returns
-------
ndarray
cell pointers
"""
return self._kc
@property
def kp(self) -> ndarray:
"""Node index pointers for flux molecule cells (12 per molecule)
Returns
-------
ndarray
node pointers
"""
return self._kp
@property
def sl(self) -> ndarray:
"""Face area for all flux molecules (central molecule face)
Returns
-------
ndarray:
face area array
"""
return self._sl
@property
def voli(self) -> ndarray:
"""Inverse of flux molecule volume
Returns
-------
ndarray
inverse volume array
"""
return self._voli
@property
def s(self) -> ndarray:
""":return:"""
return self._s
@property
def sx(self) -> ndarray:
""":return:"""
return self._sx
@property
def sy(self) -> ndarray:
""":return:"""
return self._sy
@property
def sz(self) -> ndarray:
""":return:"""
return self._sz
@property
def si(self) -> ndarray:
""":return:"""
return self._si
@property
def y_norm(self) -> ndarray:
"""Wall-normal vector
Returns
-------
ndarray
wall-normal vector (n_x, n_y, n_z)
"""
return self._y_norm
@property
def tmp(self) -> ndarray:
"""Temporary storage array
Returns
-------
ndarray
temporary storage array access
"""
return self._tmp
def __de_allocate(self) -> None:
self._fctj = []
self._fctk = []
self._kc = np.zeros((12,), dtype=np.int64)
self._kp = np.zeros((12,), dtype=np.int64)
self._sl = []
self._voli = []
self._s = np.zeros((3,))
self._sx = np.zeros((3,))
self._sy = np.zeros((3,))
self._sz = np.zeros((3,))
self._si = np.zeros((3,))
self._y_norm = []
self._tmp = []
[docs]
def allocate_tmp_arrays(self, N: int = 1) -> None:
"""Allocates arrays for temporary data storage
Parameters
----------
N: int :
number of tmp storage arrays (Default value = 1)
"""
self._tmp = np.zeros((self._size, N))
[docs]
def get_tmp_storage(self, col: int = 0) -> ndarray:
"""Gets access to temporary storage array
Parameters
----------
col: int :
column in temporary storage matrix (Default value = 0)
Returns
-------
ndarray
temporary storage array
"""
return self._tmp[:, col]
[docs]
def set_pointers(self, idx: int,
kp: Union[ndarray, list[int]],
kc: Union[ndarray, list[int]]) -> None:
"""Populate cell and node pointers using provided arrays
Parameters
----------
idx: int :
face index
kp: ndarray or list[int] :
node indices (12 nodes per molecule)
kc: ndarray or list[int] :
cell indices (12 cells per molecule)
"""
self._kp[idx, :] = kp[:]
self._kc[idx, :] = kc[:]
[docs]
def set_factors(self, idx: int, fctj: float, fctk: float) -> None:
"""Update flux molecule weight factors
Weight factors are needed for calculation of cell face gradients and diffusive fluxes. The provided weight
factors represents the flux molecule local j- and k-directions, respectively. The local i-direction of a flux
molecule is always aligned with the center face normal (i.e. in the convective molecule direction)
Parameters
----------
idx: int :
cell index
fctj: float :
weight factor local j-direction
fctk: float :
weight factor local k-direction
"""
self._fctj[idx] = fctj
self._fctk[idx] = fctk
[docs]
def set_data(self, idx: int,
kp: Union[ndarray, list[int]],
kc: Union[ndarray, list[int]],
fctj: float, fctk: float) -> None:
"""Set flux molecule data (cell and node pointers and weight factors)
See documentation of :func:'set_pointers' and :func:'set_factors'
Parameters
----------
idx: int :
flux molecule index
kp: ndarray or list[int] :
node indices (12 nodes per molecule)
kc: ndarray or list[int] :
cell indices (12 cells per molecule)
fctj: float :
weight factor local j-direction
fctk: float :
weight factor local k-direction
"""
self.set_pointers(idx, kp, kc)
self.set_factors(idx, fctj, fctk)
[docs]
def get_pointers(self, idx: int = None) -> Tuple[ndarray, ndarray]:
"""Gets node and cell pointers for all defined flux molecules or a specific flux molecule.
Parameters
----------
idx: int :
flux molecule index (Default value = None)
Returns
-------
tuple
node and cell pointers for a single flux molecule (if index is specified) or for all defined flux molecules
in container (kp, kc) where kp and kc both are arrays
"""
if idx is None:
return self._kp, self._kc
else:
return self._kp[idx, :], self._kc[idx, :]
[docs]
def get_factors(self, idx: int = None) -> Union[Tuple[float, float], Tuple[ndarray, ndarray]]:
"""Gets weight factors for all defined flux molecules or a specific flux molecule.
Parameters
----------
idx: int :
flux molecule index (Default value = None)
Returns
-------
tuple
weight factors in local j- and k-directions for all defined flux molecules in container or one specific
flux molecule (if flux molecule index is provided)
"""
if idx is None:
return self._fctj, self._fctk
else:
return self._fctj[idx], self._fctk[idx]
[docs]
def get_conv_metrics(self, idx: int = None) -> Union[Tuple[float, float], Tuple[ndarray, ndarray]]:
"""Get metrics data used for convective flux calculations for all flux molecules or for a specific
flux molecule
Parameters
----------
idx: int :
flux molecule index (Default value = None)
Returns
-------
tuple
face area
"""
if idx is None:
return self._s, self._sl
else:
return self._s[idx, :], self._sl[idx]
[docs]
def get_diff_metrics(self, idx: int = None) -> Union[Tuple[float, ...], Tuple[ndarray, ...]]:
"""Get metrics data used for diffusive flux calculations for all flux molecules or for a specific
flux molecule
Parameters
----------
idx: int :
flux molecule index (Default value = None)
Returns
-------
tuple
"""
if idx is None:
return self._sx, self._sy, self._sz, self._si, self._voli
else:
return self._sx[idx, :], self._sy[idx, :], self._sz[idx, :], self._si[idx, :], self._voli[idx]
[docs]
def get_wall_normal(self, idx: int = None) -> Union[float, ndarray]:
"""Gets wall-normal for all flux molecules or for a specific flux molecule
Parameters
----------
idx: int :
flux molecule index (Default value = None)
Returns
-------
float or ndarray
wall-normal vector
"""
if idx is None:
return self._y_norm
else:
return self._y_norm[idx]
[docs]
def print(self, idx: int = None) -> None:
"""Prints flux molecule data (dell pointers, node pointers, and weight factors) for all flux molecules or for
a specific flux molecule
Parameters
----------
idx: int :
flux molecule index (Default value = None)
"""
if idx is None:
for i in range(self._size):
self.print(i)
else:
print(self._fctj[idx], self._fctk[idx])
print(self._kp[idx][:])
print(self._kc[idx][:])
[docs]
def update_factors(self, idx: int, mim: int, mip: int, mjm: int, mjp: int) -> None:
"""Update flux molecule weight factors
Parameters
----------
idx : int :
flux molecule index
mim : int :
number of flux molecule cells in negative local i-direction (0 at low-i boundary)
mip : int :
number of flux molecule cells in positive local i-direction (0 at high-i boundary)
mjm : int :
number of flux molecule cells in negative local j-direction (0 at low-j boundary)
mjp : int :
number of flux molecule cells in positive local j-direction (0 at high-j boundary)
"""
self._fctj[idx] = 0.25
self._fctk[idx] = 0.25
if mim == 0:
self._fctj[idx] += 0.25
if mip == 0:
self._fctj[idx] += 0.25
if mjm == 0:
self._fctk[idx] += 0.25
if mjp == 0:
self._fctk[idx] += 0.25
if self._fctj[idx] == 0.75:
self._fctj[idx] = 0.0
if self._fctk[idx] == 0.75:
self._fctk[idx] = 0.0
[docs]
def update_block_interface_factors(self, idx: int, mim: int, mip: int, mjm: int, mjp: int) -> None:
"""Update flux molecule weight factors for mesh block interfaces
Parameters
----------
idx : int :
flux molecule index
mim : int :
number of flux molecule cells in negative local i-direction (0 at low-i boundary)
mip : int :
number of flux molecule cells in positive local i-direction (0 at high-i boundary)
mjm : int :
number of flux molecule cells in negative local j-direction (0 at low-j boundary)
mjp : int :
number of flux molecule cells in positive local j-direction (0 at high-j boundary)
"""
self._fctj[idx] = 0.25
self._fctk[idx] = 0.25
if mim == 0 and mip == 0:
self._fctj[idx] = 0.0
elif mim == 0 or mip == 0:
self._fctj[idx] = 0.5
if mjm == 0 and mjp == 0:
self._fctk[idx] = 0.0
elif mjm == 0 or mjp == 0:
self._fctk[idx] = 0.5
[docs]
def update_metrics(self, x: ndarray, y: ndarray, z: ndarray) -> None:
"""Update flux molecule metrics data
Parameters
----------
x : ndarray :
x-coordinate vector
y : ndarray :
y-coordinate vector
z : ndarray :
z-coordinate vector
"""
g3d_world = G3DWorld()
idx1 = 0
idx2 = self._size
self._s[idx1:idx2, 0] = 0.5 * ((y[self._kp[idx1:idx2, 3 + 4]] - y[self._kp[idx1:idx2, 0 + 4]]) *
(z[self._kp[idx1:idx2, 2 + 4]] - z[self._kp[idx1:idx2, 1 + 4]]) -
(z[self._kp[idx1:idx2, 3 + 4]] - z[self._kp[idx1:idx2, 0 + 4]]) *
(y[self._kp[idx1:idx2, 2 + 4]] - y[self._kp[idx1:idx2, 1 + 4]]))
self._s[idx1:idx2, 1] = 0.5 * ((z[self._kp[idx1:idx2, 3 + 4]] - z[self._kp[idx1:idx2, 0 + 4]]) *
(x[self._kp[idx1:idx2, 2 + 4]] - x[self._kp[idx1:idx2, 1 + 4]]) -
(x[self._kp[idx1:idx2, 3 + 4]] - x[self._kp[idx1:idx2, 0 + 4]]) *
(z[self._kp[idx1:idx2, 2 + 4]] - z[self._kp[idx1:idx2, 1 + 4]]))
self._s[idx1:idx2, 2] = 0.5 * ((x[self._kp[idx1:idx2, 3 + 4]] - x[self._kp[idx1:idx2, 0 + 4]]) *
(y[self._kp[idx1:idx2, 2 + 4]] - y[self._kp[idx1:idx2, 1 + 4]]) -
(y[self._kp[idx1:idx2, 3 + 4]] - y[self._kp[idx1:idx2, 0 + 4]]) *
(x[self._kp[idx1:idx2, 2 + 4]] - x[self._kp[idx1:idx2, 1 + 4]]))
if g3d_world.options.dim_mode is DIMMode.G2D_AXISYMM:
r = 0.25 * (y[self._kp[idx1:idx2, 0 + 4]] +
y[self._kp[idx1:idx2, 1 + 4]] +
y[self._kp[idx1:idx2, 2 + 4]] +
y[self._kp[idx1:idx2, 3 + 4]])
self._s[idx1:idx2, 0] = r * self._s[idx1:idx2, 0]
self._s[idx1:idx2, 1] = r * self._s[idx1:idx2, 1]
self._s[idx1:idx2, 2] = r * self._s[idx1:idx2, 2]
self._sl[idx1:idx2] = (self._s[idx1:idx2, 0] ** 2 + self._s[idx1:idx2, 1] ** 2 + self._s[
idx1:idx2, 2] ** 2) ** 0.5
[docs]
def update_diff_metrics(self,
x: ndarray,
y: ndarray,
z: ndarray,
n_faces: int = 0, idx_start: int = 0) -> None:
"""Update flux molecule metrics data for diffusive flux calculations
Parameters
----------
x: ndarray :
x-coordinate vector
y: ndarray :
y-coordinate vector
z: ndarray :
z-coordinate vector
n_faces: int :
number of faces (Default value = 0)
idx_start: int :
index of first face (Default value = 0)
"""
g3d_world = G3DWorld()
if n_faces == 0:
n_faces = self._size - idx_start
idx1 = idx_start
idx2 = idx_start + n_faces
xi = .125 * (x[self._kp[idx1:idx2, 8]] +
x[self._kp[idx1:idx2, 9]] +
x[self._kp[idx1:idx2, 10]] +
x[self._kp[idx1:idx2, 11]] -
x[self._kp[idx1:idx2, 0]] -
x[self._kp[idx1:idx2, 1]] -
x[self._kp[idx1:idx2, 2]] -
x[self._kp[idx1:idx2, 3]])
yi = .125 * (y[self._kp[idx1:idx2, 8]] +
y[self._kp[idx1:idx2, 9]] +
y[self._kp[idx1:idx2, 10]] +
y[self._kp[idx1:idx2, 11]] -
y[self._kp[idx1:idx2, 0]] -
y[self._kp[idx1:idx2, 1]] -
y[self._kp[idx1:idx2, 2]] -
y[self._kp[idx1:idx2, 3]])
zi = .125 * (z[self._kp[idx1:idx2, 8]] +
z[self._kp[idx1:idx2, 9]] +
z[self._kp[idx1:idx2, 10]] +
z[self._kp[idx1:idx2, 11]] -
z[self._kp[idx1:idx2, 0]] -
z[self._kp[idx1:idx2, 1]] -
z[self._kp[idx1:idx2, 2]] -
z[self._kp[idx1:idx2, 3]])
xj = .5 * (x[self._kp[idx1:idx2, 5]] +
x[self._kp[idx1:idx2, 7]] -
x[self._kp[idx1:idx2, 4]] -
x[self._kp[idx1:idx2, 6]])
yj = .5 * (y[self._kp[idx1:idx2, 5]] +
y[self._kp[idx1:idx2, 7]] -
y[self._kp[idx1:idx2, 4]] -
y[self._kp[idx1:idx2, 6]])
zj = .5 * (z[self._kp[idx1:idx2, 5]] +
z[self._kp[idx1:idx2, 7]] -
z[self._kp[idx1:idx2, 4]] -
z[self._kp[idx1:idx2, 6]])
xk = .5 * (x[self._kp[idx1:idx2, 6]] +
x[self._kp[idx1:idx2, 7]] -
x[self._kp[idx1:idx2, 4]] -
x[self._kp[idx1:idx2, 5]])
yk = .5 * (y[self._kp[idx1:idx2, 6]] +
y[self._kp[idx1:idx2, 7]] -
y[self._kp[idx1:idx2, 4]] -
y[self._kp[idx1:idx2, 5]])
zk = .5 * (z[self._kp[idx1:idx2, 6]] +
z[self._kp[idx1:idx2, 7]] -
z[self._kp[idx1:idx2, 4]] -
z[self._kp[idx1:idx2, 5]])
self._sx[idx1:idx2, 0] = (yj * zk) - (zj * yk)
self._sy[idx1:idx2, 0] = (zj * xk) - (xj * zk)
self._sz[idx1:idx2, 0] = (xj * yk) - (yj * xk)
self._sx[idx1:idx2, 1] = (yk * zi) - (zk * yi)
self._sy[idx1:idx2, 1] = (zk * xi) - (xk * zi)
self._sz[idx1:idx2, 1] = (xk * yi) - (yk * xi)
self._sx[idx1:idx2, 2] = (yi * zj) - (zi * yj)
self._sy[idx1:idx2, 2] = (zi * xj) - (xi * zj)
self._sz[idx1:idx2, 2] = (xi * yj) - (yi * xj)
if g3d_world.options.dim_mode is DIMMode.G2D_AXISYMM:
r = 0.25 * (y[self._kp[idx1:idx2, 4]] +
y[self._kp[idx1:idx2, 5]] +
y[self._kp[idx1:idx2, 6]] +
y[self._kp[idx1:idx2, 7]])
self._sx[idx1:idx2, 0] = r * self._sx[idx1:idx2, 0]
self._sy[idx1:idx2, 0] = r * self._sy[idx1:idx2, 0]
self._sz[idx1:idx2, 0] = r * self._sz[idx1:idx2, 0]
self._sx[idx1:idx2, 1] = r * self._sx[idx1:idx2, 1]
self._sy[idx1:idx2, 1] = r * self._sy[idx1:idx2, 1]
self._sz[idx1:idx2, 1] = r * self._sz[idx1:idx2, 1]
self._sx[idx1:idx2, 2] = r * self._sx[idx1:idx2, 2]
self._sy[idx1:idx2, 2] = r * self._sy[idx1:idx2, 2]
self._sz[idx1:idx2, 2] = r * self._sz[idx1:idx2, 2]
self._si[idx1:idx2, 0] = self._sx[idx1:idx2, 0]
self._si[idx1:idx2, 1] = self._sy[idx1:idx2, 0]
self._si[idx1:idx2, 2] = self._sz[idx1:idx2, 0]
self._voli[idx1:idx2] = (
1.0 / (self._si[idx1:idx2, 0] * xi + self._si[idx1:idx2, 1] * yi + self._si[idx1:idx2, 2] * zi)
)
[docs]
def update_symmetry_ghost_nodes(self, x: ndarray, y: ndarray, z: ndarray) -> None:
"""Update geometric representation of symmetry plane ghost nodes (mirror nodes in symmetry plane)
Parameters
----------
x: ndarray :
x-coordinate vector
y: ndarray :
y-coordinate vector
z: ndarray :
z-coordinate vector
"""
# update ghost node coordinates for symmetry faces
delta = np.zeros(3)
for i_face in range(int(self._size / 2), self._size):
for ip in range(4):
delta[0] = x[self._kp[i_face, ip]] - x[self._kp[i_face, ip + 4]]
delta[1] = y[self._kp[i_face, ip]] - y[self._kp[i_face, ip + 4]]
delta[2] = z[self._kp[i_face, ip]] - z[self._kp[i_face, ip + 4]]
dd = (delta[0] * self._s[i_face, 0] +
delta[1] * self._s[i_face, 1] +
delta[2] * self._s[i_face, 2]) / self._sl[i_face]
for i in range(3):
delta[i] -= 2. * dd * self._s[i_face, i] / self._sl[i_face]
x[self._kp[i_face, ip + 8]] = x[self._kp[i_face, ip + 4]] + delta[0]
y[self._kp[i_face, ip + 8]] = y[self._kp[i_face, ip + 4]] + delta[0]
z[self._kp[i_face, ip + 8]] = z[self._kp[i_face, ip + 4]] + delta[0]
[docs]
def update_wall_diff_metrics(self, x: ndarray, y: ndarray, z: ndarray) -> None:
"""Update wall face diffusive flux metrics
Parameters
----------
x: ndarray :
x-coordinate vector
y: ndarray :
y-coordinate vector
z: ndarray :
z-coordinate vector
"""
g3d_world = G3DWorld()
idx1 = int(self._size / 2)
idx2 = self._size
xi = .25 * (x[self._kp[idx1:idx2, 4]] +
x[self._kp[idx1:idx2, 5]] +
x[self._kp[idx1:idx2, 6]] +
x[self._kp[idx1:idx2, 7]] -
x[self._kp[idx1:idx2, 0]] -
x[self._kp[idx1:idx2, 1]] -
x[self._kp[idx1:idx2, 2]] -
x[self._kp[idx1:idx2, 3]])
yi = .25 * (y[self._kp[idx1:idx2, 4]] +
y[self._kp[idx1:idx2, 5]] +
y[self._kp[idx1:idx2, 6]] +
y[self._kp[idx1:idx2, 7]] -
y[self._kp[idx1:idx2, 0]] -
y[self._kp[idx1:idx2, 1]] -
y[self._kp[idx1:idx2, 2]] -
y[self._kp[idx1:idx2, 3]])
zi = .25 * (z[self._kp[idx1:idx2, 4]] +
z[self._kp[idx1:idx2, 5]] +
z[self._kp[idx1:idx2, 6]] +
z[self._kp[idx1:idx2, 7]] -
z[self._kp[idx1:idx2, 0]] -
z[self._kp[idx1:idx2, 1]] -
z[self._kp[idx1:idx2, 2]] -
z[self._kp[idx1:idx2, 3]])
xj = .5 * (x[self._kp[idx1:idx2, 5]] +
x[self._kp[idx1:idx2, 7]] -
x[self._kp[idx1:idx2, 4]] -
x[self._kp[idx1:idx2, 6]])
yj = .5 * (y[self._kp[idx1:idx2, 5]] +
y[self._kp[idx1:idx2, 7]] -
y[self._kp[idx1:idx2, 4]] -
y[self._kp[idx1:idx2, 6]])
zj = .5 * (z[self._kp[idx1:idx2, 5]] +
z[self._kp[idx1:idx2, 7]] -
z[self._kp[idx1:idx2, 4]] -
z[self._kp[idx1:idx2, 6]])
xk = .5 * (x[self._kp[idx1:idx2, 6]] +
x[self._kp[idx1:idx2, 7]] -
x[self._kp[idx1:idx2, 4]] -
x[self._kp[idx1:idx2, 5]])
yk = .5 * (y[self._kp[idx1:idx2, 6]] +
y[self._kp[idx1:idx2, 7]] -
y[self._kp[idx1:idx2, 4]] -
y[self._kp[idx1:idx2, 5]])
zk = .5 * (z[self._kp[idx1:idx2, 6]] +
z[self._kp[idx1:idx2, 7]] -
z[self._kp[idx1:idx2, 4]] -
z[self._kp[idx1:idx2, 5]])
self._sx[idx1:idx2, 0] = (yj * zk) - (zj * yk)
self._sy[idx1:idx2, 0] = (zj * xk) - (xj * zk)
self._sz[idx1:idx2, 0] = (xj * yk) - (yj * xk)
self._sx[idx1:idx2, 1] = (yk * zi) - (zk * yi)
self._sy[idx1:idx2, 1] = (zk * xi) - (xk * zi)
self._sz[idx1:idx2, 1] = (xk * yi) - (yk * xi)
self._sx[idx1:idx2, 2] = (yi * zj) - (zi * yj)
self._sy[idx1:idx2, 2] = (zi * xj) - (xi * zj)
self._sz[idx1:idx2, 2] = (xi * yj) - (yi * xj)
if g3d_world.options.dim_mode is DIMMode.G2D_AXISYMM:
r = 0.25 * (y[self._kp[idx1:idx2, 4]] +
y[self._kp[idx1:idx2, 5]] +
y[self._kp[idx1:idx2, 6]] +
y[self._kp[idx1:idx2, 7]])
self._sx[idx1:idx2, 0] = r * self._sx[idx1:idx2, 0]
self._sy[idx1:idx2, 0] = r * self._sy[idx1:idx2, 0]
self._sz[idx1:idx2, 0] = r * self._sz[idx1:idx2, 0]
self._sx[idx1:idx2, 1] = r * self._sx[idx1:idx2, 1]
self._sy[idx1:idx2, 1] = r * self._sy[idx1:idx2, 1]
self._sz[idx1:idx2, 1] = r * self._sz[idx1:idx2, 1]
self._sx[idx1:idx2, 2] = r * self._sx[idx1:idx2, 2]
self._sy[idx1:idx2, 2] = r * self._sy[idx1:idx2, 2]
self._sz[idx1:idx2, 2] = r * self._sz[idx1:idx2, 2]
self._si[idx1:idx2, 0] = self._sx[idx1:idx2, 0]
self._si[idx1:idx2, 1] = self._sy[idx1:idx2, 0]
self._si[idx1:idx2, 2] = self._sz[idx1:idx2, 0]
self._voli[idx1:idx2] = (
1.0 / (self._si[idx1:idx2, 0] * xi + self._si[idx1:idx2, 1] * yi + self._si[idx1:idx2, 2] * zi)
)
# calculate wall normal coordinate for first cell
self._y_norm = np.zeros(self._size)
xc = 0.125 * (x[self._kp[idx1:idx2, 0]] +
x[self._kp[idx1:idx2, 1]] +
x[self._kp[idx1:idx2, 2]] +
x[self._kp[idx1:idx2, 3]] +
x[self._kp[idx1:idx2, 4]] +
x[self._kp[idx1:idx2, 5]] +
x[self._kp[idx1:idx2, 6]] +
x[self._kp[idx1:idx2, 7]])
xc -= 0.25 * (x[self._kp[idx1:idx2, 4]] +
x[self._kp[idx1:idx2, 5]] +
x[self._kp[idx1:idx2, 6]] +
x[self._kp[idx1:idx2, 7]])
yc = 0.125 * (y[self._kp[idx1:idx2, 0]] +
y[self._kp[idx1:idx2, 1]] +
y[self._kp[idx1:idx2, 2]] +
y[self._kp[idx1:idx2, 3]] +
y[self._kp[idx1:idx2, 4]] +
y[self._kp[idx1:idx2, 5]] +
y[self._kp[idx1:idx2, 6]] +
y[self._kp[idx1:idx2, 7]])
yc -= 0.25 * (y[self._kp[idx1:idx2, 4]] +
y[self._kp[idx1:idx2, 5]] +
y[self._kp[idx1:idx2, 6]] +
y[self._kp[idx1:idx2, 7]])
zc = 0.125 * (z[self._kp[idx1:idx2, 0]] +
z[self._kp[idx1:idx2, 1]] +
z[self._kp[idx1:idx2, 2]] +
z[self._kp[idx1:idx2, 3]] +
z[self._kp[idx1:idx2, 4]] +
z[self._kp[idx1:idx2, 5]] +
z[self._kp[idx1:idx2, 6]] +
z[self._kp[idx1:idx2, 7]])
zc -= 0.25 * (z[self._kp[idx1:idx2, 4]] +
z[self._kp[idx1:idx2, 5]] +
z[self._kp[idx1:idx2, 6]] +
z[self._kp[idx1:idx2, 7]])
self._y_norm[idx1:idx2] = -(xc * self._s[idx1:idx2, 0] +
yc * self._s[idx1:idx2, 1] +
zc * self._s[idx1:idx2, 2]) / self._sl[idx1:idx2]
[docs]
def check_metrics(self, x: ndarray, y: ndarray, z: ndarray) -> None:
"""Check flux molecule metrics data
Parameters
----------
x: ndarray :
x-coordinate vector
y: ndarray :
y-coordinate vector
z: ndarray :
z-coordinate vector
"""
idx1 = 0
idx2 = self._size
x[self._kc[idx1:idx2, 1]] -= self._s[idx1:idx2, 0]
y[self._kc[idx1:idx2, 1]] -= self._s[idx1:idx2, 1]
z[self._kc[idx1:idx2, 1]] -= self._s[idx1:idx2, 2]
x[self._kc[idx1:idx2, 2]] += self._s[idx1:idx2, 0]
y[self._kc[idx1:idx2, 2]] += self._s[idx1:idx2, 1]
z[self._kc[idx1:idx2, 2]] += self._s[idx1:idx2, 2]
[docs]
def check_cell_metrics(self, ic: int, check_sum: ndarray):
"""Check cell metrics data
Parameters
----------
ic: int :
cell index
check_sum: ndarray :
accumulated check sum
"""
for i_face in range(self._size):
if self._kc[i_face, 1] == ic:
print(
' i_face %d: [%e,%e,%e]' % (i_face, -self._s[i_face, 0], -self._s[i_face, 1],
-self._s[i_face, 2]))
for i in range(3):
check_sum[i] -= self._s[i_face, i]
elif self._kc[i_face, 2] == ic:
print(' i_face %d: [%e,%e,%e]' % (i_face, self._s[i_face, 0], self._s[i_face, 1], self._s[i_face, 2]))
for i in range(3):
check_sum[i] += self._s[i_face, i]
[docs]
def print_data(self, f: TextIO = None) -> None:
"""Prints cell pointers, node pointers, and face metrics to file (or stdout)
Parameters
----------
f: TextIO :
ascii file handle (Default value = None)
"""
if f is not None:
for i in range(self._size):
f.write('face idx: %d\n' % i)
f.write('kc: %s\n' % str(self._kc[i, :]))
f.write('kp: %s\n' % str(self._kp[i, :]))
f.write('s: %s\n' % str(self._s[i, :]))
else:
for i in range(self._size):
print('face idx: %d' % i)
print(self._kc[i, :])
print(self._kp[i, :])
print(self._s[i, :])
[docs]
class FMPArray:
"""Definition of class FMPArray: flux molecule placeholder container"""
def __init__(self):
self.__size = 0
self.__FMPs = []
@property
def size(self) -> int:
"""Storage size
Returns
-------
int
size
"""
return self.__size
@property
def FMPs(self) -> list:
"""Flux molecule placeholder list
Returns
-------
list
list of allocated flux molecule placeholders
"""
return self.__FMPs
[docs]
def add_FMP(self, **kwargs: Any) -> None:
"""Adds flux molecule to container
Parameters
----------
**kwargs: Any :
keyword-argument pairs
will be forwarded to flux molecule placeholder (FMP) constructor
see :func:'set_from_key_value'
"""
fmp = FMP(**kwargs)
if len(fmp.tag) == 0:
if fmp.type != FMPTypes.UNDEFINED:
fmp.tag = fmp.type.name
else:
fmp.tag = 'FMP ' + str(self.__size)
self.__FMPs.append(fmp)
self.__size += 1
[docs]
def allocate_FMPs(self, N: int = 0, idx: int = None) -> None:
"""Allocates flux molecule placeholders in container - all flux molecules placeholders or one specific
Parameters
----------
N: int :
flux molecule placeholder array length (Default value = 0)
idx: int :
flux molecule placeholder index listed in this container (Default value = None)
"""
if idx is None:
for fmp in self.__FMPs:
fmp.allocate(size=N)
else:
self.__FMPs[idx].allocate(size=N)
[docs]
def deallocate_FMPs(self) -> None:
"""Deallocates listed flux molecule placeholders"""
for i in range(self.__size):
self.__FMPs[i] = FMP()
[docs]
def get_FMPs(self, idx: int = None) -> Union[list, FMP]:
"""
Parameters
----------
idx :
return:
idx: int :
(Default value = None)
Returns
-------
"""
if idx is None:
return self.__FMPs
else:
return self.__FMPs[idx]
[docs]
def set_FMP_tag(self, idx: int, tag: str) -> None:
"""
Parameters
----------
idx :
param tag:
idx: int :
tag: str :
Returns
-------
"""
self.__FMPs[idx].tag = tag
[docs]
def set_FMP_data(self, idx: int, face_idx: int, kp: int, kc: int, fctj: float, fctk: float) -> None:
"""
Parameters
----------
idx :
param face_idx:
kp :
param kc:
fctj :
param fctk:
idx: int :
face_idx: int :
kp: int :
kc: int :
fctj: float :
fctk: float :
Returns
-------
"""
self.__FMPs[idx].set_data(face_idx, kp, kc, fctj, fctk)
[docs]
def get_max_FMP_size(self) -> int:
""":return:"""
FMP_size = 0
for tmp in self.__FMPs:
FMP_size = max(FMP_size, tmp.size)
return FMP_size
[docs]
def update_FMP_metrics(self, x: ndarray, y: ndarray, z: ndarray) -> None:
"""
Parameters
----------
x :
param y:
z :
x: ndarray :
y: ndarray :
z: ndarray :
Returns
-------
"""
for tmp in self.__FMPs:
tmp.update_metrics(x, y, z)
[docs]
def update_FMP_diff_metrics(self, x: ndarray, y: ndarray, z: ndarray) -> None:
"""
Parameters
----------
x :
param y:
z :
x: ndarray :
y: ndarray :
z: ndarray :
Returns
-------
"""
for tmp in self.__FMPs:
tmp.update_diff_metrics(x, y, z)
[docs]
def check_FMP_metrics(self, x: ndarray, y: ndarray, z: ndarray, tag: str = 'ALL') -> None:
"""
Parameters
----------
x :
param y:
z :
param tag:
x: ndarray :
y: ndarray :
z: ndarray :
tag: str :
(Default value = 'ALL')
Returns
-------
"""
for tmp in self.__FMPs:
if tag == tmp.tag or tag == 'ALL':
tmp.check_metrics(x, y, z)
[docs]
def check_FMP_cell_metrics(self, ic: int, check_sum: Union[ndarray, list[float]]) -> None:
"""
Parameters
----------
ic :
param check_sum:
ic: int :
check_sum: Union[ndarray :
list[float]] :
Returns
-------
"""
for tmp in self.__FMPs:
print(' flux molecule tag: %s' % tmp.tag)
tmp.check_cell_metrics(ic, check_sum)
[docs]
def print_FMP_data(self, tag: str = 'ALL', f: TextIO = None) -> None:
"""
Parameters
----------
tag :
param f:
tag: str :
(Default value = 'ALL')
f: TextIO :
(Default value = None)
Returns
-------
"""
for tmp in self.__FMPs:
if tag == tmp.tag or tag == 'ALL':
tmp.print_data(f)