Skip to content

第8章 网格尺寸场 (Mesh Size Fields)


8.1 学习目标

  • 理解 Gmsh 网格尺寸场(Mesh Size Field)的概念,掌握五种核心场类型:Distance、Threshold、MathEval、Box、Min 的用途与 API 调用方式
  • 学会通过 setAsBackgroundMesh 将尺寸场设为背景网格,以及通过 setSizeCallback 用 C++ lambda 实现自定义尺寸回调
  • 掌握 Gmsh 网格尺寸计算五层优先级链,并能关闭干扰项以避免过度细化(over-refinement)
  • 了解 Delaunay(算法 5)与 Frontal-Delaunay(算法 6)对大梯度尺寸场的适应性差异

8.2 核心概念说明

8.2.1 什么是网格尺寸场

在前面的章节中,我们通过在几何点上指定 lc 参数(第 1-2 章)或使用背景网格(background mesh,第 7 章)来控制网格大小。Gmsh 还提供了一种更强大、更灵活的机制——网格尺寸场 (Mesh Size Field)

尺寸场的本质是一个标量函数:给定空间中的任意坐标 (x, y, z),返回该点处期望的网格单元尺寸。通过在域内逐点定义不同的期望尺寸,你可以实现:

  • 局部细化:在应力集中区布置极细网格
  • 渐变过渡:在粗细网格之间平滑过渡
  • 数学表达式控制:用解析函数定义任意分布的网格尺寸
  • 多约束合成:组合多个场的约束,取最严格者

8.2.2 场类型概览

本章覆盖以下五种核心场类型:

场类型 用途 关键参数
Distance 返回到指定点/曲线的距离值 PointsList, CurvesList, Sampling
Threshold 将距离值映射为网格尺寸(分段线性) InField, SizeMin, SizeMax, DistMin, DistMax
MathEval 用数学表达式直接定义尺寸 F(支持 x,y,z 变量及 F4 引用其他场)
Box 盒内/盒外不同尺寸 + 过渡区 VIn, VOut, XMin/Max, YMin/Max, ZMin/Max, Thickness
Min 取多个场的逐点最小值作为最终尺寸 FieldsList

Gmsh 还提供其他场类型(如 Structured, Attractor, Restrict, Gradient, Max, Frustum, Intersect, MathEvalCombined 等),完整列表参见 Gmsh 参考手册。

8.2.3 网格尺寸计算的五层优先级链

在网格生成时,Gmsh 对每个网格点依次计算以下几层尺寸,取各层的最小值

第 1 层: 模型包围盒尺寸(全局最大尺寸的兜底)
    ↓ (取 min)
第 2 层: Mesh.MeshSizeFromPoints — 几何点上的 lc 值(如启用)
    ↓ (取 min)
第 3 层: Mesh.MeshSizeFromCurvature — 曲率自适应尺寸(如 > 0)
    ↓ (取 min)
第 4 层: 背景网格尺寸场 (Background Mesh Field)
    ↓ (取 min)
第 5 层: 逐实体网格尺寸约束 (Per-entity Mesh Size Constraint)

此后,该值还会经过尺寸回调函数setSizeCallback,如果已设置)的进一步修正,然后被限制在 [Mesh.MeshSizeMin, Mesh.MeshSizeMax] 区间内,最后乘以 Mesh.MeshSizeFactor。此外,边界网格尺寸还受 Mesh.MeshSizeExtendFromBoundary 控制是否向面/体内部插值。

当网格尺寸已完全由尺寸场指定时(如本章示例),应关闭第 2、3 层及边界扩展,以避免它们干扰场定义的尺寸分布:

gmsh::option::setNumber("Mesh.MeshSizeExtendFromBoundary", 0);
gmsh::option::setNumber("Mesh.MeshSizeFromPoints", 0);
gmsh::option::setNumber("Mesh.MeshSizeFromCurvature", 0);

8.3 C++ 代码逐段讲解

8.3.1 初始化与几何建立

首先创建一块单位矩形面 [0,1] x [0,1],并额外添加点 5 (0.2, 0.5, 0) 用于后续 Distance 场演示:

#include <set>
#include <sstream>
#include <algorithm>
#include <gmsh.h>

int main(int argc, char **argv) {
  gmsh::initialize(argc, argv);
  gmsh::model::add("t10");

  double lc = 0.15;
  gmsh::model::geo::addPoint(0.0, 0.0, 0, lc, 1);
  gmsh::model::geo::addPoint(1.0, 0.0, 0, lc, 2);
  gmsh::model::geo::addPoint(1.0, 1.0, 0, lc, 3);
  gmsh::model::geo::addPoint(0.0, 1.0, 0, lc, 4);
  gmsh::model::geo::addPoint(0.2, 0.5, 0, lc, 5);

  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}, 5);
  gmsh::model::geo::addPlaneSurface({5}, 6);
  gmsh::model::geo::synchronize();

这里 lc = 0.15 是所有边界点的默认网格尺寸。之后我们通过尺寸场在局部覆盖此默认值。


8.3.2 Distance 场(距离场)

Distance 场 (Field Type: "Distance") 返回空间中任意一点到指定几何实体(点或曲线)的最短距离。它是最基础也最常用的场——几乎所有后续有物理意义的尺寸控制都始于距离。

  // 定义 Distance 场 (Field 1): 到点 5 和曲线 2 的距离
  gmsh::model::mesh::field::add("Distance", 1);
  gmsh::model::mesh::field::setNumbers(1, "PointsList", {5});
  gmsh::model::mesh::field::setNumbers(1, "CurvesList", {2});
  gmsh::model::mesh::field::setNumber(1, "Sampling", 100);

参数解释: - "PointsList":要计算距离的目标点标签列表(此处为点 5) - "CurvesList":要计算距离的目标曲线标签列表(此处为曲线 2) - "Sampling":曲线上的采样点数(默认为 100)。Gmsh 在曲线上等距采样后计算到采样点的最近距离。采样数越大,距离计算越精确

Distance 场返回的是一个距离值(浮点数),而非尺寸值。因此它通常作为 Intermediate Field(中间场) 输入到其他场(如 Threshold、MathEval)中进行后续映射。


8.3.3 Threshold 场(阈值场)

Threshold 场 (Field Type: "Threshold") 将 Distance 场的返回距离值分段线性映射为网格尺寸值。映射关系如下:

  SizeMax  -                      /------------------
           |                     /
           |                    /
           |                   /
  SizeMin  -  o--------------/
           |  |              |        |
           +--+--------------+--------+----> 距离
              Point         DistMin  DistMax
  • 距离 < DistMin 时:尺寸 = SizeMin(精细化区域)
  • 距离 > DistMax 时:尺寸 = SizeMax(粗网格区域)
  • 距离在 [DistMin, DistMax] 之间:线性插值过渡
  • Distance=0 时对应 Point 处,此时尺寸取 SizeMin(默认值,未在图中显式标出起始段)
  // 定义 Threshold 场 (Field 2): 将 Distance 场 1 的值映射为尺寸
  gmsh::model::mesh::field::add("Threshold", 2);
  gmsh::model::mesh::field::setNumber(2, "InField", 1);    // 引用 Field 1
  gmsh::model::mesh::field::setNumber(2, "SizeMin", lc / 30);
  gmsh::model::mesh::field::setNumber(2, "SizeMax", lc);
  gmsh::model::mesh::field::setNumber(2, "DistMin", 0.15);
  gmsh::model::mesh::field::setNumber(2, "DistMax", 0.5);

参数解释: - "InField":输入场编号,即要引用的 Distance 场(这里是 Field 1) - "SizeMin" / "SizeMax":网格尺寸的最小值和最大值 - "DistMin" / "DistMax":距离阈值范围

这段代码的效果是:在点 5 和曲线 2 附近 0.15 以内的区域,网格尺寸取 lc/30 = 0.005(精细);在 0.5 以外的区域,尺寸取 lc = 0.15(较粗);中间区域平滑过渡。


8.3.4 MathEval 场(数学表达式场)

MathEval 场 (Field Type: "MathEval") 直接用数学表达式定义空间各点的网格尺寸。这是最灵活的方式——你可以用任意解析函数描述网格分布。

  // 定义 MathEval 场 (Field 3): 用空间坐标的三角函数调制尺寸
  gmsh::model::mesh::field::add("MathEval", 3);
  gmsh::model::mesh::field::setString(
      3, "F", "cos(4*3.14*x) * sin(4*3.14*y) / 10 + 0.101");

参数 "F" 是一个字符串,代表数学表达式。表达式语法支持:

类别 内容
空间变量 x, y, z — 当前评估点的坐标
场引用 F1, F2, F3, ... — 引用 Field N 的返回值(见下节)
运算符 +, -, *, /, ^ (幂)
函数 cos, sin, tan, exp, log, log10, sqrt, abs, fmod, atan2, hypot, min, max, if, floor, ceil, round

上例中 cos(4*pi*x) * sin(4*pi*y) / 10 + 0.101 会在矩形面上产生波纹状的网格尺寸分布——波峰位置得大尺寸,波谷位置得小尺寸。


8.3.5 MathEval 引用其他场(F4 跨场引用)

MathEval 的表达式可以引用任意已定义的场。通过 F<id> 语法(如 F4 表示 Field 4 的返回值),可以将多个场级联起来实现复杂逻辑。

首先定义一个 Distance 场,然后令 MathEval 场引用其返回距离值:

  // 定义 Distance 场 (Field 4): 到点 1 的距离
  gmsh::model::mesh::field::add("Distance", 4);
  gmsh::model::mesh::field::setNumbers(4, "PointsList", {1});

  // 定义 MathEval 场 (Field 5): 引用 Field 4 的返回值 (F4)
  gmsh::model::mesh::field::add("MathEval", 5);
  std::stringstream stream;
  stream << "F4^3 + " << lc / 100;
  gmsh::model::mesh::field::setString(5, "F", stream.str());

这里 F4 代表 Field 4(距离场)在当前位置的返回值——即当前点到点 1 的距离。表达式 F4^3 + lc/100 的作用是:以三次律(cubic law)使网格尺寸随距离增加而增大。越靠近点 1,尺寸越小(最小值为 lc/100 = 0.0015)。

这种 Distance + MathEval引用F4 的组合手法非常常见,它可以实现任意函数形状的尺寸过渡,而不限于 Threshold 的线性映射。


8.3.6 Box 场(盒形场)

Box 场 (Field Type: "Box") 定义一个长方体内的精细网格区和体外粗网格区,中间通过 Thickness 参数指定过渡层厚度。

  // 定义 Box 场 (Field 6): 盒内精细,盒外粗糙,中间过渡
  gmsh::model::mesh::field::add("Box", 6);
  gmsh::model::mesh::field::setNumber(6, "VIn", lc / 15);       // 盒内尺寸
  gmsh::model::mesh::field::setNumber(6, "VOut", lc);           // 盒外尺寸
  gmsh::model::mesh::field::setNumber(6, "XMin", 0.3);
  gmsh::model::mesh::field::setNumber(6, "XMax", 0.6);
  gmsh::model::mesh::field::setNumber(6, "YMin", 0.3);
  gmsh::model::mesh::field::setNumber(6, "YMax", 0.6);
  gmsh::model::mesh::field::setNumber(6, "Thickness", 0.3);

参数解释:

参数 含义
VIn 盒体内部的网格尺寸
VOut 盒体外部的网格尺寸
XMin/XMax 盒体在 X 方向的边界坐标
YMin/YMax 盒体在 Y 方向的边界坐标
ZMin/ZMax 盒体在 Z 方向的边界坐标(3D 情况使用,默认全空间覆盖)
Thickness 过渡区宽度。在盒体边界外 Thickness 范围内,尺寸从 VIn 平滑过渡到 VOut

Box 场非常适合在已知关键区域位置但不想手动布置几何点时快速施加局部细化。典型应用场景包括:焊缝热影响区、螺栓孔周围、裂纹尖端区域等。


8.3.7 Min 组合场

当同时定义了多个尺寸场后,Gmsh 在每个点处需要确定最终的尺寸值。Min 场 (Field Type: "Min") 取多个场的逐点最小值作为最终尺寸。

为什么要取最小值?因为网格尺寸控制遵循"最严格者胜"原则——模拟需要在所有高梯度区域都有足够分辨率,取 min 能同时满足所有约束。

  // 定义 Min 场 (Field 7): 取 Fields 2,3,5,6 的最小值
  gmsh::model::mesh::field::add("Min", 7);
  gmsh::model::mesh::field::setNumbers(7, "FieldsList", {2, 3, 5, 6});

"FieldsList" 接受一个整数数组,列出要参与比较的场编号。Gmsh 中还有 "Max" 场用于取最大值,以及 "Restrict" 场用于将某个场的输出限制在指定区域内。


8.3.8 setAsBackgroundMesh — 将场提升为背景网格

创建的 Min 场需要通过 setAsBackgroundMesh 注册为背景网格尺寸场,Gmsh 才会在网格生成时使用它:

  gmsh::model::mesh::field::setAsBackgroundMesh(7);

此函数将 Field 7 的输出提升为第 8.2.3 节中第 4 层优先级。一次只能有一个场充当背景网格。


8.3.9 setSizeCallback — C++ Lambda 自定义尺寸回调

除了预定义的场类型,Gmsh C++ API 还提供了完全自定义的尺寸回调机制。通过 setSizeCallback,你可以传入一个 C++ 函数对象(lambda、函数指针等),该函数在每次网格点需要确定尺寸时被调用:

  // 自定义尺寸回调:在每个点取默认值与 0.02*x+0.01 的最小值
  auto meshSizeCallback = [](int dim, int tag, double x, double y, double z,
                             double lc) {
    return std::min(lc, 0.02 * x + 0.01);
  };
  gmsh::model::mesh::setSizeCallback(meshSizeCallback);

回调签名:

double callback(int dim, int tag, double x, double y, double z, double lc);
参数 含义
dim 当前查询的实体维度(0=点,1=线,2=面,3=体)
tag 当前查询的实体标签
x, y, z 当前网格评估点的坐标
lc Gmsh 内部已经计算出的尺寸值(经前五层及回调之前所有步骤处理后)
返回值 最终使用的尺寸值

回调函数在五层优先级链之后、尺寸钳制([MeshSizeMin, MeshSizeMax])之前被调用。它既可以进一步细化(返回比 lc 更小的值),也可以放宽约束(返回更大值)。回调适用于无法通过预定义场类型表达的复杂尺寸逻辑,例如:

  • 从外部文件读取实测尺寸分布数据
  • 调用外部求解器计算后验误差估计
  • 基于特定材料属性做差异化尺寸控制

8.3.10 关闭干扰项与算法选择

如前文(8.2.3 节)所述,当尺寸已完全由尺寸场控制时,应关闭默认的边界扩展和曲率自适应等干扰:

  gmsh::option::setNumber("Mesh.MeshSizeExtendFromBoundary", 0);
  gmsh::option::setNumber("Mesh.MeshSizeFromPoints", 0);
  gmsh::option::setNumber("Mesh.MeshSizeFromCurvature", 0);

算法选择:Gmsh 的 2D 网格生成提供两种主流算法:

算法 ID 名称 特点
6(默认) Frontal-Delaunay 网格质量最高,但在大梯度尺寸场下稳定性较差
5 Delaunay 对大梯度尺寸场适应性更好,网格过渡更自然

当尺寸场包含剧烈的尺寸变化(如 lc/30lc 的 30 倍对比度)时,推荐使用 Delaunay 算法:

  gmsh::option::setNumber("Mesh.Algorithm", 5);

然后生成 2D 网格并输出:

  gmsh::model::mesh::generate(2);
  gmsh::write("t10.msh");

8.4 完整可运行代码

// ============================================================================
// 第 8 章完整示例:Gmsh 网格尺寸场 (Mesh Size Fields)
// 编译: g++ -o ch08 ch08.cpp -I/path/to/gmsh/include -L/path/to/gmsh/lib -lgmsh
// ============================================================================

#include <set>
#include <sstream>
#include <algorithm>
#include <gmsh.h>

int main(int argc, char **argv) {
  gmsh::initialize(argc, argv);
  gmsh::model::add("ch08_demo");

  // ======================== 1. 建立几何 ========================
  double lc = 0.15;
  gmsh::model::geo::addPoint(0.0, 0.0, 0, lc, 1);
  gmsh::model::geo::addPoint(1.0, 0.0, 0, lc, 2);
  gmsh::model::geo::addPoint(1.0, 1.0, 0, lc, 3);
  gmsh::model::geo::addPoint(0.0, 1.0, 0, lc, 4);
  gmsh::model::geo::addPoint(0.2, 0.5, 0, lc, 5);

  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}, 5);
  gmsh::model::geo::addPlaneSurface({5}, 6);
  gmsh::model::geo::synchronize();

  // ======================== 2. Distance 场 (Field 1) ========================
  // 返回到点 5 和曲线 2 的距离,曲线上采样 100 个点
  gmsh::model::mesh::field::add("Distance", 1);
  gmsh::model::mesh::field::setNumbers(1, "PointsList", {5});
  gmsh::model::mesh::field::setNumbers(1, "CurvesList", {2});
  gmsh::model::mesh::field::setNumber(1, "Sampling", 100);

  // ======================== 3. Threshold 场 (Field 2) ========================
  // 将 Field 1 的距离值映射为网格尺寸
  // 距离 < 0.15 -> 尺寸 = lc/30 ; 距离 > 0.5 -> 尺寸 = lc ; 中间线性过渡
  gmsh::model::mesh::field::add("Threshold", 2);
  gmsh::model::mesh::field::setNumber(2, "InField", 1);
  gmsh::model::mesh::field::setNumber(2, "SizeMin", lc / 30);
  gmsh::model::mesh::field::setNumber(2, "SizeMax", lc);
  gmsh::model::mesh::field::setNumber(2, "DistMin", 0.15);
  gmsh::model::mesh::field::setNumber(2, "DistMax", 0.5);

  // ======================== 4. MathEval 场 (Field 3) ========================
  // 三角函数调制,产生波纹状尺寸分布
  gmsh::model::mesh::field::add("MathEval", 3);
  gmsh::model::mesh::field::setString(
      3, "F", "cos(4*3.14*x) * sin(4*3.14*y) / 10 + 0.101");

  // ======================== 5. Distance + MathEval 级联 ========================
  // Field 4: 到点 1 的距离
  gmsh::model::mesh::field::add("Distance", 4);
  gmsh::model::mesh::field::setNumbers(4, "PointsList", {1});

  // Field 5: F4 引用 Field 4 的输出,三次律尺寸分布
  gmsh::model::mesh::field::add("MathEval", 5);
  std::stringstream stream;
  stream << "F4^3 + " << lc / 100;
  gmsh::model::mesh::field::setString(5, "F", stream.str());

  // ======================== 6. Box 场 (Field 6) ========================
  // 盒 [0.3, 0.6] x [0.3, 0.6] 内尺寸=lc/15,盒外=lc,过渡层厚度 0.3
  gmsh::model::mesh::field::add("Box", 6);
  gmsh::model::mesh::field::setNumber(6, "VIn", lc / 15);
  gmsh::model::mesh::field::setNumber(6, "VOut", lc);
  gmsh::model::mesh::field::setNumber(6, "XMin", 0.3);
  gmsh::model::mesh::field::setNumber(6, "XMax", 0.6);
  gmsh::model::mesh::field::setNumber(6, "YMin", 0.3);
  gmsh::model::mesh::field::setNumber(6, "YMax", 0.6);
  gmsh::model::mesh::field::setNumber(6, "Thickness", 0.3);

  // ======================== 7. Min 组合场 (Field 7) ========================
  // 取所有场的逐点最小值作为最终尺寸
  gmsh::model::mesh::field::add("Min", 7);
  gmsh::model::mesh::field::setNumbers(7, "FieldsList", {2, 3, 5, 6});

  // ======================== 8. 设为背景网格 ========================
  gmsh::model::mesh::field::setAsBackgroundMesh(7);

  // ======================== 9. 自定义尺寸回调 (Lambda) ========================
  auto meshSizeCallback = [](int dim, int tag, double x, double y, double z,
                             double lc) {
    return std::min(lc, 0.02 * x + 0.01);
  };
  gmsh::model::mesh::setSizeCallback(meshSizeCallback);

  // ======================== 10. 关闭干扰项,选择算法 ========================
  gmsh::option::setNumber("Mesh.MeshSizeExtendFromBoundary", 0);
  gmsh::option::setNumber("Mesh.MeshSizeFromPoints", 0);
  gmsh::option::setNumber("Mesh.MeshSizeFromCurvature", 0);
  gmsh::option::setNumber("Mesh.Algorithm", 5);   // Delaunay,更适合大梯度尺寸场

  // ======================== 11. 生成网格并输出 ========================
  gmsh::model::mesh::generate(2);
  gmsh::write("ch08_result.msh");

  // ======================== 12. 显示 GUI(可选) ========================
  std::set<std::string> args(argv, argv + argc);
  if (!args.count("-nopopup")) gmsh::fltk::run();

  gmsh::finalize();
  return 0;
}

保存为 ch08.cpp 后编译运行:

g++ -o ch08 ch08.cpp -I/path/to/gmsh/include -L/path/to/gmsh/lib -lgmsh
./ch08              # 打开 GUI 查看结果
./ch08 -nopopup     # 仅生成 ch08_result.msh,不打开 GUI

8.5 关键 API 速查表

场管理 (gmsh::model::mesh::field)

函数 签名 / 示例 说明
add field::add("Distance", tag) 创建指定类型的尺寸场,须指定唯一标签
setNumber field::setNumber(tag, "Key", value) 设置场的单个数值参数
setNumbers field::setNumbers(tag, "Key", {v1, v2, ...}) 设置场的数组参数(如点/曲线列表)
setString field::setString(tag, "F", "expr") 设置场的字符串参数(如 MathEval 的表达式)
setAsBackgroundMesh field::setAsBackgroundMesh(tag) 将指定场注册为背景网格尺寸场
list field::list() 列出所有已定义的场

尺寸回调

函数 说明
gmsh::model::mesh::setSizeCallback(callback) 设置全局尺寸回调,callback 签名: double(int dim, int tag, double x, double y, double z, double lc)
gmsh::model::mesh::removeSizeCallback() 移除已设置的尺寸回调

相关选项 (gmsh::option)

选项名 类型 默认值 说明
Mesh.Algorithm integer 6 2D 网格算法:5=Delaunay, 6=Frontal-Delaunay, 7=BAMG, 8=DelQuad
Mesh.MeshSizeExtendFromBoundary integer 1 是否将边界尺寸向内部域插值(0=关闭)
Mesh.MeshSizeFromPoints integer 1 是否使用几何点的 lc 参数(0=关闭)
Mesh.MeshSizeFromCurvature integer 0 曲率自适应元素数/2pi(0=关闭,正值为每 2pi 弧度的元素数)
Mesh.MeshSizeMin float 全局最小网格尺寸(硬上限)
Mesh.MeshSizeMax float 全局最大网格尺寸(硬上限)
Mesh.MeshSizeFactor float 1.0 全局网格尺寸缩放系数

MathEval 表达式语法简表

类别 语法
坐标变量 x, y, z
场引用 F1, F2, F3, ... (引用 Field N 的返回值)
运算符 +, -, *, /, ^ (幂运算)
三角函数 cos, sin, tan, acos, asin, atan, atan2(y,x), hypot(x,y)
指数/对数 exp, log (自然对数), log10
平方根/绝对值 sqrt, abs, fmod(x,y)
极值 min(x,y), max(x,y)
条件 if(cond, val_true, val_false)
取整 floor, ceil, round
常量 Pi, E

8.6 常见问题与注意事项

  1. 场标签必须唯一:每个 field::add 的第二个参数是整数标签,不能重复使用。建议用递增整数或枚举来管理。

  2. InField 引用必须先定义:Threshold 场的 InField 参数所引用的场(如 Distance 场)必须在 Threshold 场之前创建。

  3. Sampling 的取值:Distance 场的 Sampling 控制曲线上采样点数。对于高曲率曲线,采样不足会导致距离计算误差,建议取值 100-1000。

  4. Thickness 的过渡机制:Box 场的 Thickness 定义的过渡是通过线性插值实现。Thickness 设为 0 时可获得硬边界(不推荐,会生成质量极差的过渡网格)。

  5. 尺寸回调的性能setSizeCallback 中的 lambda 在网格生成时被频繁调用(每个候选节点一次)。避免在回调中执行重量级操作(如文件 I/O、网络请求等)。

  6. Delaunay vs Frontal-Delaunay:当尺寸场中有超过 10 倍的尺寸梯度时,强烈建议使用 Mesh.Algorithm = 5 (Delaunay)。默认的 Frontal-Delaunay(算法 6)在平滑尺寸场下可生成更高质量网格,但遇到大梯度尺寸场容易出现网格空洞或扭曲单元。

  7. Min 场的必要性:如果你只定义一个场并直接设其为背景网格,则不需要 Min 场。仅当多个场同时生效时才需要组合。