Gmsh使用教程Ⅰ

发布于 2023-06-16  2520 次阅读


Please refresh the page if equations are not rendered correctly.
---------------------------------------------------------------

[TOC]

Gmsh 操作指南

1. Gmsh简介

Gmsh 是一个开源的 3D 有限元网格生成器,内置 CAD 引擎和后处理器。其设计目标是提供一种快速、轻便且用户友好的网格划分工具,具有参数输入和高级可视化功能。Gmsh 围绕几何、网格、求解器和后处理四个模块构建。对这些模块的任何输入的规范可以使用图形用户界面交互地完成,也可以使用 Gmsh 自己的脚本语言(.geo 文件)完成,或者使用 C++、C、Python 或 Julia 应用程序编程接口(API)。

2. Gmsh的获取与安装

2.1 Windows系统下Gmsh的安装

Windows系统下的Gmsh可以从Gmsh的官网直接下载,下载之后无需安装就可以直接打开使用,Gmsh官网还能直接下载源代码等相关文件.

Gmsh: a three-dimensional finite element mesh generator with built-in pre- and post-processing facilities

Gmsh帮助文档:Gmsh 4.11.1

2.2 Python 接口

Gmash的Python接口使用pip命令即可安装:

pip install--upgrade gmsh

安装成功后会有一个Gmsh.py文件,可以查询Gmsh中个函数的用法。

2.3. Gmsh构建几何

Gmsh 有两个几何内核用于构造几何,一个是内置的 built-in 几何内核,另一个是第三方的 OCC 内核,其中 build-in 内核仅支持自下而上构建几何体,即以 点-线-边-面 的顺序逐步构建几何;OCC 内核不但支持自下而上构建几何,同时还支持使用建模函数来构建几何体。

2.3.1. 基于Bulit-in内核创建几何

使用Gmsh的Python API,首先导入gmsh模块

import gmsh

若想使用gmsh,还需对其初始化,使用初始化命令

gmsh.initialize()

创建一个模型

gmsh.model.add('test1')

自下而上构建几何对象,首先需要构建点对象

gmsh.model.geo.addPoint(0, 0, 0, 0.1, 1)
gmsh.model.geo.addPoint(1, 0, 0, 0.1, 2)
gmsh.model.geo.addPoint(1, 1, 0, 0.1, 3)
gmsh.model.geo.addPoint(0, 1, 0, 0.1, 4)

其中前三个参数是点的坐标,gmsh 的几何都是在三维下创建的,若想建立二维的几何对象,只需要把所有点的 z 坐标设为 0 即可,第四个参数为该点处的参考网格尺寸值,第五个参数为该点的标号,标号从 1 开始。

由点创建线对象

gmsh.model.geo.addLine(1, 2, 1) 
gmsh.model.geo.addLine(3, 2, 2)
gmsh.model.geo.addLine(3, 4, 3)
gmsh.model.geo.addLine(4, 1, 4)

前两个参数是点的标号,即边的两个端点的标号,同时还给定了线的方向,即从第一个点指向第二个点;第三个参数为该边的标号。不同类型的对象的标号是不通用的,也就是说,虽然点已经有了标号 1 到 4,但边和点是不同类型的几何对象,因此还可以使用标号 1 到 4。

创建边对象与面对象

gmsh.model.geo.addCurveLoop([1, -2, 3, 4], 1) # 线环,边
gmsh.model.geo.addPlaneSurface([1], 1) #面

Line 对象只是线,若想生成面,则首先需要创建边对象,也称其为线环(CurveLoop),即将 Line 组成边界,其中第一个变量为一个列表,里面按顺序放置组成边界的线的标号,线之间需要首尾相连,由于 2 号边的方向是由 3 号点指向 2 号点,因此在 2 前面加一个负号,表示其相反的方向;第二个参数为边的编号。创建边界后,我们创建面对象,其中第一个参数是一个列表,里面放置组成面的边界的编号;第二个参数为面的编号。

我们将上面的设置同步到我们创建的模型,生成二维网格并将网格数据输出到 .msh 文件。

gmsh.model.geo.synchronize() # 同步到模型
gmsh.model.mesh.generate(2) # 生成网格
gmsh.write("t1.msh")

最后,在图形界面显示结果,并结束使用 gmsh。

gmsh.fltk.run() # 图形界面显示
gmsh.finalize() # 结束使用gmsh

完整代码如下

import gmsh
gmsh.initialize()
gmsh.model.add("test1")

lc = 1e-1# 网格尺寸

gmsh.model.geo.addPoint(0, 0, 0, lc, 1)
gmsh.model.geo.addPoint(1, 0, 0, lc, 2)
gmsh.model.geo.addPoint(1, 1, 0, lc, 3)
gmsh.model.geo.addPoint(0, 1, 0, lc, 4)

gmsh.model.geo.addLine(1, 2, 1) # 线
gmsh.model.geo.addLine(2, 3, 2)
gmsh.model.geo.addLine(3, 4, 3)
gmsh.model.geo.addLine(4, 1, 4)

gmsh.model.geo.addCurveLoop([1, 2, 3, 4], 1)
gmsh.model.geo.addPlaneSurface([1], 1)

gmsh.model.geo.synchronize()
gmsh.model.mesh.generate(2)

gmsh.write("test1.msh")

gmsh.fltk.run()
gmsh.finalize()

生成内部有洞的区域,相关代码:

import gmsh

gmsh.initialize()
gmsh.model.add("t2")

lc = 0.05
# 构建几何
gmsh.model.geo.addPoint(0, 0, 0, lc, 1)
gmsh.model.geo.addPoint(1, 0, 0, lc, 2)
gmsh.model.geo.addPoint(1, 1, 0, lc, 3)
gmsh.model.geo.addPoint(0, 1, 0, lc, 4)

gmsh.model.geo.addLine(1, 2, 1)
gmsh.model.geo.addLine(3, 2, 2)
gmsh.model.geo.addLine(3, 4, 3)
gmsh.model.geo.addLine(4, 1, 4)

gmsh.model.geo.addCurveLoop([4, 1, -2, 3], 1)

gmsh.model.geo.addPoint(0.5,0.5,0,lc,5)
gmsh.model.geo.addPoint(0.3,0.5,0,lc,6)
gmsh.model.geo.addPoint(0.7,0.5,0,lc,7)

gmsh.model.geo.addCircleArc(6,5,7,tag=5) # 生成圆弧
gmsh.model.geo.addCircleArc(7,5,6,tag=6)# 该函数只能生成弧度小于等于180度的圆弧

gmsh.model.geo.addCurveLoop([5,6],2)

gmsh.model.geo.addPlaneSurface([1,2], 1)
#gmsh.model.geo.addPlaneSurface([2],2)

gmsh.model.geo.synchronize()

gmsh.model.mesh.generate(2)   #2 代表生成二维网格

gmsh.fltk.run()
gmsh.finalize()

上面的代码中,使用了 addCircleArc 函数,该函数用来生成圆弧线,第一个和第三个参数是圆弧两端点的标号,第二个参数是圆弧的圆心标号,最后一个参数是圆弧的标号,由于圆弧也属于线类型,故其和 Line 类型共用标号。由于该函数表达圆弧的弧度范围为\left[0,\pi]\right.,因此我们调用该函数两次才能拼接成一个圆。

在构建面对象时,所用的边列表为[1,2],边 1 为外边界,边 2 则为内部的洞边界,Gmsh 默认列表的第一个边标号为外边界,之后的边都为内部的洞边界。如果我们想生成界面网格,只需把洞也构建成为一个面对象,即去掉 gmsh.model.geo.addPlaneSurface([2],2) 的注释即可(相当于创建两个surface),效果如下:

2.3.2. 基于OCC内核创建几何

除了使用 built-in 内核来构建几何,我们还可以使用 OCC 内核来构建几何,OCC 也支持自下而上构建几何,在上面的代码中,把 gmsh.model.geo 改为 gmsh.model.occ 即可。除此以外,OCC 还支持使用函数来构建几何,以生成正方形对象 \left[0,1]^2\right.为例,代码如下:

import gmsh

gmsh.initialize()
gmsh.model.add("t3")

gmsh.model.occ.addRectangle(0,0,0,1,1)
gmsh.model.occ.synchronize()

gmsh.model.mesh.setSize(gmsh.model.getEntities(0),0.05)
gmsh.model.mesh.generate(2)

gmsh.fltk.run()
gmsh.finalize()

在上面的代码中,使用函数 addRectangle 可以构建矩形对象,前三个参数是矩形左下角点的坐标,第四个,第五个参数分别是矩形的长和高。

由于不是自下而上构建几何,不能逐点去设置网格的尺寸值,因此使用 gmsh.model.getEntities 来获得所有点对象。若不输入任何参数,则该函数表示获得所有实体,若输入 0,则获取所有点对象,输入大于 0 的整数,表示获取所有该维度下的对象。之后,使用函数 gmsh.model.occ.setSize 来对所有点对象赋予网格尺寸值。

gmsh 提供了许多函数来构建几何对象,除了 addRectangle,还有构造圆形的 addDisk,构造球的 addSphere,构造立方体的 addBox 等等。

还可以利用布尔运算,同时使用这些基本的构造几何函数来构建更为复杂的几何模型,首先构造两个矩形,与一个椭圆

gmsh.initialize()
gmsh.model.add("t4")

gmsh.model.occ.addRectangle(-1,-1,0,2,2,1)
gmsh.model.occ.addRectangle(0, -1,0,1,1,2)
gmsh.model.occ.addDisk(0.5,0.5,0,0.3,0.2,3)

其中 addDisk 函数可以用来构造一个圆或者椭圆,前三个参数为圆心的坐标,后两个参数分别为 x 方向的半径和 y 方向的半径。我们想构造一个有椭圆洞的L形区域,因此我们使用布尔差运算。

gmsh.model.occ.cut([(2,1)],[(2,2),(2,3)],4)

cut 函数的作用是计算几何体之间的差,并构建出新的几何体。第一个参数为布尔差的被减项,第二个参数为布尔差的减项,均为列表形式,列表中的每一个元素表示一个几何体对象,在 Python 中,gmsh 的几何对象使用元组表示,元组的第一个元素为几何对象的维数,第二个元素为几何对象的标号,因此 (2,1) 就表示标号为 1 的面;第三项为新生成几何对象的标号。上面函数的作用即为面 1 减去面 2 与面 3 所在的区域。默认情况下,使用 cut 函数后,使用的对象会被删除,即面 1,面 2,面 3 都会被删除,只保留面 4,如果想保留,则可以设置第五个与第六个参数为 False

  在区域内构造一个圆形的界面,因此使用 fragment 函数

gmsh.model.occ.addDisk(-0.5,-0.5,0,0.2,0.2,5)
gmsh.model.occ.fragment([(2,4)],[(2,5)])
gmsh.model.occ.synchronize()

类似于 cut 函数,第一、二个参数为包含几何对象的列表,fragment 函数的作用为将输入的几何对象进行组合,下面的结果中可以看到,圆形区域界面嵌入了L形区域中。

 设置网格尺寸

gmsh.model.mesh.setSize(gmsh.model.getEntities(0), 0.05)

ov = gmsh.model.getEntitiesInBoundingBox(-0.1,-0.1,-0.1, 0.1,0.1,0.1, 0)
gmsh.model.mesh.setSize(ov, 0.01)

其中 gmsh.model.getEntitiesInBoundingBox 函数会以列表形式返回在给定 Box 内的几何对象的标号,前三个参数为 Box 左下角点的坐标,后三个参数为 Box 右上角点的坐标,最后一个参数为几何对象的维数,0 则返回在 Box 内所有点的标号。

完整代码如下:

import gmsh

gmsh.initialize()
gmsh.model.add("t4")

gmsh.model.occ.addRectangle(-1,-1,0,2,2,1)
gmsh.model.occ.addRectangle(0, -1,0,1,1,2)
gmsh.model.occ.addDisk(0.5,0.5,0,0.3,0.2,3)

gmsh.model.occ.cut([(2,1)],[(2,2),(2,3)],4)

gmsh.model.occ.addDisk(-0.5,-0.5,0,0.2,0.2,5)
gmsh.model.occ.fragment([(2,4)],[(2,5)])

gmsh.model.occ.synchronize()

gmsh.model.mesh.setSize(gmsh.model.getEntities(0), 0.05)

ov = gmsh.model.getEntitiesInBoundingBox(-0.1,-0.1,-0.1, 0.1,0.1,0.1, 0)
gmsh.model.mesh.setSize(ov, 0.01)

gmsh.model.mesh.generate(2)

gmsh.fltk.run()
gmsh.finalize()

结果如下

构造更复杂的几何

Gmsh 还支持构建贝塞尔曲线、样条曲线以及B-样条曲线以及曲面,同时,Gmsh 还支持拉伸、旋转等操作,使用这些功能我们就可以构造更加复杂的几何。

import gmsh
import numpy as np
from numpy import pi
def f(x):
    return x**2
x = np.linspace(-1, 1, 20)
y = f(x)

gmsh.initialize()
gmsh.model.add('test_5')
for i in range(len(x)):
    gmsh.model.geo.add_point(x[i], y[i], 0, tag=i+1)
gmsh.model.geo.add_spline(range(1, len(x)+1),1)
gmsh.model.geo.twist([(1, 1)], 0, 1, 0, 0, 0, 1, 0, 0, 1, pi/6)
gmsh.model.geo.synchronize()
gmsh.model.mesh.set_size(gmsh.model.getEntities(0),0.05)
gmsh.model.mesh.generate(2)
gmsh.fltk.run()
gmsh.finalize()

上述代码中,构造了一条抛物线并将其沿 (0,0,1) 方向进行拉伸旋转,结果如下

构造抛物线时,利用函数 addSpline,使用样条曲线来拟合抛物线,第一个参数是一个列表或数组,里面按顺序存放样条曲线拟合点的标号,第二个参数是线的标号。Gmsh 还提供了 addBSpline,addBezier 等函数,可以构造B-样条曲线、贝塞尔曲线等。

进行拉伸旋转时,使用了 twist 函数,该函数可以将几何对象进行拉伸旋转,第一个参数是要操作的对象,第二到四个参数是旋转轴通过一点的坐标,第五到七个参数是旋转轴的方向,第八到十个参数是拉伸的方向,最后一个参数是旋转的角度。Gmsh 还提供了平移、旋转、拉伸等多个函数用于操作几何对象,合理使用这些函数,可以构建复杂的几何对象。

2.4. 网格生成与用户界面操作

2.4.1. 3D模型网格生成

在Gmsh中,当几何模型构造完成后,gmsh.model.mesh.generate()来生成网格

import gmsh

gmsh.initialize()
gmsh.model.add("t1")
gmsh.model.occ.addBox(1,1,1,1,1,1)
gmsh.model.occ.synchronize()

gmsh.model.mesh.setSize(gmsh.model.getEntities(0), 0.05)
gmsh.option.setNumber("Mesh.Algorithm3D",1)
gmsh.model.mesh.generate(3)

gmsh.fltk.run()
gmsh.finalize()

若要生成二维三角形网格,则 generate() 函数中输入参数 2,若要生成三维四面体网格,则输入参数 3。同时,还可以设置网格生成所使用的算法,如上的 gmsh.option.setNumber("Mesh.Algorithm3D",1) 就设置生成四面体网格的算法为 Delaunay 算法,若生成三角形网格,则字符串参数为 Mesh.Algorithm,不同的数字表示不同的网格生成算法,在 Gmsh 的说明文档里有相应说明。

对于 Gmsh 的用户操作界面,可以拖动鼠标左键来对旋转模型,滑动滚轮放大缩小模型,拖动右键来平动界面。Gmsh 左侧选项的功能全部都可以编写代码来实现,因此很少会用到。我个人在用户操作界面中,最常使用的功能是 Tools 中的 Visibility,在 List 中,可以查看到所有几何实体,并且可以将几何实体单独表示,对于复杂的几何模型,能够查看局部网格的状态。

2.4.2. 超限网格与四边形网格生成

超限网格是利用超限插值得到的网格,在 Gmsh 中,只需给定四条边界上的节点与四个顶点,即可生成超限网格。

import gmsh
gmsh.initialize()
gmsh.model.add('test')
lc = 0.1
# 添加点
gmsh.model.geo.add_point(0, 0, 0, lc, 1)
gmsh.model.geo.add_point(2, 0, 0, lc, 2)
gmsh.model.geo.add_point(2, 1, 0, lc, 3)
gmsh.model.geo.add_point(1.2, 1.3, 0, lc, 4)
gmsh.model.geo.add_point(0.7, 1.3, 0, lc, 5)
gmsh.model.geo.add_point(0, 1, 0, lc, 6)
# 添加线
gmsh.model.geo.add_line(1, 2, 1)
gmsh.model.geo.add_line(2, 3, 2)
gmsh.model.geo.add_line(3, 4, 3)
gmsh.model.geo.add_line(4, 5, 4)
gmsh.model.geo.add_line(5, 6, 5)
gmsh.model.geo.add_line(6, 1, 6)
# 添加线环
gmsh.model.geo.add_curve_loop([1, 2, 3, 4, 5, 6], 1)
# 添加面
gmsh.model.geo.addPlaneSurface([1], 1)

# 在每条边上均匀插点
gmsh.model.geo.mesh.set_transfinite_curve(1, 20)
gmsh.model.geo.mesh.set_transfinite_curve(3, 6)
gmsh.model.geo.mesh.set_transfinite_curve(4, 6)
gmsh.model.geo.mesh.set_transfinite_curve(5, 10)
#  在下面两条边上等比插点
gmsh.model.geo.mesh.set_transfinite_curve(2, 30, 'progression', 1.1)
gmsh.model.geo.mesh.set_transfinite_curve(6, 30, 'Progression', -1.1)

# 超限插值
gmsh.model.geo.mesh.set_transfinite_surface(1, 'Left', [1, 2, 3, 6])
gmsh.model.geo.mesh.setRecombine(2, 1)     # 指定维数为2,标号1指定surface1
gmsh.model.geo.synchronize()  # 同步
gmsh.model.mesh.generate(2)   # 生成网格

gmsh.fltk.run()
gmsh.finalize()

上述代码中,首先定义区域,并使用 setTransfiniteCurve 函数在每条边上进行均匀插点,如果加入 Progression 参数与相应的值,则会按照等比数列进行插点,即新插入的点到上一个点的距离是上两个的点的给定值倍。之后,调用 setTransfiniteSurface 生成网格,由于超限插值是在曲面四边形上进行插值,因此需要给定四个顶点;指定维数 2 和标号 1,使用 setRecombine 函数还可以将面 1 上的三角形网格合并成为四边形网格。

利用超限插值,可以使用 Gmsh 生成结构网格

import gmsh

gmsh.initialize()

gmsh.model.add("test")

gmsh.model.geo.addPoint(0,0,0,tag=1)
gmsh.model.geo.addPoint(1,0,0,tag=2)
gmsh.model.geo.addPoint(1,1,0,tag=3)
gmsh.model.geo.addPoint(0,1,0,tag=4)

gmsh.model.geo.addLine(1,2,1)
gmsh.model.geo.addLine(2,3,2)
gmsh.model.geo.addLine(3,4,3)
gmsh.model.geo.addLine(4,1,4)

gmsh.model.geo.addCurveLoop([1,2,3,4],1)
gmsh.model.geo.addPlaneSurface([1],1)
for i in range(1,5):
    gmsh.model.geo.mesh.setTransfiniteCurve(i,10)
gmsh.model.geo.mesh.setTransfiniteSurface(1,"Right")   # 表示三角形的排序方式

gmsh.model.geo.synchronize()

gmsh.model.mesh.generate(2)

gmsh.fltk.run()
gmsh.finalize()

结果如下:

2.4.3. 网格尺寸场

除了在每点处设置网格尺寸,Gmsh 还提供了使用 Field 设置网格尺寸的方法,通过定义尺寸场类型和对应的尺寸场参数,可以生成不同尺寸分布的网格

import gmsh
gmsh.initialize()
gmsh.model.add('test')
lc=0.15
gmsh.model.occ.addRectangle(0, 0, 0, 1, 1, 1)
gmsh.model.occ.synchronize()


gmsh.model.mesh.field.add('Box', 1)    # 定义Box尺寸场,标号为1
# 设定参数
gmsh.model.mesh.field.setNumber(1, 'VIn', lc/15)
gmsh.model.mesh.field.setNumber(1, 'VOut', lc)
gmsh.model.mesh.field.setNumber(1, 'XMin', 0.4)
gmsh.model.mesh.field.setNumber(1, 'YMin', 0.4)
gmsh.model.mesh.field.setNumber(1, 'XMax', 0.6)
gmsh.model.mesh.field.setNumber(1, 'YMax', 0.6)
gmsh.model.mesh.field.setNumber(1, 'Thickness', 0.3)

gmsh.model.mesh.field.set_as_background_mesh(1)

gmsh.model.mesh.generate(2)
gmsh.fltk.run()
gmsh.finalize()


上述代码中,我们使用了 Box 尺寸场(不同的几何形状对应的几何参数不同),该尺寸场可以通过 XMin,YMin,XMax,YMax 定义一个矩形区域(三维还可给定ZMin,ZMax 定义立方体),给定区域内外的过渡层厚度 Thickness,在区域内外设定不同的网格尺寸 VIn,VOut,效果则如上图所示。

  不同的 Field 有着不同的功能,有些 Field 还需要结合进行使用,例如 DistanceThreshold

gmsh.model.mesh.field.add('Distance', 2)   # 定义Distance尺寸场标号为2
gmsh.model.mesh.field.setNumbers(2, 'PointsList', [1])   # 1号结点
gmsh.model.mesh.field.setNumbers(2, 'CurvesList', [2])   # 2号线
gmsh.model.mesh.field.setNumber(2, 'Sampling', 100)    # 设定用来离散线或者面的点的个数
gmsh.model.mesh.field.add('Threshold', 3)
gmsh.model.mesh.field.setNumber(3, "InField", 2)
# 如果指定对象的距离小于等于0.15,设定网格尺寸为lc/30;大于等于0.5设定尺寸为lc;在其中使用插值法网格尺寸从lc/30-lc过度
gmsh.model.mesh.field.setNumber(3, "SizeMin", lc / 30)
gmsh.model.mesh.field.setNumber(3, "SizeMax", lc)
gmsh.model.mesh.field.setNumber(3, "DistMin", 0.15)
gmsh.model.mesh.field.setNumber(3, "DistMax", 0.5)

gmsh.model.mesh.field.set_as_background_mesh(3)

Distance 尺寸场并不提供网格尺寸,它只计算区域内其他点到传入其中的点 、边、面的距离,而 Threshold 尺寸场可以通过 InField 参数传入 Distance 的数据,根据到给定点、边、面 的距离设置相应的网格尺寸,结果如下所示。

Gmsh 还提供了 MathEval 尺寸场,可以直接通过输入数学函数作为尺寸场生成网格

gmsh.model.mesh.field.add("MathEval",4)
gmsh.model.mesh.field.setString(4, "F","Cos(4*3.14*x) * Sin(4*3.14*y) / 10 + 0.101")

gmsh.model.mesh.field.setAsBackgroundMesh(4)

结果如下

若定义了多种尺寸场,可以使用 Min 尺寸场将所有尺寸场整合到一起

gmsh.model.mesh.field.add("Min",5)
gmsh.model.mesh.field.setNumbers(5,"FieldsList",[1,3,4])

gmsh.model.mesh.field.setAsBackgroundMesh(5)

Min 尺寸场可将其他尺寸场作为输入,取所有尺寸场的网格尺寸最小值,如下图所示。

Gmsh 总共提供了29种不同的网格尺寸场,能满足大多数网格生成的要求。

Everything not saved will be lost.
最后更新于 2023-09-07