绕多个障碍物的流动¶
一个稳态纳维-斯托克斯算例,既展示了 TensorMesh 的有限元机制,也同样突出了它的网格生成能力。脚本 examples/fluid/flow_obstacles/flow_obstacles.py 求解 \(\mathrm{Re} = 150\) 下穿过一个 \(3 \times 1\) 通道的不可压缩流动,通道内含有六个大小与位置各异的圆形障碍物。网格通过 MeshGen 借助 CSG(构造实体几何)以编程方式生成:从一个矩形出发,再减去六个圆盘。
问题¶
其中通道 \((0, 3) \times (0, 1)\) 减去位于以下位置的六个圆盘
边界条件:
入口(\(x = 0\)):抛物型分布,\(u_x(y) = 4\,y\,(1 - y)\),
壁面(\(y = 0\)、\(y = 1\))与障碍物表面:无滑移,
出口(\(x = 3\)):\(p = 0\)。
在 \(\mathrm{Re} = 150\) 时流动是稳态的(无脱落),每个障碍物的尾迹与下一个相互作用,解中呈现出靠得很近的圆柱之间特征性的狭窄射流。
通过 CSG 生成网格¶
这个脚本最有意思的部分是网格生成代码块——它简短、自成体系,并展示了 MeshGen 所暴露的 add_… / remove_… 风格的 CSG:
from tensormesh import MeshGen
gen = MeshGen(chara_length=1.0/n_grid)
gen.add_rectangle(0, 0, 3.0, 1.0)
for ox, oy, orad in [
(0.5, 0.5, 0.10), (1.0, 0.3, 0.08), (1.0, 0.7, 0.08),
(1.5, 0.5, 0.12), (2.0, 0.4, 0.07), (2.0, 0.6, 0.07),
]:
gen.remove_circle(ox, oy, orad)
mesh = gen.gen().double()
在底层,MeshGen 将布尔运算与三角剖分交给 Gmsh 的 OpenCASCADE 后端处理,随后再按其内部单元排序转换回 Mesh。完整的 MeshGen API 参见 网格。
求解器¶
与 顶盖驱动方腔 完全相同——同样的自定义 NavierStokesAssembler、同样的 SUPG/PSPG 稳定化、同样的 Picard 线性化。真正的差别仅在于:
边界掩码更为丰富(入口、壁面、障碍物表面、出口),
入口速度非零(抛物型),因此
Condenser在构造时其dirichlet_value包含了给定的入口分布,出口没有速度边界条件;只有压力被钉定为零。
is_inlet = points[:, 0] < 1e-6
is_outlet = points[:, 0] > 3.0 - 1e-6
is_wall = (points[:, 1] < 1e-6) | (points[:, 1] > 1.0 - 1e-6)
# …assemble u_mask / u_val accordingly, then Picard-iterate as in cavity…
输出¶
flow_obstacles.png 是最终图像:速度大小与压力等值线叠加在障碍物轮廓之上。图中可做的合理性检查包括:
\(x \approx 1.0\) 处上排两个障碍物之间的高速射流,
位于 \((1.5, 0.5)\) 的最大障碍物后方的宽阔回流区,
沿通道近乎均匀的压降。
图 47 flow_obstacles.py 在 Re = 150 时的输出。左:速度大小——高速射流从障碍物对之间挤过,并在下游展宽为尾迹。右:压力——每个障碍物上游出现滞止区,尾迹中出现低压区,沿通道流向方向呈现近乎均匀的压降。¶
运行方式¶
cd examples/fluid/flow_obstacles
python flow_obstacles.py # writes flow_obstacles.png
在默认网格分辨率下,Picard 循环大约需 20 次迭代收敛。