Skip to content

第14章 各向异性网格(Anisotropic Mesh):方向感知的网格生成


14.1 学习目标

  • 理解各向同性网格(Isotropic Mesh)与各向异性网格(Anisotropic Mesh)的本质区别:标量尺寸 vs 张量度量(metric tensor)
  • 掌握通过 merge() 加载 .pos 文件作为各向异性背景网格的方法,理解 TT(张量三角形)格式中度量张量的含义
  • 学会使用 bamg(Bidimensional Anisotropic Mesh Generator)作为二维各向异性网格生成器,包括 Mesh.Algorithm=7Mesh.SmoothRatioMesh.AnisoMax 等关键选项
  • 理解各向异性网格在 CAE 中的典型应用场景:CFD 边界层网格(壁面法向加密、流向稀疏)、激波捕捉、复合材料界面
  • 建立本章与第7章(背景网格)、第8章(尺寸场)的知识联系——各向异性背景网格是标量背景网格的张量推广

14.2 核心概念说明

14.2.1 各向同性 vs 各向异性网格

在前面的章节中,我们通过点级 lc、标量背景网格(第7章)、尺寸场(第8章)控制的网格都是各向同性(Isotropic)的。这意味着在空间的任意一点,网格尺寸在所有方向上都相同——单元是"正三角形"(2D)或"正四面体"(3D),没有方向偏好。

各向异性(Anisotropic)网格则不同:在空间中的每一点,网格尺寸是一个方向相关的量。不同方向允许不同的网格边长。例如,在 CFD 壁面附近: - 垂直于壁面的方向需要极细的网格(捕捉边界层速度梯度) - 平行于壁面的方向可以用较粗的网格(流向变化缓慢)

这种方向依赖性无法用单一的标量值描述,而需要一个 2x2(二维)或 3x3(三维)对称正定的度量张量(Metric Tensor)

网格类型 尺寸描述 单元形状 典型场景
各向同性(Isotropic) 标量 h(x,y,z) 正三角形/正四面体 通用结构分析、无方向偏好的均匀细化
各向异性(Anisotropic) 度量张量 M(x,y,z) ∈ R^(dxd) 拉伸三角形/四面体 CFD 边界层、激波、复合材料

14.2.2 度量张量(Metric Tensor)的几何意义

在二维空间中,度量张量 M 是一个 2x2 对称正定矩阵。它可以谱分解为:

M = R^T * diag(1/h1^2, 1/h2^2) * R

其中: - h1h2 是两个正交主方向上的期望网格边长 - R 是旋转矩阵,描述主方向在空间中的朝向 - 当 h1 = h2 时,退化为各向同性情况;当 h1 << h2 时,实现强各向异性(在一个方向上极度加密)

Gmsh 内部使用该度量张量来计算任意两点之间的各向异性距离,并据此驱动网格生成器构造拉伸单元。

14.2.3 bamg:二维各向异性网格生成器

Gmsh 内置的默认二维网格生成器 Mesh.Algorithm=6(Frontal-Delaunay)主要面向各向同性网格。对于各向异性二维网格,Gmsh 调用 bamg(Bidimensional Anisotropic Mesh Generator),通过设置 Mesh.Algorithm=7 启用。bamg 是一个基于 Delaunay 的各向异性网格生成器,能够根据度量张量场生成高质量的各向异性三角形。

关键选项:

选项 含义 建议值
Mesh.Algorithm 二维网格算法 7 = bamg
Mesh.SmoothRatio 平滑比,控制相邻单元尺寸变化的剧烈程度 1.2 ~ 3.0
Mesh.AnisoMax 最大各向异性比(最长边/最短边) 100 ~ 10000(视边界层需求)

14.2.4 各向异性背景网格的 .pos 格式

与第7章使用的标量 .pos 格式(ST 标量三角形)不同,各向异性背景网格使用的是 TT(Tensor Triangle,张量三角形)格式:

View "nodalMetric" {
TT(x1,y1,z1, x2,y2,z2, x3,y3,z3){m11,m12,m13, m21,m22,m23, m31,m32,m33, ...};
};
  • 前三个括号:三角形三个顶点的坐标(共9个值)
  • 花括号内:每个顶点上的 3x3 度量张量(对称矩阵,共9个值),三个顶点共27个值
  • 对于二维问题(z=0),度量张量的第3行/列退化为 (0, 0, 1),实际生效的是左上角 2x2 子矩阵

t17_bgmesh.pos 中,度量张量在方块的左半部分值较小(网格较粗),右上角区域值很大(网格较细),且张量表现出明显的方向性(非对角线元素非零),引导生成拉伸方向的三角形。

14.2.5 各向异性 mesh::field 定义方式

除了加载 .pos 文件作为背景网格外,Gmsh 也支持通过 gmsh::model::mesh::field API 程序化地定义各向异性尺寸场。使用 F(MathEval)场的矩阵表达式或通过 setNumber 设置矩阵参数的方式可构建自定义度量场,但通常 .pos 文件方式更为实用——它可以由外部求解器(如误差估计器)生成,并在 Gmsh 中直接用于网格重剖。

14.2.6 与第7章和第8章的关系

本章内容与第7章和第8章形成递进关系:

第7章: 标量背景网格(ST 格式)—— 每点一个标量尺寸 h
   ↓ 推广
第8章: 尺寸场(Distance/MathEval/Box 等)—— 参数化控制标量尺寸
   ↓ 推广
第14章: 各向异性背景网格(TT 格式)—— 每点一个度量张量 M(方向+尺寸)

三者共享 setAsBackgroundMesh() 的统一接口,差异仅在于数据本身是标量还是张量。当背景网格提供的是张量数据时,Gmsh 自动将其作为各向异性度量场处理。


14.3 C++ 代码逐段讲解

14.3.1 创建几何体

首先创建一个 4x4 的二维方块作为计算域:

#include <set>
#include <cmath>
#include <gmsh.h>

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

  // 创建一个 4x4 的二维方块,左下角 (-2, -2),边长 4
  gmsh::model::occ::addRectangle(-2, -2, 0, 4, 4);
  gmsh::model::occ::synchronize();

解释:通过 OpenCASCADE 内核创建一个 [-2, 2] x [-2, 2] 的正方形平面区域。synchronize() 将 CAD 模型同步到 Gmsh 内部数据结构。该区域将作为各向异性网格的剖分域。


14.3.2 加载各向异性背景网格文件

  // 加载包含各向异性度量张量的后处理视图
  try {
    gmsh::merge("../t17_bgmesh.pos");
  } catch(...) {
    gmsh::logger::write("无法加载各向异性背景网格文件: 退出!");
    gmsh::finalize();
    return 0;
  }

解释gmsh::merge() 加载外部后处理文件。这里加载的 t17_bgmesh.pos 文件包含一个名为 "nodalMetric" 的后处理视图,其中每个三角形的每个顶点都携带一个 3x3 度量张量。文件中的 TT 条目定义了张量场在空间中的分布:在域的不同位置度量张量的大小和方向各不相同,从而实现空间变化的方向性网格控制。

该文件通常由外部工具(如误差估计器、自适应求解器、或 Python 脚本)生成,覆盖整个计算域。对于实际 CAE 工作流,你可以用自己的求解器输出替换此文件。


14.3.3 将视图注册为背景网格

  // 将加载的后处理视图注册为各向异性背景网格
  int bgField = gmsh::model::mesh::field::add("PostView");
  gmsh::model::mesh::field::setNumber(bgField, "ViewIndex", 0);
  gmsh::model::mesh::field::setAsBackgroundMesh(bgField);

解释:这是将外部数据关联到网格生成管线的关键三步:

  1. field::add("PostView") 创建一个 PostView 类型的尺寸场。PostView 场类型从已加载的后处理视图中读取尺寸信息。
  2. field::setNumber(bgField, "ViewIndex", 0) 指定使用第 0 号视图(即 merge() 加载的第一个视图)。如果 .pos 文件包含多个视图,可通过改变此索引选择不同视图。
  3. field::setAsBackgroundMesh(bgField) 将该场设为全局背景网格,所有后续网格生成操作都将查询此场中的度量张量。

PostView 场能自动区分标量视图(ST,生成各向同性网格)和张量视图(TT,生成各向异性网格),无需手动指定。


14.3.4 配置 bamg 各向异性网格生成器

  // 配置 bamg 各向异性二维网格生成器
  gmsh::option::setNumber("Mesh.SmoothRatio", 3);
  gmsh::option::setNumber("Mesh.AnisoMax", 1000);
  gmsh::option::setNumber("Mesh.Algorithm", 7);

解释:三个选项协同配置 bamg 的行为:

  • Mesh.Algorithm = 7:显式选择 bamg 作为二维网格生成器。Gmsh 的默认算法(Frontal-Delaunay, 算法 6)不能生成各向异性网格——如果不设此项,Gmsh 会从度量张量中提取各向同性尺寸(取主方向最大尺寸),仅生成各向同性网格。
  • Mesh.SmoothRatio = 3:控制相邻单元之间的尺寸过渡平滑度。该值越大,网格尺寸变化越剧烈。bamg 需要对梯度合理的度量场才能收敛,若场中的尺寸变化过于剧烈,需调小此值。
  • Mesh.AnisoMax = 1000:允许的最大各向异性比(最长边与最短边之比)。此处设 1000,允许在边界层区域产生极度拉伸的三角形。实际值应根据物理需求设定——CFD 边界层通常需要 100~10000 的比值。

注意Mesh.SmoothRatio 对 bamg 的作用与对各向同性生成器不同。bamg 用它在度量空间中进行梯度限制(gradient limiting),防止度量张量在空间上变化过快导致网格质量恶化。


14.3.5 生成网格并输出

  // 生成二维各向异性网格
  gmsh::model::mesh::generate(2);

  // 保存为 .msh 文件
  gmsh::write("t14_anisotropic.msh");

  // 启动 GUI 查看结果(如未指定 -nopopup)
  std::set<std::string> args(argv, argv + argc);
  if(!args.count("-nopopup")) gmsh::fltk::run();

  gmsh::finalize();
  return 0;
}

解释mesh::generate(2) 生成二维网格,Gmsh 内部调用 bamg 的库函数,依据度量张量场在各处生成尺寸和方向匹配的三角形。生成后通过 gmsh::write() 导出为标准 .msh 格式文件,可直接用于后续 CAE 求解器。fltk::run() 打开 Gmsh 的图形界面,供用户可视化检查各向异性网格效果。


14.4 面向 CAE 的应用场景

14.4.1 CFD 边界层网格

在计算流体力学(CFD)中,壁面附近的边界层具有极强的速度梯度,需要在壁面法向布置极细的网格,而流向(平行于壁面)则可以粗糙得多。各向异性网格天然适合此场景:

  • 度量张量的主轴在壁面法向上对应极小尺寸 h_n(如 0.001mm)
  • 壁面切向对应较大尺寸 h_t(如 1mm)
  • 各向异性比 h_t / h_n 可达 1000 以上

传统方法通过结构化边界层网格(棱柱层)实现,而 bamg + 各向异性背景网格提供了非结构化替代方案,能更好地处理复杂几何。

14.4.2 激波捕捉

在高超声速流动中,激波是一个极薄的区域(几倍分子平均自由程),需要用极细的网格解析。激波的法向需要加密,而激波面内的方向可以粗糙。自适应求解器可在激波位置输出各向异性度量张量,迭代生成对齐激波方向的拉伸网格。

14.4.3 复合材料界面

复合材料(如纤维增强层合板)中,基体与纤维的界面处应力梯度在界面法向远大于切向。各向异性网格可以在不显著增加总单元数的前提下,在界面法向提高分辨率。


14.5 各向异性背景网格的生成方法

在实际 CAE 工作流中,各向异性背景网格通常不由手工编写,而是通过以下途径自动生成:

  1. 自适应误差估计:在粗网格上求解,计算每个单元的误差指示器(如 Hessian recovery),然后根据 Hessian 矩阵的特征值和特征向量构造各向异性度量张量,导出为 .pos 文件
  2. 解析度量场:对于简单几何和已知解特征的问题,可通过 Python/MATLAB 脚本根据几何位置直接计算度量张量并写入 .pos
  3. CFD 求解器内置输出:某些求解器(如 SU2、Code_Saturne)支持直接输出 Gmsh 格式的各向异性度量场

以下是一个简单的 Python 片段示意如何生成 .pos 文件中的各向异性数据:

# 示意: 生成壁面法向加密的各向异性度量张量 .pos 文件
# 实际使用时需要根据几何计算每个节点的位置和度量张量

import numpy as np

def metric_at(x, y):
    """在壁面 y=0 附近,法向(y)加密,切向(x)稀疏"""
    dist = y  # 到壁面距离
    h_normal = 0.001 + 0.1 * dist        # 壁面法向: 0.001 ~ 远场 0.1
    h_tangential = 0.1                    # 壁面切向: 恒为 0.1
    # 度量张量 M = diag(1/h_x^2, 1/h_y^2)
    return np.array([[1/h_tangential**2, 0],
                     [0, 1/h_normal**2]])

# 输出为 .pos TT 格式...

14.6 关键 API 速查表

API 用途 说明
gmsh::merge(filename) 加载后处理视图文件 支持 .pos 格式,自动解析 ST/TT 等单元类型
gmsh::model::mesh::field::add("PostView") 创建 PostView 尺寸场 将已加载视图的内容注册为可用的尺寸场
gmsh::model::mesh::field::setNumber(f, "ViewIndex", idx) 选择视图索引 指定使用 merge 加载的第几个视图(从 0 开始)
gmsh::model::mesh::field::setAsBackgroundMesh(f) 设为背景网格 全局生效,所有后续 generate() 均受其控制
option::setNumber("Mesh.Algorithm", 7) 选择 bamg 算法 二维各向异性网格的必要条件
option::setNumber("Mesh.SmoothRatio", v) 度量梯度平滑比 控制 bamg 对度量张量空间变化的平滑程度
option::setNumber("Mesh.AnisoMax", v) 最大各向异性比 允许的最大边长比,防止过度拉伸导致数值问题
gmsh::model::mesh::generate(2) 生成二维网格 在 Mesh.Algorithm=7 时调用 bamg
gmsh::write("file.msh") 输出网格文件 标准 Gmsh 网格格式,包含节点、单元及度量数据

14.7 注意事项与常见问题

  1. bamg 仅支持二维Mesh.Algorithm=7 对三维网格无效。对于三维各向异性网格,需使用 Gmsh 与外部库(如 MMG3D)的集成,或分步骤生成(先生成二维边界层,再向三维拉伸)。

  2. 度量张量必须光滑:bamg 对度量张量的空间连续性有要求。若 .pos 文件中相邻三角形的度量值差异过大,需增大 Mesh.SmoothRatio 或先在外部对度量场进行平滑处理。

  3. 文件中不能混用 ST 和 TT:作为各向异性背景网格的视图应全部使用 TT 类型。如果使用 ST,Gmsh 将退化为各向同性处理。

  4. 三维张量格式:即使做二维问题,.pos 文件中的度量张量仍然是 3x3 格式。对于 z=0 平面上的二维问题,第三行/列通常为 (0, 0, 1)

  5. 与其他尺寸约束的冲突:如第8章所述,Gmsh 多层尺寸优先级链的各层取最小值。如果几何点上有极小的 lc 值,它会盖过背景网格的度量张量。如需纯粹依赖背景网格,应关闭 Mesh.MeshSizeFromPoints 等其他来源:

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


14.8 完整可运行代码

// -----------------------------------------------------------------------------
//  Chapter 14: Anisotropic Mesh — Direction-Aware Mesh Generation
//
//  功能: 加载各向异性背景网格 (.pos),使用 bamg 在方块上生成各向异性二维网格
//
//  编译 (需链接 Gmsh SDK):
//    g++ -o ch14_aniso ch14_aniso.cpp -lgmsh
//
//  运行:
//    ./ch14_aniso          (带 GUI 查看)
//    ./ch14_aniso -nopopup  (仅生成 .msh 文件)
// -----------------------------------------------------------------------------

#include <set>
#include <cmath>
#include <gmsh.h>

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

  // ---- 1. 创建几何体 ----
  // 创建一个 4x4 的二维方块,左下角 (-2, -2)
  gmsh::model::occ::addRectangle(-2, -2, 0, 4, 4);
  gmsh::model::occ::synchronize();

  // ---- 2. 加载各向异性背景网格 ----
  // t17_bgmesh.pos 中包含 TT(张量三角形)数据,定义了度量张量场
  try {
    gmsh::merge("../t17_bgmesh.pos");
  } catch(...) {
    gmsh::logger::write("Could not load anisotropic background mesh; exiting.");
    gmsh::finalize();
    return 0;
  }

  // ---- 3. 将后处理视图注册为背景网格 ----
  int bgField = gmsh::model::mesh::field::add("PostView");
  gmsh::model::mesh::field::setNumber(bgField, "ViewIndex", 0);
  gmsh::model::mesh::field::setAsBackgroundMesh(bgField);

  // ---- 4. 配置 bamg 各向异性二维网格生成器 ----
  gmsh::option::setNumber("Mesh.SmoothRatio", 3);
  gmsh::option::setNumber("Mesh.AnisoMax", 1000);
  gmsh::option::setNumber("Mesh.Algorithm", 7);

  // ---- 5. 生成二维各向异性网格 ----
  gmsh::model::mesh::generate(2);

  // ---- 6. 输出网格 ----
  gmsh::write("ch14_anisotropic.msh");

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

  gmsh::finalize();
  return 0;
}

14.9 本章小结

  • 各向异性网格通过度量张量(Metric Tensor)在每一点同时描述网格尺寸和方向偏好,突破各向同性网格"所有方向同尺寸"的限制。
  • .pos 文件中的 TT(张量三角形)格式携带每个顶点上的 3x3 度量张量,是各向异性背景网格的数据载体。
  • PostView 场类型 + setAsBackgroundMesh() 将外部度量数据路由到 Gmsh 网格生成管线。
  • Mesh.Algorithm=7 启用 bamg 是生成二维各向异性网格的必要条件;Mesh.AnisoMax 控制各向异性比的物理上限。
  • 本章内容与第7章和第8章构成完整递进:标量尺寸 -> 标量尺寸场 -> 张量度量场(各向异性)。
  • 在 CAE 实践中,CFD 边界层、激波捕捉和复合材料界面是各向异性网格的三个核心应用场景。