
简介面向使用 Peridigm 开展无网格/近场动力学仿真、需要把 Gmsh 网格转为 Exodus II 格式的研究者与工程师提供一套可直接运行的 Python 转换脚本与配套示例。包内共 25 个文件约 861KB以 Python 脚本为核心辅以 msh 网格样例、png 效果截图、geo 几何文件及 README、INSTALL、requirements 等说明文档另含 license 与配置文件便于快速理解用法与验证结果。资源已有 565 人学习说明在相关仿真流程中有一定参考价值。读者可获得 convert.py 转换入口、mesh.py 等模块化代码、二维三角形与四边形单元测试用例以及 Gmsh 与 Exodus II 对照截图帮助理解元素类型支持范围与 VTK 依赖配置并借助示例网格完成从建模到 Peridigm 前处理的衔接减少格式转换环节的试错成本。1. 从 gmsh 到 Exodus II一份能直接跑通 Peridigm 的网格转换资源手里有一份用 gmsh 画好的四面体网格想丢进 Peridigm 做近场动力学计算结果第一步就卡住——Peridigm 只认 Exodus IIgmsh 默认吐出来的是.msh。这个转换环节看着不起眼实际是整条仿真链路上最容易翻车的地方节点编号对不上、单元类型映射错、边界节点集丢失随便一个都能让你在求解器里看到一堆莫名其妙的报错。这份 gmsh-exodus-converter 资源就是冲着这个痛点来的它把 gmsh 的网格数据读进来重新组织成 Exodus II 的块结构、节点集和边集输出一个 Peridigm 能直接吃的文件。适合谁已经在用 gmsh 做前处理、准备上 Peridigm 跑近场动力学算例的从业者以及需要把 gmsh 网格导进 ParaView 做后处理、但不想手动折腾格式的工程师。Python 写的改起来不费劲参数和映射逻辑都摆在明面上。2. 转换链路拆解gmsh 的网格模型和 Exodus II 差在哪2.1 两种格式的数据组织方式gmsh 的.msh文件本质是一个扁平的标签系统节点坐标一张表单元连接关系一张表物理组physical group用标签挂上去。它不关心你这些单元属于哪个“块”也不强制你给边界节点单独建集。Exodus II 完全是另一套思路——它要求网格按块block组织每个块里单元类型一致节点集nodeset和边集sideset是独立实体Peridigm 读的时候就是按块遍历、按节点集施加边界条件。所以转换的核心不是“改个后缀”而是把 gmsh 的扁平标签重新映射成 Exodus II 的层次结构。常见做法是读 gmsh 的物理组一个物理组对应一个 Exodus 块边界物理组转成节点集如果原模型有面载荷还得把面单元转成边集。这一步映射关系定错了后面全白搭。2.2 为什么不用 gmsh 自带的导出gmsh 本身能导.exo但它的导出逻辑是“有什么写什么”块划分完全跟着单元类型走不认你的物理组语义。Peridigm 那边期望的是按材料区或按部件分块gmsh 导出来的块结构往往对不上节点集也经常丢。另一个坑是单元类型编号gmsh 的四面体是 4 号Exodus II 里对应的是TETRA4中间这层映射如果靠手写很容易把楔形单元和金字塔单元搞混。这份转换脚本把映射表显式写出来了改的时候一眼能看到对应关系比在黑盒导出器里猜要踏实得多。2.3 环境准备和依赖脚本依赖gmsh的 Python API 和netCDF4Exodus II 底层是 NetCDF。装的时候注意版本gmsh 的 Python 包和系统里装的 gmsh 可执行文件版本最好一致不然读网格时偶发段错误。我一般用虚拟环境隔离python -m venv venv-gmsh-exo source venv-gmsh-exo/bin/activate pip install gmsh netCDF4 numpynetCDF4在部分系统上需要先装libnetcdf-dev和hdf5的开发库编译不过就先补系统依赖。装完跑一句python -c import gmsh, netCDF4确认没报错再往下走。3. 动手转换从读网格到写出 Exodus II 的完整步骤3.1 读取 gmsh 网格并提取物理组第一步是把.msh读进来拿到节点坐标、单元连接和物理组标签。脚本里通常这么起手import gmsh import numpy as np gmsh.initialize() gmsh.open(model.msh) # 拿所有节点坐标按 tag 排序保证索引一致 node_tags, coord, _ gmsh.model.mesh.getNodes() coord coord.reshape(-1, 3) order np.argsort(node_tags) node_tags node_tags[order] coord coord[order] # 建立 tag 到连续索引的映射Exodus 要求从 1 开始连续编号 tag_to_idx {int(t): i 1 for i, t in enumerate(node_tags)} # 遍历物理组区分体组和面组 entities gmsh.model.getEntities() for dim, tag in entities: phys gmsh.model.getPhysicalGroupsForEntity(dim, tag) # dim3 的物理组对应体块dim2 的对应边界集这里的关键是tag_to_idx这层映射。gmsh 的节点 tag 不保证连续中间可能有空洞而 Exodus II 的节点编号必须从 1 开始连续。直接拿原 tag 写进去Peridigm 读的时候会报节点越界。np.argsort那一步是为了让坐标数组和 tag 数组顺序对齐不然后面按索引取坐标会错位。3.2 单元类型映射表gmsh 的单元类型编号和 Exodus II 的块类型名不是一一对应的脚本里需要一张显式映射表。常见的几种gmsh 类型号gmsh 名称Exodus II 块类型节点数4四面体TETRA445六面体HEX886楔形WEDGE663四边形QUAD442三角形TRI33写的时候按块遍历每个块只放一种单元类型。如果同一个物理组里混了四面体和楔形得拆成两个块Exodus II 不允许一个块里单元类型不一致。这一步是新手最容易忽略的——gmsh 里一个物理组可以随便混Exodus 里不行。3.3 写出 Exodus II 文件写文件用netCDF4直接操作或者用现成的 Exodus 写库。核心是建维度、写变量、填数据from netCDF4 import Dataset with Dataset(model.exo, w, formatNETCDF4) as nc: nc.createDimension(num_nodes, len(node_tags)) nc.createDimension(num_elem, total_elem) nc.createDimension(num_dim, 3) nc.createDimension(num_node_sets, len(nodesets)) nc.createDimension(num_side_sets, len(sidesets)) # 坐标变量Exodus 约定变量名 coordx/coordy/coordz for i, name in enumerate([coordx, coordy, coordz]): v nc.createVariable(name, f8, (num_nodes,)) v[:] coord[:, i] # 每个块单独写 connect 变量命名 connect1/connect2... for bidx, (etype, conn) in enumerate(blocks.items(), start1): v nc.createVariable(fconnect{bidx}, i4, (num_elem, num_nod_per_el)) v[:] connconnect变量里的节点编号必须是前面tag_to_idx映射后的连续索引不能直接塞 gmsh 原 tag。写完之后用ncdump -h model.exo看一眼维度对不对再丢进 ParaView 里加载能正常显示网格、块颜色区分清楚基本就说明结构没问题了。3.4 用 ParaView 做一次可视化验证转换完别急着上 Peridigm先在 ParaView 里过一遍。打开.exo文件检查三件事网格几何和 gmsh 里看到的是否一致、块的数量和物理组数量是否对得上、节点集能不能单独选中高亮。ParaView 读 Exodus II 是按块组织的如果块名显示成默认的block_1、block_2而不是你预期的材料区名说明块命名那一步没写对。这一步花五分钟能省掉后面在求解器里排查半小时的功夫。4. 避坑排查转换过程中最常见的五个翻车点4.1 节点编号不连续导致求解器报越界现象Peridigm 启动即报节点索引超出范围或者 ParaView 里网格显示成一团乱线。原因直接把 gmsh 的原始节点 tag 写进了connect变量而 tag 中间有空洞。解决写文件前强制做一次tag_to_idx重映射所有连接关系里的节点号都过一遍映射表确保输出编号从 1 到 N 连续。4.2 单元类型混装导致块读取失败现象Exodus 文件能打开但某个块里的单元显示不全或者 Peridigm 读块时直接跳过。原因一个物理组里混了四面体和楔形写的时候塞进了同一个connect变量。解决按单元类型号分组每种类型单独建块块内单元类型必须一致。gmsh 里画网格时尽量让一个物理组只含一种单元类型从源头避免。4.3 边界节点集丢失现象Peridigm 里施加边界条件时找不到对应的节点集或者节点集是空的。原因gmsh 的边界物理组是面组dim2转换时只处理了体组面组没转成 Exodus 的 nodeset。解决遍历物理组时把 dim2 的组单独拎出来提取其包含的节点 tag去重后写成node_ns1之类的节点集变量。注意面组里的节点要去重一个节点可能属于多个面。4.4 坐标单位不一致现象网格在 ParaView 里尺寸明显不对或者 Peridigm 算出来的结果量级离谱。原因gmsh 建模时用的单位比如毫米和 Peridigm 期望的单位比如米没统一转换脚本原样搬运坐标。解决在读取坐标后加一步单位换算或者在 gmsh 建模阶段就统一到国际单位制。这个坑不报错但结果全错属于最阴的一类。4.5 netCDF4 版本不匹配导致写文件失败现象脚本跑到写文件那一步抛NetCDF: HDF error或者变量创建失败。原因netCDF4库和底层 HDF5 版本不兼容或者文件格式参数没指定。解决Dataset创建时显式指定formatNETCDF4装库时用pip而不是系统包管理器混装虚拟环境里保持netCDF4和h5py版本匹配。实在搞不定就降一档用NETCDF3_64BIT_OFFSET格式Exodus II 也认。5. 进阶技巧把转换脚本改成可复用的命令行工具脚本跑通一次之后下一步是把它变成能反复用的工具而不是每次改路径、改文件名。我一般用argparse包一层import argparse parser argparse.ArgumentParser(descriptiongmsh to Exodus II converter) parser.add_argument(input, helpinput .msh file) parser.add_argument(-o, --output, defaultout.exo, helpoutput .exo file) parser.add_argument(--scale, typefloat, default1.0, helpcoordinate scale factor) args parser.parse_args() # 读取后统一乘 scale解决单位问题 coord coord * args.scale--scale这个参数看着简单实际很救命——同一个模型在不同算例里单位制不一样加个缩放因子就不用改代码。再进一步把块命名映射也做成配置用一个 JSON 文件描述“物理组名 → 块名”的对应关系脚本读配置来命名块这样换项目时只改配置不改代码。验证转换结果是否可靠我习惯做一个“往返检查”把生成的.exo用 ParaView 导出成.vtk再和原始.msh在 ParaView 里并排对比节点数、单元数、包围盒尺寸三项对得上基本就能放心往求解器里送。另外Peridigm 的示例算例里通常带一个已知能跑的 Exodus 文件拿它的维度结构做参照对比自己生成文件的ncdump -h输出块数、节点集数、变量命名逐项核对比盲猜快得多。从那以后我每次做格式转换都强制先跑一遍“小模型冒烟测试”——拿一个只有几十个单元的简化模型走完整条链路确认求解器能读、能算一步再上真实规模。这个习惯帮我挡掉了好几次因为映射表写错导致的批量返工。希望帮到你。本文还有配套的精品资源点击获取