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