Structured Cylinder Meshes
dream.mesh.get_structured_cylinder_mesh builds a fully structured mesh in polar coordinates \((r, \varphi)\) around a cylinder. It accepts the same interface as get_rectangular_mesh: the caller supplies a radial array \(r\) and an angular array \(\varphi\) for each domain region. The angular direction is closed by default (close_angular=True), so \(\varphi\) should span exactly one full revolution \([0, 2\pi]\) with the last value equal to \(2\pi\) (which is
identified with \(\varphi = 0\)).
Boundaries at a constant radius are specified by passing the target radius as a scalar or single-element array together with the full angular range.
get_nodal_points can be used to cluster nodes near the inner or outer radius by choosing a non-uniform distribution.
[1]:
import numpy as np
from ngsolve.webgui import Draw
from dream.mesh import get_structured_cylinder_mesh, get_nodal_points
Uniform annular mesh
We generate a uniform annular mesh around a cylinder of radius \(r_i = 0.5\) out to an outer boundary at \(r_o = 5.0\). The angular direction uses 32 uniform sectors.
[2]:
ri = 0.5 # cylinder radius
ro = 5.0 # farfield radius
r = np.linspace(ri, ro, 21) # 20 uniform radial layers
phi = np.linspace(0, 2*np.pi, 33) # 32 uniform angular sectors
domains = [
("fluid", (r, phi)),
]
boundaries = [
("cylinder", (r[0], phi)), # inner circle
("farfield", (r[-1], phi)), # outer circle
]
mesh = get_structured_cylinder_mesh(domains, boundaries)
print("Materials: ", mesh.GetMaterials())
print("Boundaries:", mesh.GetBoundaries())
Draw(mesh)
Materials: ('fluid',)
Boundaries: ('cylinder', 'farfield')
[2]:
WebGLScene
Radially clustered mesh
For boundary-layer or near-field resolution near the cylinder surface, a non-uniform radial distribution is preferable. We use get_nodal_points with a 'tanh' distribution to cluster nodes near \(r = r_i\) while keeping a coarser grid towards the farfield.
[3]:
ri = 0.5
ro = 5.0
# tanh distribution in [0,1], mapped to [ri, ro]
r_norm = get_nodal_points(21, distribution='tanh', beta=2.5)
r = ri + (ro - ri) * r_norm
phi = np.linspace(0, 2*np.pi, 33)
domains = [
("fluid", (r, phi)),
]
boundaries = [
("cylinder", (r[0], phi)),
("farfield", (r[-1], phi)),
]
mesh = get_structured_cylinder_mesh(domains, boundaries)
print("Materials: ", mesh.GetMaterials())
print("Boundaries:", mesh.GetBoundaries())
Draw(mesh)
Materials: ('fluid',)
Boundaries: ('cylinder', 'farfield')
[3]:
WebGLScene
Two-domain mesh: fluid core and outer sponge annulus
A sponge layer is often placed in an outer annular region to damp outgoing waves. We create two concentric domains: a near-field fluid region with dense tanh clustering near the cylinder, and a coarser outer sponge annulus. The two domains share their common boundary at \(r = r_t\).
[4]:
ri = 0.5 # cylinder radius
rt = 4.0 # transition radius (fluid/sponge interface)
ro = 6.0 # outer sponge boundary
# Dense tanh-clustered radial nodes in the fluid region
r_norm = get_nodal_points(21, distribution='tanh', beta=2.5)
r_fluid = ri + (rt - ri) * r_norm
# Uniform radial nodes in the sponge region
r_sponge = np.linspace(rt, ro, 9)
phi = np.linspace(0, 2*np.pi, 33)
domains = [
("fluid", (r_fluid, phi)),
("sponge", (r_sponge, phi)),
]
boundaries = [
("cylinder", (r_fluid[0], phi)),
("farfield", (r_sponge[-1], phi)),
]
mesh = get_structured_cylinder_mesh(domains, boundaries)
print("Materials: ", mesh.GetMaterials())
print("Boundaries:", mesh.GetBoundaries())
Draw(mesh)
Materials: ('fluid', 'sponge')
Boundaries: ('cylinder', 'farfield')
[4]:
WebGLScene