Skip to content

第22章 遍历模型与网格数据:前处理查询 API 全解


22.1 学习目标

  • 理解 Gmsh 模型实体(Model Entity)的 (dim, tag) 标识体系,掌握 getEntities() 遍历全部几何实体
  • 掌握 mesh::getNodes() 按实体或全局获取节点坐标,理解交错(interleaved)坐标存储格式
  • 掌握 mesh::getElements() 获取单元类型、单元标签和节点连接列表(element connectivity),以及 getElementsByType() 按类型筛选
  • 学会使用 getType()getEntityName() 查询实体类型与名称
  • 掌握 getAdjacencies() 查询上邻接(upward)和下邻接(downward)关系
  • 理解物理组(Physical Group)与 getPhysicalGroupsForEntity() / getPhysicalName() 的查询
  • 掌握分区信息查询:getPartitions()getParent() 追溯分区实体的原始父实体
  • 掌握 mesh::getElementProperties() 查询单元类型的名称、维度、阶次、节点数和参数坐标
  • 能够编写完整的前处理数据提取程序,为有限元求解器输入准备网格数据

22.2 核心概念说明

22.2.1 模型实体(Model Entity)与 (dim, tag) 标识

Gmsh 中所有几何信息由模型实体(Model Entity)组成,按维度分为四类:

维度 实体类型 英文名称 说明
0 Point 几何点
1 曲线 Curve 几何边
2 曲面 Surface 几何面
3 Volume 几何体

每个实体由一个 (dim, tag) 对唯一标识,其中 dim 为维度(0-3),tag 为严格正整数的标签。模型实体可以来自内置 geo 内核、OpenCASCADE occ 内核,也可以是离散实体(Discrete Entity)——由网格本身定义,没有底层 CAD 几何。

网格数据(Nodes 和 Elements)被分类(classified)到相应的模型实体上。例如:一个面实体包含其内部的三角形/四边形单元以及内部节点,而边界节点和边界边上的单元则存储在其边界实体上。这种分类关系使得前处理程序可以按实体精准提取网格子集。

22.2.2 网格数据结构概览

模型(Model)
 ├── 实体列表 (dim, tag) pairs
 │    ├── Point (0, n)        ← 含点单元 + 孤立节点
 │    ├── Curve (1, n)        ← 含线单元 + 内部节点
 │    ├── Surface (2, n)      ← 含三角形/四边形 + 内部节点
 │    └── Volume (3, n)       ← 含四面体/六面体等 + 内部节点
 │
 ├── 节点 (Nodes)
 │    ├── nodeTag: 全局唯一正整数
 │    ├── coords: x1,y1,z1, x2,y2,z2, ...  (交错存储)
 │    └── parametricCoords: 参数坐标(可选)
 │
 ├── 单元 (Elements)
 │    ├── elemType: Gmsh 单元类型编号 (1=2节点线, 2=3节点三角形, 4=4节点四面体, ...)
 │    ├── elemTags: 每种类型的单元标签列表
 │    └── nodeTags: 每种类型的节点连接列表 (CCW 或 Gmsh 规定顺序)
 │
 └── 物理组 (Physical Groups)
      └── (dim, physicalTag) 引用一组模型实体

22.2.3 单元类型编号与命名规则

Gmsh 预定义了数百种单元类型。常用的包括:

类型编号 名称 说明 节点数
1 Line 2 2 节点线单元 2
2 Triangle 3 3 节点三角形 3
3 Quadrangle 4 4 节点四边形 4
4 Tetrahedron 4 4 节点四面体 4
5 Hexahedron 8 8 节点六面体 8
6 Prism 6 6 节点三棱柱 6
7 Pyramid 5 5 节点金字塔 5
8 Line 3 3 节点二阶线单元 3
9 Triangle 6 6 节点二阶三角形 6
15 Point 1 1 节点点单元 1

通过 getElementProperties() 可以查询任意类型编号对应的完整属性。

22.2.4 邻接关系(Adjacencies)

Gmsh 为每个实体维护拓扑邻接关系:

  • 上邻接(Upward Adjacencies):当前实体是哪些更高维实体的边界。例如一个面(dim=2)的上邻接是包含该面的体(dim=3);一条线(dim=1)的上邻接是包含该线的面。
  • 下邻接(Downward Adjacencies):当前实体的边界由哪些更低维实体构成。例如一个面的下邻接是其边界线和边界点;一个体的下邻接是其边界面。

22.2.5 分区实体与父子关系

当网格被分区(见第21章)后,Gmsh 创建分区实体(Partition Entity)。通过 getPartitions(dim, tag) 可获取分区索引列表,通过 getParent(dim, tag) 可追溯该分区实体的原始父实体(parentDim, parentTag)。非分区实体的这两个查询返回空结果。

22.2.6 物理组(Physical Group)

物理组是模型实体的命名集合,仍按 (dim, physicalTag) 标识。它用于在网格导出时标记边界条件区域(如 inlet、outlet、wall 等)。通过 getPhysicalGroupsForEntity() 可反查某个实体属于哪些物理组。


22.3 C++ 代码逐段讲解

22.3.1 初始化与模型准备

#include <gmsh.h>
#include <iostream>
#include <vector>

int main(int argc, char **argv)
{
    gmsh::initialize();

    // 支持从命令行加载已有MSH文件,或自动创建示例几何
    if(argc > 1 && argv[1][0] != '-') {
        gmsh::open(argv[1]);
    } else {
        // 创建一个简单的锥体作为示例几何体
        gmsh::model::occ::addCone(1, 0, 0, 1, 0, 0, 0.5, 0.1);
        gmsh::model::occ::synchronize();
        gmsh::model::mesh::generate();
    }

    // 获取模型名称和维度
    std::string modelName;
    gmsh::model::getCurrent(modelName);
    int modelDim = gmsh::model::getDimension();
    std::cout << "Model: " << modelName << " (" << modelDim << "D)\n";

这段代码初始化 Gmsh,可选择从 MSH 文件读取已有网格(gmsh::open())或自动创建一个锥体并生成网格。getCurrent() 返回当前模型名称,getDimension() 返回模型最高维度。

22.3.2 遍历所有实体:getEntities()

    // 获取模型中所有实体的 (dim, tag) 对
    std::vector<std::pair<int, int>> entities;
    gmsh::model::getEntities(entities);

    std::cout << "Total entities: " << entities.size() << "\n\n";

    // 也可按维度过滤
    // gmsh::model::getEntities(entities, 2);  // 仅获取面实体 (dim=2)

getEntities() 返回一个 vector<pair<int,int>>,每个元素是一个 (dim, tag) 对。可选第二个参数 dim 按维度过滤(-1 表示全部维度)。这是遍历模型几何结构的入口 API。

常见使用模式: 在前处理程序中,首先调用 getEntities() 获取全部实体列表,然后遍历每个实体提取其网格数据。

22.3.3 遍历节点:mesh::getNodes()

    for(auto e : entities) {
        int dim = e.first, tag = e.second;

        // ---- 获取该实体上的网格节点 ----
        std::vector<std::size_t> nodeTags;
        std::vector<double> nodeCoords, parametricCoords;
        gmsh::model::mesh::getNodes(nodeTags, nodeCoords,
                                     parametricCoords, dim, tag);

        std::cout << "Entity (" << dim << "," << tag << "): "
                  << nodeTags.size() << " nodes\n";

        // 坐标按 x1,y1,z1, x2,y2,z2, ... 交错存储
        for(std::size_t i = 0; i < nodeTags.size(); i++) {
            double x = nodeCoords[i * 3 + 0];
            double y = nodeCoords[i * 3 + 1];
            double z = nodeCoords[i * 3 + 2];
            // 在此构建求解器节点数据结构
        }

mesh::getNodes() 的完整签名:

void getNodes(vector<size_t> &nodeTags,
              vector<double> &coord,
              vector<double> &parametricCoord,
              int dim = -1, int tag = -1,
              bool includeBoundary = false,
              bool returnParametricCoord = true);

关键参数说明: - dim / tag:指定实体,只获取该实体上的节点。两者都设为 -1 则获取全部网格节点。 - includeBoundary:设为 true 时也会包含该实体边界上的节点(默认 false,只返回内部节点)。 - coord:坐标数组,按 x0, y0, z0, x1, y1, z1, ... 顺序交错存储。数组长度为 nodeTags.size() * 3。 - parametricCoords:节点的参数坐标(用于高阶单元),可用 returnParametricCoord=false 跳过。

前处理要点: 通常需要按实体提取节点(指定 dim/tag),然后在求解器中将它们映射为局部编号。三维坐标用 coords[i*3 + 0/1/2] 模式索引。

22.3.4 遍历单元:mesh::getElements()

        // ---- 获取该实体上的网格单元 ----
        std::vector<int> elemTypes;
        std::vector<std::vector<std::size_t>> elemTags, elemNodeTags;
        gmsh::model::mesh::getElements(elemTypes, elemTags,
                                        elemNodeTags, dim, tag);

        int totalElems = 0;
        for(auto &tags : elemTags) totalElems += tags.size();
        std::cout << "  Elements: " << totalElems << " ("
                  << elemTypes.size() << " types)\n";

mesh::getElements() 的签名:

void getElements(vector<int> &elementTypes,
                 vector<vector<size_t>> &elementTags,
                 vector<vector<size_t>> &nodeTags,
                 int dim = -1, int tag = -1);

关键数据结构: - elementTypes[type1, type2, ...],该实体上出现的单元类型编号列表。 - elementTags[[tagsForType1], [tagsForType2], ...],与 elementTypes 一一对应,每项是单元标签的向量。 - nodeTags[[nodesForType1], [nodesForType2], ...],与 elementTypes 一一对应。对于第 k 种类型,nodeTags[k] 包含所有该类单元的节点编号按序拼接——即连接性数组(connectivity)。

遍历每个单元的具体实现:

        // 遍历每种单元类型
        for(std::size_t iType = 0; iType < elemTypes.size(); iType++) {
            int eType = elemTypes[iType];
            auto &eTags = elemTags[iType];
            auto &nTags = elemNodeTags[iType];

            // 查询该类型每个单元有几个节点
            std::string eName;
            int eDim, eOrder, numNodes, numPrimaryNodes;
            std::vector<double> localCoords;
            gmsh::model::mesh::getElementProperties(
                eType, eName, eDim, eOrder, numNodes,
                localCoords, numPrimaryNodes);

            std::cout << "  Type " << eType << " (" << eName
                      << "), order=" << eOrder
                      << ", nodes/elem=" << numNodes
                      << ", count=" << eTags.size() << "\n";

            // 遍历该类型的每个单元
            for(std::size_t j = 0; j < eTags.size(); j++) {
                std::size_t elemTag = eTags[j];
                // 该单元的节点连接从 nTags 中提取
                // nTags[j*numNodes] 到 nTags[j*numNodes + numNodes - 1]
            }
        }

前处理要点: nodeTags[iType] 是展平的一维数组,第 j 个单元的 numNodes 个节点起始于索引 j * numNodes。构建求解器单元结构时,先通过 getElementProperties() 获取 numNodes,再逐单元切片提取。

22.3.5 单元属性查询:mesh::getElementProperties()

        // 演示每一个单元类型的详细属性
        for(auto eType : elemTypes) {
            std::string eName;
            int eDim, eOrder, numNodes, numPrimaryNodes;
            std::vector<double> localCoord;
            gmsh::model::mesh::getElementProperties(
                eType, eName, eDim, eOrder, numNodes,
                localCoord, numPrimaryNodes);

            std::cout << "  [" << eType << "] " << eName
                      << ": dim=" << eDim << ", order=" << eOrder
                      << ", nodes=" << numNodes
                      << ", primaryNodes=" << numPrimaryNodes
                      << "\n";
        }

输出参数说明:

参数 类型 说明
eName string 单元名称,如 "Triangle 3"、"Tetrahedron 4"
eDim int 单元维度
eOrder int 单元阶次(1=线性, 2=二次, ...)
numNodes int 单元总节点数
localCoord vector 参数空间中的节点局部坐标,交错存储
numPrimaryNodes int 主节点数(不含边中点和内部高阶节点)

22.3.6 邻接关系查询:getAdjacencies()

        // ---- 查询上邻接和下邻接 ----
        std::vector<int> upward, downward;
        gmsh::model::getAdjacencies(dim, tag, upward, downward);

        if(!upward.empty()) {
            std::cout << "  Upward: ";
            for(auto adjTag : upward)
                std::cout << "(" << dim+1 << "," << adjTag << ") ";
            std::cout << "\n";
        }
        if(!downward.empty()) {
            std::cout << "  Downward: ";
            for(auto adjTag : downward)
                std::cout << "(" << dim-1 << "," << adjTag << ") ";
            std::cout << "\n";
        }

upward 返回更高维邻接实体的 tag(维度为 dim+1),downward 返回更低维邻接实体的 tag(维度为 dim-1)。实际用法:需记录维度偏移,upward 中的 tag 需要配合 dim+1 才能构成完整 (dim, tag) 标识。

典型场景: 已知一个面实体,查 upward 得到它属于哪个体(用于材料属性传播);已知一个体实体,查 downward 得到它的边界面(用于边界条件施加)。

22.3.7 物理组查询

        // ---- 该实体属于哪些物理组 ----
        std::vector<int> physicalTags;
        gmsh::model::getPhysicalGroupsForEntity(dim, tag, physicalTags);

        if(!physicalTags.empty()) {
            std::cout << "  Physical groups: ";
            for(auto pt : physicalTags) {
                std::string physName;
                gmsh::model::getPhysicalName(dim, pt, physName);
                std::cout << "\"" << physName << "\" ("
                          << dim << "," << pt << ") ";
            }
            std::cout << "\n";
        }

getPhysicalGroupsForEntity() 返回该实体所属的物理组标签列表。然后通过 getPhysicalName() 获取物理组的可读名称(如 "inlet"、"wall")。这是 CAE 前处理中识别边界条件区域的常用方法。

22.3.8 分区信息与父实体

        // ---- 是否分区实体?父实体是谁? ----
        std::vector<int> partitions;
        gmsh::model::getPartitions(dim, tag, partitions);
        if(!partitions.empty()) {
            std::cout << "  Partitions: ";
            for(auto p : partitions) std::cout << p << " ";
            int parentDim, parentTag;
            gmsh::model::getParent(dim, tag, parentDim, parentTag);
            std::cout << " <- parent (" << parentDim << ","
                      << parentTag << ")\n";
        }

分区后,getPartitions() 返回该实体所属分区的索引(从 0 起)。getParent() 追溯该分区实体来自哪个原始父实体。非分区实体两个查询均返回空结果。

22.3.9 实体类型与名称

        // ---- 实体类型和名称 ----
        std::string entityType;
        gmsh::model::getType(dim, tag, entityType);
        std::string entityName;
        gmsh::model::getEntityName(dim, tag, entityName);

        std::cout << "Entity " << entityName
                  << " of type " << entityType
                  << " (" << dim << "," << tag << ")\n";

getType() 返回实体类型字符串: - dim=0: "Point" - dim=1: "Curve" - dim=2: "Surface" - dim=3: "Volume" - 离散实体: "Discrete Point", "Discrete Curve", "Discrete Surface", "Discrete Volume"

getEntityName() 返回在 GEO 脚本中或 OCC 建模时赋予的实体名称(可能为空)。

22.3.10 按类型获取单元:getElementsByType()(补充)

getElements() 一次性获取某实体上所有类型单元外,Gmsh 还提供按类型获取的 API:

    // 获取2D三角单元(type=2)的所有单元
    std::vector<std::size_t> triTags, triNodes;
    gmsh::model::mesh::getElementsByType(2, triTags, triNodes);

    std::cout << "Triangle 3 count: " << triTags.size() << "\n";
    // triNodes 展平存储: [n0,n1,n2, n0,n1,n2, ...]

getElementsByType() 的签名:

void getElementsByType(int elementType,
                        vector<size_t> &elementTags,
                        vector<size_t> &nodeTags,
                        int tag = -1,
                        size_t task = 0,
                        size_t numTasks = 1);

参数 tasknumTasks 支持并行分区读取:numTasks=N 时将数据分成 N 份,task=k 读取第 k 份。单线程使用时保持默认值 task=0, numTasks=1

22.3.11 全局节点获取与求解器数据导出

当不关心实体划分,需要一次性导出全部网格时,可调用全局模式:

    // 全局获取所有节点(dim=-1, tag=-1)
    std::vector<std::size_t> allNodeTags;
    std::vector<double> allCoords, allParamCoords;
    gmsh::model::mesh::getNodes(allNodeTags, allCoords,
                                 allParamCoords, -1, -1);

    // 全局获取所有单元类型
    std::vector<int> allElemTypes;
    gmsh::model::mesh::getElementTypes(allElemTypes);

    std::cout << "Global: " << allNodeTags.size() << " nodes, "
              << allElemTypes.size() << " element types\n";

getElementTypes() 可选 dimtag 参数按实体过滤。全局模式下,这是导出完整求解器输入的最快方式。

22.3.12 完整遍历循环骨架

将所有查询整合到外层循环中,形成标准的前处理查询骨架:

    std::vector<std::pair<int, int>> entities;
    gmsh::model::getEntities(entities);

    for(auto &e : entities) {
        int dim = e.first, tag = e.second;

        // 1. 基础信息
        std::string eType, eName;
        gmsh::model::getType(dim, tag, eType);
        gmsh::model::getEntityName(dim, tag, eName);

        // 2. 物理组
        std::vector<int> physTags;
        gmsh::model::getPhysicalGroupsForEntity(dim, tag, physTags);

        // 3. 邻接关系
        std::vector<int> up, down;
        gmsh::model::getAdjacencies(dim, tag, up, down);

        // 4. 分区信息
        std::vector<int> parts;
        gmsh::model::getPartitions(dim, tag, parts);

        // 5. 节点
        std::vector<std::size_t> nodeTags;
        std::vector<double> coords, paramCoord;
        gmsh::model::mesh::getNodes(nodeTags, coords, paramCoord, dim, tag);

        // 6. 单元
        std::vector<int> elemTypes;
        std::vector<std::vector<std::size_t>> elemTags, elemNodeTags;
        gmsh::model::mesh::getElements(elemTypes, elemTags, elemNodeTags,
                                        dim, tag);

        // 7. 按求解器需求重组数据...
    }

22.3.13 清理与结束

    gmsh::clear();
    gmsh::finalize();
    return 0;
}

gmsh::clear() 清除所有模型数据,gmsh::finalize() 释放 Gmsh 内部资源。注意如果之前使用了 gmsh::fltk::run() 启动 GUI,应在关闭窗口后再调用 clear()


22.4 完整可运行代码

// ch22_full.cpp — 遍历模型所有实体并打印完整网格信息
#include <gmsh.h>
#include <iostream>
#include <vector>
#include <set>

int main(int argc, char **argv)
{
    gmsh::initialize();

    // 步骤1:准备模型(加载文件或创建示例几何)
    if(argc > 1 && argv[1][0] != '-') {
        gmsh::open(argv[1]);
    } else {
        // 创建一个复杂一点的几何:圆柱体方便展示所有实体类型
        gmsh::model::occ::addCylinder(0, 0, 0, 0, 0, 1, 0.5);
        gmsh::model::occ::synchronize();
        // 设置网格尺寸并生成
        gmsh::option::setNumber("Mesh.MeshSizeMin", 0.2);
        gmsh::model::mesh::generate(3);
    }

    // 步骤2:打印模型基本信息
    std::string modelName;
    gmsh::model::getCurrent(modelName);
    std::cout << "============================================\n";
    std::cout << "Model: " << modelName
              << " (dim=" << gmsh::model::getDimension() << ")\n";
    std::cout << "============================================\n\n";

    // 步骤3:获取全部实体列表
    std::vector<std::pair<int, int>> entities;
    gmsh::model::getEntities(entities);

    std::cout << "Total entities: " << entities.size() << "\n\n";

    // 全局统计
    std::size_t totalNodes = 0, totalElements = 0;

    // 步骤4:遍历每个实体
    for(auto &e : entities) {
        int dim = e.first, tag = e.second;

        // --- 4a. 实体类型与名称 ---
        std::string entityType, entityName;
        gmsh::model::getType(dim, tag, entityType);
        gmsh::model::getEntityName(dim, tag, entityName);

        std::cout << "---- Entity (" << dim << "," << tag << ") ----\n";
        if(!entityName.empty())
            std::cout << "  Name: \"" << entityName << "\"\n";
        std::cout << "  Type: " << entityType << "\n";

        // --- 4b. 节点 ---
        std::vector<std::size_t> nodeTags;
        std::vector<double> coords, paramCoord;
        gmsh::model::mesh::getNodes(nodeTags, coords, paramCoord, dim, tag);
        std::cout << "  Nodes: " << nodeTags.size() << "\n";
        totalNodes += nodeTags.size();

        if(!nodeTags.empty()) {
            // 打印前3个节点坐标示例
            int showN = std::min(3, (int)nodeTags.size());
            std::cout << "  Sample coords: ";
            for(int i = 0; i < showN; i++) {
                std::cout << "n" << nodeTags[i] << "("
                          << coords[i*3+0] << ","
                          << coords[i*3+1] << ","
                          << coords[i*3+2] << ") ";
            }
            std::cout << "\n";
        }

        // --- 4c. 单元 ---
        std::vector<int> elemTypes;
        std::vector<std::vector<std::size_t>> elemTags, elemNodeTags;
        gmsh::model::mesh::getElements(elemTypes, elemTags, elemNodeTags,
                                        dim, tag);

        int entityElemCount = 0;
        for(auto &tags : elemTags) entityElemCount += tags.size();
        totalElements += entityElemCount;
        std::cout << "  Elements: " << entityElemCount << "\n";

        // 打印每种单元类型的详细信息
        for(std::size_t t = 0; t < elemTypes.size(); t++) {
            std::string eName;
            int eDim, eOrder, numNodes, numPrimaryNodes;
            std::vector<double> localCoords;
            gmsh::model::mesh::getElementProperties(
                elemTypes[t], eName, eDim, eOrder, numNodes,
                localCoords, numPrimaryNodes);

            std::cout << "    [" << elemTypes[t] << "] " << eName
                      << ": " << elemTags[t].size()
                      << " elems, order=" << eOrder
                      << ", nodes/elem=" << numNodes;

            // 展示第一个单元的连接性
            if(!elemTags[t].empty()) {
                std::cout << "\n      elem#" << elemTags[t][0]
                          << " nodes=[";
                for(int n = 0; n < numNodes; n++) {
                    std::cout << elemNodeTags[t][n] << " ";
                }
                std::cout << "]";
            }
            std::cout << "\n";
        }

        // --- 4d. 邻接关系 ---
        std::vector<int> up, down;
        gmsh::model::getAdjacencies(dim, tag, up, down);
        if(!up.empty()) {
            std::cout << "  Upward (" << dim+1 << "D): ";
            for(auto u : up) std::cout << u << " ";
            std::cout << "\n";
        }
        if(!down.empty()) {
            std::cout << "  Downward (" << dim-1 << "D): ";
            for(auto d : down) std::cout << d << " ";
            std::cout << "\n";
        }

        // --- 4e. 物理组 ---
        std::vector<int> physTags;
        gmsh::model::getPhysicalGroupsForEntity(dim, tag, physTags);
        if(!physTags.empty()) {
            std::cout << "  Physical groups: ";
            for(auto pt : physTags) {
                std::string pn;
                gmsh::model::getPhysicalName(dim, pt, pn);
                std::cout << "\"" << pn << "\"(" << dim << "," << pt << ") ";
            }
            std::cout << "\n";
        }

        // --- 4f. 分区信息 ---
        std::vector<int> parts;
        gmsh::model::getPartitions(dim, tag, parts);
        if(!parts.empty()) {
            std::cout << "  Partitions: ";
            for(auto p : parts) std::cout << p << " ";
            int pDim, pTag;
            gmsh::model::getParent(dim, tag, pDim, pTag);
            std::cout << "-> parent(" << pDim << "," << pTag << ")\n";
        }

        std::cout << "\n";
    }

    // 步骤5:输出全局统计
    std::cout << "============================================\n";
    std::cout << "Summary:\n";
    std::cout << "  Total entities: " << entities.size() << "\n";
    std::cout << "  Total nodes:    " << totalNodes << "\n";
    std::cout << "  Total elements: " << totalElements << "\n";

    // 全局单元类型统计
    std::vector<int> allElemTypes;
    gmsh::model::mesh::getElementTypes(allElemTypes);
    std::cout << "  Element types used: " << allElemTypes.size() << " (";
    for(auto t : allElemTypes) std::cout << t << " ";
    std::cout << ")\n";
    std::cout << "============================================\n";

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

    gmsh::clear();
    gmsh::finalize();
    return 0;
}

编译与运行:

g++ -o ch22_full ch22_full.cpp -lgmsh
./ch22_full                          # 使用自动创建的圆柱体
./ch22_full input.msh                # 加载已有的MSH网格文件
./ch22_full input.msh -nopopup       # 不弹GUI,批处理模式

22.5 关键 API 速查表

22.5.1 模型查询

API 签名 说明
model::getEntities (vectorpair &dimTags, int dim=-1) 获取全部或指定维度实体 (dim,tag) 列表
model::getCurrent (string &name) 获取当前模型名称
model::getDimension () -> int 获取模型最高维度(0-3)
model::getType (int dim, int tag, string &type) 获取实体类型字符串
model::getEntityName (int dim, int tag, string &name) 获取实体名称(可为空)

22.5.2 网格查询

API 签名 说明
mesh::getNodes (vec<size_t> &nodeTags, vec<double> &coord, vec<double> &paramCoord, int dim=-1, int tag=-1, bool includeBoundary=false, bool returnParamCoord=true) 获取节点标签和坐标(交错存储)
mesh::getElements (vec<int> &elemTypes, vec<vec<size_t>> &elemTags, vec<vec<size_t>> &nodeTags, int dim=-1, int tag=-1) 按实体获取所有单元类型、标签和连接性
mesh::getElementTypes (vec<int> &elemTypes, int dim=-1, int tag=-1) 获取某实体上的单元类型列表(不含数据和标签)
mesh::getElementsByType (int elemType, vec<size_t> &elemTags, vec<size_t> &nodeTags, int tag=-1, size_t task=0, size_t numTasks=1) 按类型获取单元标签和展平连接性
mesh::getElementProperties (int elemType, string &name, int &dim, int &order, int &numNodes, vec<double> &localCoord, int &numPrimaryNodes) 查询单元类型属性

22.5.3 拓扑与分组查询

API 签名 说明
model::getAdjacencies (int dim, int tag, vec<int> &upward, vec<int> &downward) 获取上下邻接实体 tag 列表
model::getPhysicalGroupsForEntity (int dim, int tag, vec<int> &physTags) 获取实体所属物理组标签列表
model::getPhysicalName (int dim, int tag, string &name) 获取物理组名称
model::getPartitions (int dim, int tag, vec<int> &partitions) 获取实体所属分区索引列表
model::getParent (int dim, int tag, int &parentDim, int &parentTag) 获取分区实体的原始父实体

22.5.4 数据结构速记

概念 存储方式 索引公式
节点坐标 coords[x0,y0,z0, x1,y1,z1, ...] x_i = coords[3*i], y_i = coords[3*i+1], z_i = coords[3*i+2]
单元连接性(getElements) nodeTags[typeIdx] 为展平一维数组 第 j 个单元节点起始于 j * numNodesPerElem
单元连接性(getElementsByType) nodeTags 为展平一维数组 同上,起始于 j * numNodesPerElem
实体标识 pair<int,int> 或两个独立 int (dim, tag)
参数坐标 paramCoord[u0,v0,w0, u1,v1,w1, ...] numNodes * 3 交错(仅曲面/体有参数坐标)

22.5.5 典型前处理工作流

1. gmsh::initialize()                    // 启动 Gmsh
2. gmsh::open(file) 或 手动建立几何       // 加载/创建模型
3. model::getEntities(entities)           // 获取实体列表
4. 遍历 entities:
    4a. mesh::getNodes(..., dim, tag)     // 提取节点
    4b. mesh::getElements(..., dim, tag)  // 提取单元
    4c. getAdjacencies(dim, tag, ...)     // 查询拓扑
    4d. getPhysicalGroupsForEntity(...)   // 识别边界条件
    4e. getElementProperties(...)         // 理解单元结构
5. 重组为求解器数据格式                    // 构建 CSR/COO 等
6. gmsh::clear(); gmsh::finalize()        // 清理

本章覆盖了 Gmsh C++ API 中最核心的前处理查询接口。通过 getEntities() + getNodes() + getElements() 的三步模式,可以完整提取模型中的所有网格数据。配合 getAdjacencies() 的拓扑查询和 getPhysicalGroupsForEntity() 的物理组识别,能够胜任绝大多数有限元前处理软件的数据准备需求。下一章将介绍如何使用 API 直接修改和操作网格。