开始只是想学SOFA, 谁知道这个坑深似海,还要先学GMSH。。。。。
一步步来吧,可恶啊。
GMSH的安装
安装没啥难度,按照官网的提示走
这里,更建议直接使用python的pip进行安装(因为直接下载源文件可能需要自己再配置些东西。。。):
pip install --upgrade gmsh
需要注意的是,这样操作的话软件包是被安装到当前使用的Python的路径下了,
如果使用了conda的话,可以在Python安装目录下的Lib\site-packages\找到gmsh-4.11.1.dist-info,如果在pycharm里import时报错,可以将这个site-packages添加到内容根试试。(一般不会遇到)
可以在Python安装目录下的share\doc\gmsh文件夹里找到教程和示例的源代码。
如果是使用pip安装的话,可以使用以下命令打开:
gmsh
(使用了conda的话要注意,启动软件时要保证环境是安装gmsh时的那个环境,因为这个东西是安装到当时的环境里的,不是直接安装到系统)
启动之后会显示这样的界面:
基本介绍(太长可不看部分)
Gmsh接口的两个默认内核是内置内核和OpenCASCADE内核。
在.geo脚本中选择CAD内核是使用SetFactory命令完成的。
在写 .geo脚本时,标签的数字是不能重复使用的。另外Gmsh保留零或负标签供内部使用。Gmsh教程从t1开始,是学习如何使用几何模块的最佳场所:它包含基于内置和OpenCASCADE内核的复杂度增加的示例。
几何模块 Geometry
模型实体可以在几何模块Geometry中以各种方式进行操作和转换,但操作始终直接在其各自的CAD内核中执行。
同样,可以通过每个CAD内核自己的导入机制在几何模块中导入模型。例如,默认情况下,Gmsh通过OpenCASCADE导入STEP和IGES文件,这将导致创建具有内部OpenCASCADE表示的模型实体.
除了CAD类型的几何实体(其几何结构由CAD内核提供)之外,Gmsh还支持由网格定义的离散模型实体(例如STL)。Gmsh不会对这些离散实体执行几何运算,但可以通过所谓的“重新参数化”程序1为它们配备几何图形。然后将参数化用于网格,其方式与CAD实体完全相同。示例参见t13
网格模块 Mesh
2D非结构化算法生成三角形和/或四边形(当使用重组命令或选项时)。三维非结构化算法生成四面体或四面体和金字塔(当边界网格包含四边形时)。
默认情况下,2D结构化算法(超限和拉伸)生成三角形,但可以通过使用复合命令或选项获得四边形。3D结构化算法生成四面体、六面体、棱柱和金字塔,这取决于它们所基于的曲面网格的类型。
教程 的1.2.1~1.2.3部分介绍了•选择正确的非结构化算法•指定网格元素大小•基本实体与物理组,如果有需要可详细查看。
求解器模块 Solver
Gmsh实现了ONELAB服务器,用于与外部解算器或其他代码(称为“客户端”)交换数据。ONELAB接口允许调用这些客户端,并让它们共享参数和建模信息。
后处理模块 Post-processing
感觉挺厉害的,主要是后处理时的视图及视图效果和功能。锦上添花。
Gmsh优势
- 使用内置脚本语言快速描述简单和/或“重复”的几何图形;
- 参数化几何图形;
- 以标准交换格式从其他CAD软件导入几何图形;
- 生成非结构化1D、2D和3D简单有限元网格,并对单元大小进行精细控制;
- 。。。。
Gmsh 劣势
- Gmsh生成的所有网格在有限元网格的意义上都是一致的
- Gmsh的图形用户界面只展示了有限数量的可用功能
实例
本部分为教程文档里的第二章,这部分只有代码,没有代码的讲解。代码太长就不粘贴过来了。
实例有:
t1 | 几何基础、基本实体、物理组 | t15 | 嵌入点、线和表面 |
t2 | 变换、拉伸几何体、体积 | t16 | 构造实体几何,OpenCASCADE几何内核 |
t3 | 拉伸网格、ONELAB | t17 | 各向异性背景网格 |
t4 | 内置函数、曲面中的孔、注释、实体颜色 | t18 | 周期网格 |
t5 | 网格大小、宏、循环、体积中的孔 | t19 | 穿透、圆角、管道、曲率网格尺寸 |
t6 | 超限网格、删除实体 | t20 | STEP导入和操作、几何分区 |
t7 | 背景网格 | t21 | 网格分区 |
t8 | 后处理,图像导出和动画 | x1 | 几何和网格数据 |
t9 | 插件 | x2 | 网格导入、离散实体、混合模型、,地形网格化 |
t10 | 网格大小字段 | x3 | 后处理数据导入:基于列表 |
t11 | 非结构化四边形网格 | x4 | 后处理信息导入:基于模型 |
t12 | 与化合物的交叉面片网格 | x5 | 附加几何数据:参数化、法线、曲率 |
t13 | 在没有基础CAD模型的情况下修复STL文件 | x6 | 附加网格数据:积分点、雅可比函数和基函数 |
t14 | 同调和上同调计算 | x7 | 附加网格数据:内部边和面 |
可根据需要去找对应的示例, 不必全看。
教程正文
对应官方教程第三章
启动
gmsh
添加几何实体
在 geometry -> elementary entities -> add 里可以添加几何实体
这里添加矩形rectangle:
可以用鼠标拖动,按e确定,或者在弹出来的弹窗里填写数值,
这个矩形添加后,可以到左边结构树里找到geometry ->Edit Script, 查看上面的添加矩形操作后的 .geo文件:
如果要编辑这个 .geo文件,则编辑且保存后,应该在软件里进行更新: geometry ->Reload Script
在使用Gmsh这个软件时,比较常见的方式就是图形界面和 .geo脚本文件混合使用,共同编辑。
画网格
在软件左边 Mesh里选择需要的网格维度,这里选择2D:
此时在软件中点击 File ->save mesh, 或者‘File->Export可以导出网格文件。使用导出功能时,可以自行指定格式,如vtk。软件会根据目标格式自动调整格式。
在图窗区域双击可以弹出一个快速快捷菜单,可用于快速切换网格实体(如曲面)的可见性、重置视口、选择旋转中心、显示轴或访问完整模块选项
gmsh可以同时加载多个文件,比如将.pos文件和.msh文件与第一个教程的文件 t1合并,可以输入以下命令:
gmsh t1.geo view1.pos view5.msh
加载一个或多个后处理视图时,树菜单中会出现“后处理”条目。使用上一个命令,“后处理”下的树菜单中将出现三个视图,分别标记为“A scalar map”、“Nodal scalar map”和“Element 1 vector”。在本例中,视图包含多个时间步骤:您可以使用状态栏左侧的快捷键图标循环查看这些步骤。鼠标单击视图名称将切换所选视图的可见性,而单击右侧的箭头按钮将提供对视图选项的访问。
请注意,以交互方式指定的所有选项也可以直接在脚本文件中指定。gmsh可以以 .opt格式的文件保存操作后的各种配置,方便下次直接读取,保存方式为 File->Save Model Options。若想将某视角保存为默认视角,则可选择File->Save Options As Default
本段基础教程结束。
鼠标操作
左键:旋转、选择实体或接受套作缩放或套索选择
Ctrl+左键: 开始套索缩放或套索(取消)选择
中键:缩放//取消选择实体//接受套索缩放或取消选择套索
Ctrl+中键:正交显示
右键:平移//取消套索缩放或套索(取消)选择//后处理视图按钮上的弹出菜单
Ctrl+右键:重置为默认视点
(对于没有中键的鼠标:中键等于shift+左键)
键盘操作
太多了,挑几个可能有用的:
数字0:重新载入模型(所以轻易别按)
Ctrl+0 或9: 重新载入整个项目(更是轻易别按)
数字1或F1:画线的网格
数字2或F2:画面的网格
数字3或F3:画体积的网格
g:转到几何模块
m:转到网格模块
p:转到后处理模块
s:转到解算器模块
e:在几何体创建模式下结束/接受选择
q:在几何体创建模式下中止选择
x,y,z:在几何体创建模式下切换x,y,z坐标冻结
shift+x,y,z:在几何体创建模式中仅沿x,y,z坐标移动
alt+b:隐藏/显示边界框
alt+x,y,z:设置x,y,z视图
alt+shift+x,y,z:设置x,y,z负轴视图
alt+l,p,s,v:隐藏/显示几何线条,点,面,体积
alt+shift+l,p,s,v:隐藏/显示网格的线条,点,面,体积
脚本语言
太多了,选几个常用的提一下吧。。
- 注释:/*alskdjfalsdfj*/, or //
- 看实例 t1.geo
// -----------------------------------------------------------------------------
// Gmsh GEO tutorial 1
// Geometry basics, elementary entities, physical groups
// -----------------------------------------------------------------------------
//首先定义一个新的变量,这个变量将被用于点的定义
lc = 1e-2;
// 定义点,前三个变量表示空间位置XYZ,第四个变量表示这个点附近的网格大小
// 实例t10.geo里有直接定义通用网格大小的字段。
Point(1) = {0, 0, 0, lc};
Point(2) = {.1, 0, 0, lc};
Point(3) = {.1, .3, 0, lc};
Point(4) = {0, .3, 0, lc};
// 定义曲线,大括号里的是点的标签。注意这里的曲线方向,第二条是从点3到点2
Line(1) = {1, 2};
Line(2) = {3, 2};
Line(3) = {3, 4};
Line(4) = {4, 1};
// 利用刚才定义的线来定义一个封闭环,大括号里的是线的标签
// 在纸上画一下刚才定义的四条线,可以发现大括号里的顺序可以闭环。
Curve Loop(1) = {4, 1, -2, 3};
// 根据闭环定义曲面,大括号里是封闭环的标签
// 实例4里有如何画带孔洞的封闭环的代码
Plane Surface(1) = {1};
// 以上内容已经足以告诉gmsh怎么画出这个矩形曲面和网格了
// 还有一些高端操作,将机和实体分组,这里将第1,2,4直线定义为一个物理曲线组
// 将1号曲面(即定义的矩形曲面)定义为一个平面组
Physical Curve(5) = {1, 2, 4};
Physical Surface("My surface") = {1};
// 现在写的这个.geo文件可以在gmsh中通过 file->open打开,也可以在文件所在目录中通过命令:
// gmsh xxxx.geo 来打开,这里的xxxx用文件的实际名称代替。
// *************重要,在脚本中输出网格**************
// 若在文件最后添加下面的指令,则打开文件会自动生成2D网格并保存为msh文件
// Mesh 2;
// Save "t1.msh";
// 也可以通过改变后缀来保存为其他格式的网格文件,比如:
// msh1, msh2, msh22, msh3, msh4, msh40, msh41, msh, unv, vtk, wrl, mail, stl,
// p3d, mesh, bdf, cgns, med, diff, ir3, inp, ply2, celum, su2, x3d, dat, neu,
// m, key, off, rad
// 若使用 OpenCASCADE内核, 可以更简单地定义矩形曲面:
// Rectangle(2) = {.2, 0, 0, .1, .3};
// 确定CAD内核为 OpenCASCADE,在文件开头加入指令: SetFactory("OpenCASCADE");
- 看教程t20.geo,将其中注释翻译一下,可以应对大部分使用场景,如果有不清楚的,可以到官方教程里按ctrl+f搜索关键词,然后比对更多示例猜测使用方法。
// -----------------------------------------------------------------------------
// Gmsh GEO tutorial 20
// STEP导入和操作、几何分区
// -----------------------------------------------------------------------------
// 本文件目的:加载step格式的模型并修改,将其切片
SetFactory("OpenCASCADE"); //确定CAD内核为 OpenCASCADE
// 加载STEP文件,使用“ShapeFromFile”,将文件加载到变量v()
v() = ShapeFromFile("t20_data.step");
// 如果在读入文件之前输入以下语句:
// Geometry.OCCTargetUnit = "M";
// 则表示将单位设置为 米,若未指定,则默认情况下认为单位为 毫米
// 使用以下几个命令来获取刚才导入的物体的体积边界框,分别为三个轴向的投影的最小和最大值。
bbox() = BoundingBox Volume{v()};
xmin = bbox(0);
ymin = bbox(1);
zmin = bbox(2);
xmax = bbox(3);
ymax = bbox(4);
zmax = bbox(5);
// 我们希望将模型分割成N个切片,并保留体积切片或仅切割获得的曲面:
// DefineConstant[ string = { expression|string-expression, onelab-options } <, ...>];
// 使用值表达式创建新的表达式标识符字符串
// 下面调用这个模块的作用是,在图形界面的树形图最下面会出现代码下方图1所示的选项。
DefineConstant[
N = {5, Min 2, Max 100, Step 1, Name "Parameters/0Number of slices"}
dir = {0, Choices{0="X", 1="Y", 2="Z"}, Name "Parameters/1Direction"}
surf = {0, Choices{0, 1}, Name "Parameters/2Keep only surfaces?"}
];
dx = (xmax - xmin); // 定义体积的长宽高变量
dy = (ymax - ymin);
dz = (zmax - zmin);
L = (dir == 0) ? dz : dx;//与C中的语法相似,若满足括号条件则取冒号左端值,否则取右端。
H = (dir == 1) ? dz : dy;
// 创建一个切割面
s() = {news};
// news 表示新的表面,
// 同理,newc/newcl/newsl/newv分别表示新曲线、曲线环、新曲面、曲面环和新体积
Rectangle(s(0)) = {xmin, ymin, zmin, L, H};
// 旋转和平移模块的使用
/*
将5号点沿着x轴移动-0.02(单位为默认)
Translate {-0.02, 0, 0} { Point{5}; }
将5号点绕着{0,0.3,0}点旋转 -pi/4,第一个括号里的内容是旋转轴,第二个括号里的是中心点。
Rotate {{0,0,1}, {0,0.3,0}, -Pi/4} { Point{5}; }
将3号点复制并沿Y轴平移0.05。
3号点可以被复制并沿Y轴平移0.05。新的点会被顺延分配标签。
*/
If(dir == 0)
Rotate{ {0, 1, 0}, {xmin, ymin, zmin}, -Pi/2 } { Surface{s(0)}; }
ElseIf(dir == 1)
Rotate{ {1, 0, 0}, {xmin, ymin, zmin}, Pi/2 } { Surface{s(0)}; }
EndIf
// 共分为N层,设置每层的高度,然后将新的层放到该切片的位置
tx = (dir == 0) ? dx / N : 0;
ty = (dir == 1) ? dy / N : 0;
tz = (dir == 2) ? dz / N : 0;
Translate{tx, ty, tz} { Surface{s(0)}; }
// 将物体切成N片
For i In {1:N-2}
s() += Translate{i * tx, i * ty, i * tz} { Duplicata{ Surface{s(0)}; } };
EndFor
// 用所有的切割平面分割(即相交)体积。这里体积与曲面相交,delete 表示不产生重复界面。
BooleanFragments{ Volume{v()}; Delete; }{ Surface{s()}; Delete; }
// 移除不在体积边界上的所有曲面,曲面的多余部分。
Recursive Delete { Surface{:}; }
// 这句没看懂是想干嘛,在软件里点选上就啥也不显示了,大概是某种高端的选项吧。
If(surf)
// If we want to only keep the surfaces, retrieve the surfaces in bounding
// boxes around the cutting planes...
eps = 1e-4;
s() = {};
For i In {1:N-1}
xx = (dir == 0) ? xmin : xmax;
yy = (dir == 1) ? ymin : ymax;
zz = (dir == 2) ? zmin : zmax;
s() += Surface In BoundingBox
{xmin - eps + i * tx, ymin - eps + i * ty, zmin - eps + i * tz,
xx + eps + i * tx, yy + eps + i * ty, zz + eps + i * tz};
EndFor
// ...and remove all the other entities:
dels = Surface{:};
dels -= s();
Delete { Volume{:}; Surface{dels()}; Curve{:}; Point{:}; }
EndIf
// 指定全局网格大小
// 这个东西有用
Mesh.MeshSizeMin = 3;
Mesh.MeshSizeMax = 3;
// 可以在教程 t21 中查看划分网格而不是几何体的代码
//+
// 创建一个字符串类型的新字段(带有标记表达式)。最后这两行到底是啥意思,不清数
Field[1] = Max;
//+
Delete Field [1];
在编写完这个geo文件后,在gmsh 软件中打开。
若要修改文件,点geometry里的edit script,打开文件后修改,然后保存,在geometry里点reload
脚本画3D网格
Mesh 3;
脚本导出网格
注意,如果使用脚本导出,则每次打开文件的时候都会顺便导出网格文件。
Save "t1.msh";
Save "t1.vtk";
图1.
软件操作
如果觉得脚本写的太麻烦了,可以先写好引入模型的语句(通常是STEP文件),然后就在软件里操作。最简单的操作是使用默认网格大小,在导入模型后点击mesh->3D。
改变网格大小
在使用过程中,默认的网格大小通常难以满足需求,导致某些孔位或曲面太过粗糙,在软件中可以使用如下操作:
0. 导入模型文件。(在空项目中编辑脚本打开.step文件或者在软件中点击file->open打开都可以。),显示如下图:
(注:若想改变此时模型显示的信息,可以在旁边空白处双击鼠标左键,弹出菜单后点击“All geometry options”,在Geometry的visibility里可选显示哪些信息(如下图)。同理,在Mesh里也可以选择显示哪些东西。)
- 设置点周围的网格大小。点击左侧树形的Mesh->Define->Size at points。弹窗如下图所示,里面的数字就是将要选取的点周围的网格大小。
此时屏幕上提示选点,按住ctrl,用鼠标框选想要设置为当前数值的点,框选后按e键确认;然后修改弹窗里的数值,继续选其他点,将其他点周围网格大小设置为新的数值并确认;当所有点都这样设置完后,按q退出设置。
- 画网格。点击mesh->3D(或2D,按需选择),生成符合预期的网格导出即可。(我遇到了模型中可选的点比较少的情况,或许会影响画出来的网格效果,不过不重要,总算能够出一个比较满意的网格了)
删除网格
生成网格后(1D/2D/3D都适用),点击下图的删除element:
按照提示,先用Ctrl+鼠标左键框选要删除的网格,再按“e”确认,就可以看到网格被删除了。这里框选网格时,只要被框碰到的都会被删除。删除完成后按“q”退出。
接下来导出网格为想要的格式就行。
网格导出
在软件里打开
点file:
这些都可以选,最常见的方式是直接点export,然后输入文件名时把自己想输出的格式的后缀也打上去。
软件画好网格后在软件中点击 File ->save mesh, 或者‘File->Export可以导出网格文件。使用导出功能时,可以自行指定格式,如vtk。软件会根据目标格式自动调整格式。如果有弹窗让选择编码格式,一般来说选择二进制binary。
结语
看起来好像这个软件的作者更希望大家直接使用脚本。如果有长期使用需求的话,更建议学习使用Python编写,因为这个软件提供的API功能挺全的,且使用Python更方便集成到其他项目中,能够使自动化程度更高。
写到这里时还没测试生成的网格能不能满足SOFA的实验需求,如果有其他问题再回来编辑。
补充:
- 在SOFA里使用时用vtk文件做网格,用stl文件做模型外观,出现了stl无法跟着vtk一起旋转平移的情况。在这里找了好久的bug,最后通过对比官方的stl文件和我的stl文件,发现可能是因为官方的stl文件也是gmsh生成的,而我的是SolidWorks生成的。于是试着使用gmsh生成stl文件,问题解决。stl文件生成方法:将模型step文件导入gmsh,划分网格后export为stl格式,编码选择二进制binary。