"""single-block cylinder mesh module"""
from typing import Any
from g3d.defs import G3DWorld
from g3d.defs import G3DDisplay
from g3d.mesh.modules import BlockModule
from g3d.defs import NodeDistribution
from g3d.defs import Direction
from g3d.defs import AngleType
from g3d.defs import INTFTypes
from g3d.defs import DIMMode
from g3d.defs import BlockFace
from g3d.defs import FaceOrientation
from g3d.mesh.geo import Coord
from g3d.mesh.geo import Edge
from g3d.mesh.geo import Block
[docs]
class SingleBlockCylinderModule(BlockModule):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self._cylinder_radius = 1.
self._o_grid_radius = 1.2
self._outer_box_size = 6.
self._n_cells_o_grid = 10
self._n_cells_external = 10
self._wall_cell_height = 0.0001
self._n_data_points = 36
self._o_grid_scale_factor = 0.
self._o_grid_shape_factor = 0.2
self._o_grid_stretch_rate = 4.0
self._cylinder_length = 1.
self._inner_wake_cell_size = 0.0001
self._outer_wake_cell_size = 0.001
self._n_cells_half_outlet = 30
self._n_cells_half_freestream = 15
self._n_cells_half_inlet = 10
self._do_not_smooth_o_grid = True
[docs]
def set_from_key_value(self, key: str, value: Any) -> bool:
if super().set_from_key_value(key, value):
return True
elif key == 'cylinder_radius':
self._cylinder_radius = value
return True
elif key == 'o_grid_radius':
self._o_grid_radius = value
return True
elif key == 'outer_box_size':
self._outer_box_size = value
return True
elif key == 'wall_cell_height':
self._wall_cell_height = value
return True
elif key == 'n_data_points':
self._n_data_points = value
return True
elif key == 'o_grid_scale_factor':
self._o_grid_scale_factor = value
return True
elif key == 'o_grid_shape_factor':
self._o_grid_shape_factor = value
return True
elif key == 'o_grid_stretch_rate':
self._o_grid_stretch_rate = value
return True
elif key == 'cylinder_length':
self._cylinder_length = value
return True
elif key == 'inner_wake_cell_size':
self._inner_wake_cell_size = value
return True
elif key == 'outer_wake_cell_size':
self._outer_wake_cell_size = value
return True
elif key == 'n_cells_half_outlet':
self._n_cells_half_outlet = value
return True
elif key == 'n_cells_half_freestream':
self._n_cells_half_freestream = value
return True
elif key == 'n_cells_half_inlet':
self._n_cells_half_inlet = value
return True
elif key == 'do_not_smooth_o_grid':
self._do_not_smooth_o_grid = value
return True
return False
@property
def cylinder_radius(self) -> float:
"""
:return:
"""
return self._cylinder_radius
@cylinder_radius.setter
def cylinder_radius(self, val: float) -> None:
self._cylinder_radius = val
@property
def o_grid_radius(self) -> float:
"""
:return:
"""
return self._o_grid_radius
@o_grid_radius.setter
def o_grid_radius(self, val: float) -> None:
self._o_grid_radius = val
@property
def outer_box_size(self) -> float:
"""
:return:
"""
return self._outer_box_size
@outer_box_size.setter
def outer_box_size(self, val: float) -> None:
self._outer_box_size = val
@property
def n_cells_o_grid(self) -> int:
"""
:return:
"""
return self._n_cells_o_grid
@n_cells_o_grid.setter
def n_cells_o_grid(self, val: int) -> None:
self._n_cells_o_grid = val
@property
def n_cells_external(self) -> int:
"""
:return:
"""
return self._n_cells_external
@n_cells_external.setter
def n_cells_external(self, val: int) -> None:
self._n_cells_external = val
@property
def wall_cell_height(self) -> float:
"""
:return:
"""
return self._wall_cell_height
@wall_cell_height.setter
def wall_cell_height(self, val: float) -> None:
self._wall_cell_height = val
@property
def n_data_points(self) -> int:
"""
:return:
"""
return self._n_data_points
@n_data_points.setter
def n_data_points(self, val: int) -> None:
self._n_data_points = val
@property
def o_grid_scale_factor(self) -> float:
"""
:return:
"""
return self._o_grid_scale_factor
@o_grid_scale_factor.setter
def o_grid_scale_factor(self, val: float) -> None:
self._o_grid_scale_factor = val
@property
def o_grid_shape_factor(self) -> float:
"""
:return:
"""
return self._o_grid_shape_factor
@o_grid_shape_factor.setter
def o_grid_shape_factor(self, val: float) -> None:
"""
:param val:
"""
self._o_grid_shape_factor = val
@property
def o_grid_stretch_rate(self) -> float:
"""
:return:
"""
return self._o_grid_stretch_rate
@o_grid_stretch_rate.setter
def o_grid_stretch_rate(self, val: float) -> None:
self._o_grid_stretch_rate = val
@property
def cylinder_length(self) -> float:
"""
:return:
"""
return self._cylinder_length
@cylinder_length.setter
def cylinder_length(self, val: float) -> None:
self._cylinder_length = val
@property
def inner_wake_cell_size(self) -> float:
"""
:return:
"""
return self._inner_wake_cell_size
@inner_wake_cell_size.setter
def inner_wake_cell_size(self, val: float) -> None:
self._inner_wake_cell_size = val
@property
def outer_wake_cell_size(self) -> float:
"""
:return:
"""
return self._outer_wake_cell_size
@outer_wake_cell_size.setter
def outer_wake_cell_size(self, val: float) -> None:
self._outer_wake_cell_size = val
@property
def n_cells_half_outlet(self) -> int:
"""
:return:
"""
return self._n_cells_half_outlet
@n_cells_half_outlet.setter
def n_cells_half_outlet(self, val: int) -> None:
self._n_cells_half_outlet = val
@property
def n_cells_half_freestream(self) -> int:
"""
:return:
"""
return self._n_cells_half_freestream
@n_cells_half_freestream.setter
def n_cells_half_freestream(self, val: int) -> None:
self._n_cells_half_freestream = val
@property
def n_cells_half_inlet(self) -> int:
"""
:return:
"""
return self._n_cells_half_inlet
@n_cells_half_inlet.setter
def n_cells_half_inlet(self, val: int) -> None:
self._n_cells_half_inlet = val
@property
def do_not_smooth_o_grid(self) -> bool:
"""
:return:
"""
return self._do_not_smooth_o_grid
@do_not_smooth_o_grid.setter
def do_not_smooth_o_grid(self, val: bool) -> None:
self._do_not_smooth_o_grid = val
def _generate_mesh(self) -> None:
R = self._cylinder_radius
H = self._outer_box_size
if self._o_grid_scale_factor == 0.:
self._o_grid_scale_factor = self._o_grid_radius / R
n0 = self._n_cells_o_grid + 1
n1 = self._n_cells_external + 1
# =====================================================================
# BLOCK NODE COUNTS
# =====================================================================
ni1 = (2 * self._n_cells_half_outlet +
4 * self._n_cells_half_freestream +
2 * self._n_cells_half_inlet + 1)
nj1 = n0 + n1 - 1
# =====================================================================
# Block 1: cylinder o-grid and external region
# =====================================================================
b1 = Block(ni1, nj1, self._nk3D)
self.add_Block(b1)
c11 = Coord(R, 0.0, 0.0, spacing=self._inner_wake_cell_size)
c12 = Coord(c11).scale(self._o_grid_scale_factor)
e11 = self.circular_edge(c11, ni1, direction=Direction.X_DIRECTION, N=self._n_data_points)
b1.add_Edge(e11, [1, 1, 1, 1, ni1])
e12 = Edge(e11)
e12.scale(self._o_grid_scale_factor)
b1.add_Edge(e12, [1, n0, 1, 1, ni1])
c11m = Coord(c11,
ialt=AngleType.IALT_1,
alpha=0.,
beta=0.,
shape_factor=self._o_grid_shape_factor,
spacing=self._wall_cell_height)
e13 = Edge(n0, c11m, c12,
distribute=NodeDistribution.CURVE_3,
stretch_rate=self._o_grid_stretch_rate)
b1.add_Edge(e13, [1, 1, 1, 3, n0])
e14 = Edge(e13)
b1.add_Edge(e14, [ni1, 1, 1, 3, n0])
# outer domain coordinates
c31 = Coord(H / 2., 0.0, 0.0)
c32 = Coord(H / 2., -H / 2., 0.0)
c33 = Coord(-H / 2., -H / 2., 0.0)
c34 = Coord(-H / 2., H / 2., 0.0)
c35 = Coord(H / 2., H / 2., 0.0)
c36 = Coord(c31)
# =====================================================================
# populate outer block edge (I-direction)
# =====================================================================
n_start = 1
n_edge = self._n_cells_half_outlet + 1
c31m = Coord(c31, spacing=self._outer_wake_cell_size)
e17 = Edge(n_edge, c31m, c32,
distribute=NodeDistribution.CURVE_5,
stretch_rate=2.)
b1.add_Edge(e17, [n_start, nj1, 1, 1, n_edge])
n_start += n_edge - 1
n_edge = 2 * self._n_cells_half_freestream + 1
e18 = Edge(n_edge, c32, c33,
distribute=NodeDistribution.CURVE_2,
stretch_rate=0.)
b1.add_Edge(e18, [n_start, nj1, 1, 1, n_edge])
n_start += n_edge - 1
n_edge = 2 * self._n_cells_half_inlet + 1
e19 = Edge(n_edge, c33, c34,
distribute=NodeDistribution.CURVE_2,
stretch_rate=0.)
b1.add_Edge(e19, [n_start, nj1, 1, 1, n_edge])
n_start += n_edge - 1
n_edge = 2 * self._n_cells_half_freestream + 1
e20 = Edge(n_edge, c34, c35,
distribute=NodeDistribution.CURVE_2,
stretch_rate=0.)
b1.add_Edge(e20, [n_start, nj1, 1, 1, n_edge])
n_start = ni1
n_edge = self._n_cells_half_outlet + 1
c36m = Coord(c36, spacing=self._outer_wake_cell_size)
e21 = Edge(n_edge, c36m, c35,
distribute=NodeDistribution.CURVE_5,
stretch_rate=2.)
b1.add_Edge(e21, [n_start, nj1, 1, 2, n_edge])
# =====================================================================
# block outer end edges (J-direction)
# =====================================================================
h1 = e13.h1
c12m = Coord(c12, spacing=h1)
e15 = Edge(n1, c12m, c31,
distribute=NodeDistribution.CURVE_5,
stretch_rate=2.)
b1.add_Edge(e15, [1, n0, 1, 3, n1])
e16 = Edge(e15)
b1.add_Edge(e16, [ni1, n0, 1, 3, n1])
# =====================================================================
# control edges
# =====================================================================
shape_factor = 0.5 * (H - self._o_grid_scale_factor * self._cylinder_radius)
# outer domain (270 degrees)
nic = self._n_cells_half_outlet + self._n_cells_half_freestream
c411 = Coord(e11.get_Coord(nic))
c412 = Coord(e12.get_Coord(nic), spacing=h1)
c413 = e18.get_Coord(self._n_cells_half_freestream)
alfa, beta = c411.get_angle(c412, ialt=AngleType.IALT_1, angle_dim=AngleType.DEGREES)
c412.set(ialt=AngleType.IALT_1,
alpha=alfa,
beta=beta,
shape_factor=shape_factor,
spacing=h1)
c413.set(ialt=AngleType.IALT_1,
alpha=270.,
beta=0.,
shape_factor=shape_factor)
e22 = Edge(n1, c412, c413,
distribute=NodeDistribution.CURVE_4,
stretch_rate=0.5)
b1.add_Edge(e22, [nic + 1, n0, 1, 3, n1])
# outer domain (180 degrees)
nic += self._n_cells_half_freestream + self._n_cells_half_inlet
c422 = Coord(e12.get_Coord(nic), spacing=h1)
c423 = e19.get_Coord(self._n_cells_half_inlet)
e23 = Edge(n1, c422, c423,
distribute=NodeDistribution.CURVE_5,
stretch_rate=2.)
b1.add_Edge(e23, [nic + 1, n0, 1, 3, n1])
# outer domain (90 degrees)
nic += self._n_cells_half_inlet + self._n_cells_half_freestream
c431 = Coord(e11.get_Coord(nic))
c432 = Coord(e12.get_Coord(nic), spacing=h1)
c433 = e20.get_Coord(self._n_cells_half_freestream)
alfa, beta = c431.get_angle(c432, ialt=AngleType.IALT_1, angle_dim=AngleType.DEGREES)
c432.set(ialt=AngleType.IALT_1,
alpha=alfa,
beta=beta,
shape_factor=shape_factor,
spacing=h1)
c433.set(ialt=AngleType.IALT_1,
alpha=90.,
beta=0.,
shape_factor=shape_factor)
e24 = Edge(n1, c432, c433,
distribute=NodeDistribution.CURVE_4,
stretch_rate=0.5)
b1.add_Edge(e24, [nic + 1, n0, 1, 3, n1])
# outer domain (315 degrees)
nic = self._n_cells_half_outlet
c441 = Coord(e11.get_Coord(nic))
c442 = Coord(e12.get_Coord(nic), spacing=h1)
c443 = Coord(e18.start)
alfa, beta = c441.get_angle(c442, ialt=AngleType.IALT_1, angle_dim=AngleType.DEGREES)
c442.set(ialt=AngleType.IALT_1,
alpha=alfa,
beta=beta,
shape_factor=shape_factor,
spacing=h1)
c443.set(ialt=AngleType.IALT_1,
alpha=315.,
beta=0.,
shape_factor=shape_factor)
e25 = Edge(n1, c442, c443,
distribute=NodeDistribution.CURVE_4,
stretch_rate=0.5)
b1.add_Edge(e25, [nic + 1, n0, 1, 3, n1])
# outer domain (225 degrees)
nic += 2 * self._n_cells_half_freestream
c451 = Coord(e11.get_Coord(nic))
c452 = Coord(e12.get_Coord(nic), spacing=h1)
c453 = Coord(e19.start)
alfa, beta = c451.get_angle(c452, ialt=AngleType.IALT_1, angle_dim=AngleType.DEGREES)
c452.set(ialt=AngleType.IALT_1,
alpha=alfa,
beta=beta,
shape_factor=shape_factor,
spacing=h1)
c453.set(ialt=AngleType.IALT_1,
alpha=225.,
beta=0.,
shape_factor=shape_factor)
e26 = Edge(n1, c452, c453,
distribute=NodeDistribution.CURVE_4,
stretch_rate=0.5)
b1.add_Edge(e26, [nic + 1, n0, 1, 3, n1])
# outer domain (135 degrees)
nic += 2 * self._n_cells_half_inlet
c461 = Coord(e11.get_Coord(nic))
c462 = Coord(e12.get_Coord(nic), spacing=h1)
c463 = Coord(e20.start)
alfa, beta = c461.get_angle(c462, ialt=AngleType.IALT_1, angle_dim=AngleType.DEGREES)
c462.set(ialt=AngleType.IALT_1,
alpha=alfa,
beta=beta,
shape_factor=shape_factor,
spacing=h1)
c463.set(ialt=AngleType.IALT_1,
alpha=135.,
beta=0.,
shape_factor=shape_factor)
e27 = Edge(n1, c462, c463,
distribute=NodeDistribution.CURVE_4,
stretch_rate=0.5)
b1.add_Edge(e27, [nic + 1, n0, 1, 3, n1])
# outer domain (45 degrees)
nic += 2 * self._n_cells_half_freestream
c471 = Coord(e11.get_Coord(nic))
c472 = Coord(e12.get_Coord(nic), spacing=h1)
c473 = Coord(e21.end)
alfa, beta = c471.get_angle(c472, ialt=AngleType.IALT_1, angle_dim=AngleType.DEGREES)
c472.set(ialt=AngleType.IALT_1,
alpha=alfa,
beta=beta,
shape_factor=shape_factor,
spacing=h1)
c473.set(ialt=AngleType.IALT_1,
alpha=45.,
beta=0.,
shape_factor=shape_factor)
e28 = Edge(n1, c472, c473,
distribute=NodeDistribution.CURVE_4,
stretch_rate=0.5)
b1.add_Edge(e28, [nic + 1, n0, 1, 3, n1])
# =====================================================================
# fill KLOW plane
# =====================================================================
# fill o-grid
b1.fill_Face([1, 1, 1, 1, 3, ni1, n0])
# outer domain - segment 1
ni_start = 1
ni_delta = self._n_cells_half_outlet + 1
b1.fill_Face([ni_start, n0, 1, 1, 3, ni_delta, n1])
# outer domain - segment 2
ni_start += ni_delta - 1
ni_delta = self._n_cells_half_freestream + 1
b1.fill_Face([ni_start, n0, 1, 1, 3, ni_delta, n1])
# outer domain - segment 3
ni_start += ni_delta - 1
ni_delta = self._n_cells_half_freestream + 1
b1.fill_Face([ni_start, n0, 1, 1, 3, ni_delta, n1])
# outer domain - segment 4
ni_start += ni_delta - 1
ni_delta = self._n_cells_half_inlet + 1
b1.fill_Face([ni_start, n0, 1, 1, 3, ni_delta, n1])
# outer domain - segment 5
ni_start += ni_delta - 1
ni_delta = self._n_cells_half_inlet + 1
b1.fill_Face([ni_start, n0, 1, 1, 3, ni_delta, n1])
# outer domain - segment 6
ni_start += ni_delta - 1
ni_delta = self._n_cells_half_freestream + 1
b1.fill_Face([ni_start, n0, 1, 1, 3, ni_delta, n1])
# outer domain - segment 7
ni_start += ni_delta - 1
ni_delta = self._n_cells_half_freestream + 1
b1.fill_Face([ni_start, n0, 1, 1, 3, ni_delta, n1])
# outer domain - segment 8
ni_start += ni_delta - 1
ni_delta = self._n_cells_half_outlet + 1
b1.fill_Face([ni_start, n0, 1, 1, 3, ni_delta, n1])
def _generate_mesh_post(self) -> int:
self._smooth()
self._extrude_mesh()
return super()._generate_mesh_post()
def _extrude_mesh(self) -> None:
g3d_disp = G3DDisplay()
# extrude mesh in K-direction
if not g3d_disp.silent:
g3d_disp.header('extruding 2D mesh plane in K-direction')
e_min = Coord(0., 0., 0.)
e_max = Coord(0., 0., self._cylinder_length)
e_ext = Edge(self._nk3D, e_min, e_max, distribute=NodeDistribution.CURVE_2, stretch_rate=0.)
for b in self._blocks:
b.extrude_Face(b.get_Face(BlockFace.KLOW, FaceOrientation.INWARD_FACING_NORMAL), e_ext)
def _smooth(self) -> None:
if self._smooth_faces:
g3d_disp = G3DDisplay()
if not g3d_disp.silent:
g3d_disp.header('smoothing mesh (surface smoother)')
b1 = self._blocks[0]
if self._do_not_smooth_o_grid:
im = 1
i0 = 1
j0 = self._n_cells_o_grid + 1
k0 = 1
idir = 1
jdir = 3
npi = b1.ni
npj = self._n_cells_external + 1
self.add_smooth_face([im, i0, j0, k0, idir, jdir, npi, npj])
self.add_smooth_face_glue([im, 1, j0, 1, 5, 3, 1, npj],
[im, b1.ni, j0, 1, 5, 3, 1, npj])
else:
self.add_smooth_face(b1.get_Face(BlockFace.KLOW))
faceA = b1.get_Face(BlockFace.ILOW, FaceOrientation.OUTWARD_FACING_NORMAL)
faceB = b1.get_Face(BlockFace.IHIGH, FaceOrientation.INWARD_FACING_NORMAL)
self.add_smooth_face_glue(faceA, faceB)
self.smooth(self._n_smooth)
def _add_boundaries(self) -> None:
g3d_world = G3DWorld()
b1 = self._blocks[0]
# block interfaces
faceA = b1.get_Face(BlockFace.ILOW, FaceOrientation.OUTWARD_FACING_NORMAL)
faceB = b1.get_Face(BlockFace.IHIGH, FaceOrientation.INWARD_FACING_NORMAL)
self.add_Intf(faceA, faceB, intf_type=INTFTypes.INTERFACES)
# block end faces (K-direction)
if g3d_world.options.dim_mode == DIMMode.G3D:
faceA = b1.get_Face(BlockFace.KLOW, FaceOrientation.OUTWARD_FACING_NORMAL)
faceA.delta.z = self._cylinder_length
faceB = b1.get_Face(BlockFace.KHIGH, FaceOrientation.INWARD_FACING_NORMAL)
self.add_Intf(faceA, faceB, intf_type=INTFTypes.TRANSPERINT)
# populate outer block edge
n_start = 1
n_edge = self._n_cells_half_outlet + 1
self.add_IO([1, n_start, b1.nj, 1, 1, 5, n_edge, self._nk3D], tag='outlet')
n_start += n_edge - 1
n_edge = 2 * self._n_cells_half_freestream + 1
self.add_IO([1, n_start, b1.nj, 1, 1, 5, n_edge, self._nk3D], tag='freestream')
n_start += n_edge - 1
n_edge = 2 * self._n_cells_half_inlet + 1
self.add_IO([1, n_start, b1.nj, 1, 1, 5, n_edge, self._nk3D], tag='inlet')
n_start += n_edge - 1
n_edge = 2 * self._n_cells_half_freestream + 1
self.add_IO([1, n_start, b1.nj, 1, 1, 5, n_edge, self._nk3D], tag='freestream')
n_start += n_edge - 1
n_edge = self._n_cells_half_outlet
self.add_IO([1, n_start, b1.nj, 1, 1, 5, n_edge, self._nk3D], tag='outlet')
# cylinder wall
self.add_BC(b1.get_Face(BlockFace.JLOW), tag='cylinder')