Transfinite 算法是 Gmsh 结构化网格划分中常用的划分技术,为探究该算法实现过程,本次内容将围绕以下三个方面展开:
在使用 Gmsh 进行结构化网格划分时,通常有三种方法:内置算法(Mesh.Algorithm)、Transfinite、extrusion,本节只针对 Transfinite 进行介绍,对另外两种算法感兴趣的读者可学习 Gmsh 官方给出的经典案例。
本小节将结合具体案例来介绍如何在 Gmsh 中使用 Transfinite 技术对几何域进行结构化网格划分。
# 获取当前模型中的二维拓扑: [(2, 1)]
surfaces = gmsh.model.getEntities(2)
# 取第一个surface的编号(当前案例仅有一个surface)
surface_tag = surfaces[0][1]
# 获取[(2, surface_tag)]的边界曲线
boundary = gmsh.model.getBoundary([(2, surface_tag)], oriented=False)
# 获取边界曲线的编号
curve_tags = [tag for dim, tag in boundary if dim == 1]
# 为每个边界曲线布种子
gmsh.model.mesh.setTransfiniteCurve(curve_tags[0], N1)
gmsh.model.mesh.setTransfiniteCurve(curve_tags[1], N2)
gmsh.model.mesh.setTransfiniteCurve(curve_tags[2], N1)
gmsh.model.mesh.setTransfiniteCurve(curve_tags[3], N2)
# 对取用的surface使用transfinite算法生成内部点
gmsh.model.mesh.setTransfiniteSurface(surface_tag)
# 将生成的三角形单元合并为四边形单元
gmsh.model.mesh.setRecombine(2, surface_tag)
# 网格生成
gmsh.model.mesh.generate(2)
整个过程如上述代码所述,每行都有注释辅助理解,需要注意的细节有如下几点:
setTransfiniteCurve 在边上布种时,要注意对边的种子数要一致,不然会发出警告:Surface %d cannot be meshed using the transfinite algorithm, non-matching number of nodes on opposite sides,Gmsh 不再采用Transfinite,改采用更为通用的 Front-Delaunay 算法
gmsh.model.mesh.setTransfiniteCurve(tag, numNodes, meshType="Progression", coef=1.)
tag:curve tagnumNodes:curve 上的总节点数(包括两端点)meshType:节点分布形式,类似于 Abaqus 的 Bias 设置coef > 1:两端疏,中间密0 < coef < 1:两端密,中间疏coef > 1:尺寸变大,如:coef = 2,表示相邻边段按 2 倍递增0 < coef < 1:尺寸变小tag 取加负号"Progression":沿着 curve 方向上的尺寸变化Bump:OPFEM 设计
用户指定边进行布种时,ui界面可以显示 curve 的方向,引导用户为边布种
gmsh.model.mesh.setTransfiniteSurface(tag, arrangement="Left", cornerTags=[])
tag:surface tagarrangement:当 surface 未被 setRecombine 时三角形单元的排列方式,可选参数有: "Left", "Right", "AlternateLeft" and "AlternateRight",对于目前的结构化网格划分,可以不用考虑这个参数 | |
|---|---|
| |
cornerTags:明确指定(3个或4个)角点进行 Transfinite 插值参考官方 t6.py 教程:
gmsh.model.mesh.setTransfiniteSurface(
surface_tag,
cornerTags=[
point_tags["p1"],
point_tags["p2"],
point_tags["p3"],
point_tags["p4"],
],
)
| |
|---|
对于角点的作用,将会在下节的 Tranfinite 算法原理中详细介绍。
Transfinite 算法的核心就是 Coons Patch。所谓 Coons Patch,在计算图形学领域中,是一种由边界曲线构造内部曲面的插值方法。对于一个四边形参数区域,如果已知四条边界曲线,那么 Coons Patch 可以基于边界曲线和角点信息,通过双线性混合修正构造内部规则节点分布。
这里考虑一个四边形参数区域: ,设四个角点分别为:
四条边界曲线分别记为:
其中,按照上述方向,有:
内部点 可以先由两组边界曲线插值得到。第一组是左右边界 和 之间的线性插值:
它表示在给定 的情况下,从左边界 向右边界 插值。
第二组是下上边界 和 之间的线性插值:
它表示在给定 的情况下,从下边界 向上边界 插值。
如果只把这两部分相加,则有:
但是这样会产生一个问题:四个角点被重复计算了一次。因此还需要进行角点修正( corner-correction)。
角点修正项由四个角点 的双线性插值给出:
展开后得到:
因此,Coons Patch 的完整表达式为:
为什么需要 corner-correction?
例如在左下角:
左右边界插值项为:
上下边界插值项为:
如果没有角点修正,则:
这显然不正确。因此需要减去角点修正项。对于 ,角点修正项为 :
所以:
因此,corner-correction 的作用就是去掉四个角点被重复计算的部分,使得 Coons Patch 在边界和角点处都能严格满足原始边界条件。
角点修正项与四节点四边形单元 Q4 的双线性插值形式一致,这是为什么?
令: ,其中:
则有:
因此可以得到 Q 4 单元的四个形函数:
这说明 Coons Patch 中的 corner-correction 本质上就是由四个角点决定的双线性插值平面。
Coons Patch 的参数域是 ,映射到三维空间时 坐标是怎么处理的?
边界曲线 和角点 是三维几何对象,所以 Coons Patch 对它们进行线性组合后,得到的 自然也是三维点,包含 坐标。
Bicubic blending
虽然双线性 Coons 曲面片精确地吻合其四条边界曲线,但它在这些曲线处的切平面未必与待拼接曲面的切平面一致,从而导致拼接曲面沿这些曲线出现“褶皱”。为解决这一问题,可将线性插值替换为三次 Hermite 样条,并选择适当的权重以匹配角点处的偏导数,从而形成双三次混合的 Coons 曲面片。—维 基 百 科
参考 OCC 对曲面连续性的理解:
需要注意的是,Transfinite 插值中的参数域 只是用于描述节点在参数域中的相对位置,并不是最终的物理坐标。在有限元网格生成中,节点最终必须落在真实几何体的曲线或曲面上。因此,在 OPFEM 的实际应用中,应以几何模型为基础,通过几何边界曲线确定边界节点,再利用 Transfinite 插值计算几何表面上的内部节点,从而保证生成的网格能够准确贴合原始几何。
在解决这个问题时,会遇到三个坐标系:coons_patch 坐标系、几何表面的参数坐标系、整体坐标系,对于几何表面的参数坐标系,将会在以后的文章中进行介绍。计算流程:
在实际编程时,coons_patch 算法按照公式写就行,比较繁杂的就是准备好 s 和 c,在 Gmsh 中,给定一个四边形区域,程序内部会自动的挑好 s 和 c,在自编程实现的时候,需要理解 OCC 的拓扑结构,根据 Edge 来准备 s 和 c。
使用空间贝塞尔曲线构造四边形几何区域,拾取几何的拓扑边,将点内插到几何的参数域中,然后映射到整体坐标系下:
图中绿色曲面为原始的几何面,红色的点为自编程 coons_patch 算法计算得到的点,蓝色的点为 Gmsh 的 setTransfiniteSurface 计算得到的点,两者结果一致。
实际 Gmsh 的处理思路也是先将点插在曲面的参数域中,参见官方文档在 t6: Transfinite meshes, deleting entities 中的程序注释:
The ‘Transfinite Surface’ meshing constraint uses a transfinite interpolation algorithm in the parametric plane of the surface to connect the nodes on the boundary using a structured grid.
现在来测试强凹边界区域:
在 Gmsh 和自编程的 coons_patch 计算结果一致,且都会在强凹区域附近出现内部节点分布到几何区域外部的现象,说明该问题并不是程序实现错误,而是 Transfinite / Coons Patch 插值方法本身的局限性。
Transfinite Surface 的核心是通过四条边界曲线进行插值,其内部点由边界曲线的线性混合和角点修正共同决定,该公式本质上只是根据四条边界曲线构造一个参数映射,并没有额外判断插值得到的内部点是否仍然位于原始几何区域内部。对于凸四边形或形状较规则的四边形区域,这种边界插值通常能够得到合理的结构化网格;但对于强凹区域,边界之间的线性混合可能会跨过凹陷边界,从而使部分内部节点落到几何区域外部。
因此,强凹区域中出现节点外溢,说明该区域不适合直接作为一个单独的 Transfinite Surface 进行结构化划分。在实际应用中很多情况下,遇到的几何区域,都不是那么规则的,如果这时想用 Transfinite 进行结构化网格划分,就要对原始的几何域进行分块,这也是 OPFEM - Mesh 模块以后的发展点。
对分块感兴趣的,可以搜索相关论文,比如我推荐一篇:《Enhanced block-structured quadrilateral mesh generation: integrating cross-field and distance field for optimal domain decomposition》,以下的效果图均出自该篇文献:
| |
|---|
注:以上是木木对 Transfinite 结构化网格算法的一点粗浅理解。由于个人在数值计算和几何拓扑方面的积累尚浅,文中难免有疏漏或表述不当之处。特此抛砖引玉,诚邀各位同行批评指正,如有谬误,还望不吝赐教。