GMSH Python API 2D矩形融合失败求助:存在界面及TrimmedCurve问题
解决Gmsh Python API矩形融合不彻底及TrimmedCurve问题
核心问题分析
- 融合后残留界面:原代码几何坐标计算逻辑错误,导致矩形未真正共边,布尔融合无法识别为可合并的相邻实体
- TrimmedCurve生成:布尔运算后残留的修剪曲线,会引发有限元软件导入兼容性问题,需通过几何清理消除
解决方案步骤
1. 修正几何坐标错位问题
原循环内矩形的y坐标计算逻辑冲突,导致实体位置错位无法共边。修改为使用实时更新的y变量定位:
# Build subsequent horizontal and vertical segments x = length y = 0.0 direction = 1 for i in range(1, n_bends): y += direction * (cap_length - width) if i % 2 == 1: # channel odd - 使用实时更新的y坐标 gmsh.model.occ.addRectangle(x=length, y=y, z=0, dx=-length, dy=width) # end cap odd gmsh.model.occ.addRectangle(x=0, y=y, z=0, dx=-width, dy=cap_length) direction *= -1 elif i % 2 == 0: # channel even - 使用实时更新的y坐标 gmsh.model.occ.addRectangle(x=0, y=y, z=0, dx=length, dy=width) # end cap even gmsh.model.occ.addRectangle(x=length, y=y, z=0, dx=width, dy=cap_length) direction *= -1
2. 优化布尔融合与几何清理流程
添加多轮几何清理,采用逐步融合方式确保实体完全合并,消除TrimmedCurve:
# Synchronize to create the area(s) gmsh.model.occ.synchronize() # 第一步:删除重复几何实体,确保共边完全重合 gmsh.model.occ.removeAllDuplicates() gmsh.model.occ.synchronize() # 获取所有曲面实体 surface_dimTags = gmsh.model.getEntities(dim=2) print("初始曲面数量:", len(surface_dimTags)) # 第二步:逐步融合所有曲面,避免批量融合的识别误差 if len(surface_dimTags) > 1: target = surface_dimTags[0] for tag in surface_dimTags[1:]: result = gmsh.model.occ.fuse([target], [tag], removeObject=True, removeTool=True) target = result[0][0] # 更新目标为融合后的曲面 gmsh.model.occ.synchronize() # 第三步:再次清理重复实体,彻底消除TrimmedCurve gmsh.model.occ.removeAllDuplicates() gmsh.model.occ.synchronize() # 确认最终曲面数量 final_surfaces = gmsh.model.getEntities(dim=2) print("最终曲面数量:", len(final_surfaces))
3. 替代方案:直接生成无修剪曲面
若仍存在TrimmedCurve,可跳过布尔运算,直接通过边界线生成曲面:
- 用
addLine创建连续边界曲线 - 通过
addCurveLoop组成闭合环 - 用
addPlaneSurface生成单一曲面
该方法完全避免修剪曲线,兼容性更强。
完整修正代码
import gmsh import sys import os cm = 1e-2 mm = 1e-3 μm = 1e-6 # Initialize Gmsh gmsh.initialize() gmsh.model.add("Serpentine") # for compatibility with Firedrake # gmsh.option.setNumber("Mesh.MshFileVersion", 2.2) # write MSH 2.2 gmsh.option.setNumber("Mesh.Binary", 0) # ASCII gmsh.option.setNumber("Mesh.SaveAll", 0) # only physical groups (fine) gmsh.model.mesh.setOrder(1) # first-order elements # Parameters length = 4.0 * mm # 2.0 cm width = 1.6 * mm height = 1.6 * mm # not used in 2D, kept to minimize diffs inlet_pad = 2 * width cap_length = 3 * width n_bends = 2 # minimum is 2, 1 should also be ok, but doesn't work right now. # Use OpenCASCADE for area creation (2D) # create first channel gmsh.model.occ.addRectangle(x=-inlet_pad, y=0, z=0, dx=length + inlet_pad, dy=width, tag=1) # end cap 1 gmsh.model.occ.addRectangle(x=length, y=0, z=0, dx=width, dy=cap_length) # Build subsequent horizontal and vertical segments x = length y = 0.0 direction = 1 for i in range(1, n_bends): y += direction * (cap_length - width) if i % 2 == 1: # channel odd gmsh.model.occ.addRectangle(x=length, y=y, z=0, dx=-length, dy=width) # end cap odd gmsh.model.occ.addRectangle(x=0, y=y, z=0, dx=-width, dy=cap_length) direction *= -1 elif i % 2 == 0: # channel even gmsh.model.occ.addRectangle(x=0, y=y, z=0, dx=length, dy=width) # end cap even gmsh.model.occ.addRectangle(x=length, y=y, z=0, dx=width, dy=cap_length) direction *= -1 # Synchronize to create the area(s) gmsh.model.occ.synchronize() # 清理重复实体 gmsh.model.occ.removeAllDuplicates() gmsh.model.occ.synchronize() # get surface entity dimTags surface_dimTags = gmsh.model.getEntities(dim=2) print("初始曲面数量:", len(surface_dimTags)) # 逐步融合所有曲面 if len(surface_dimTags) > 1: target = surface_dimTags[0] for tag in surface_dimTags[1:]: result = gmsh.model.occ.fuse([target], [tag], removeObject=True, removeTool=True) target = result[0][0] gmsh.model.occ.synchronize() # 再次清理重复实体,消除TrimmedCurve gmsh.model.occ.removeAllDuplicates() gmsh.model.occ.synchronize() # 确认最终曲面数量 final_surfaces = gmsh.model.getEntities(dim=2) print("最终曲面数量:", len(final_surfaces)) # Define a characteristic length for mesh elements lc = 2.0 * cm / 100 # Set the mesh size for all 0D entities (points) gmsh.model.mesh.setSize(dimTags=gmsh.model.getEntities(0), size=lc) gmsh.option.setNumber("Mesh.CharacteristicLengthMin", lc / 2.0) gmsh.option.setNumber("Mesh.CharacteristicLengthMax", lc) gmsh.option.setNumber("Mesh.MeshSizeFromCurvature", 100) # Generate mesh (2D) gmsh.model.mesh.generate(dim=2) # Optionally save the mesh meshes_dir = "meshes" os.makedirs(meshes_dir, exist_ok=True) mesh_filename = os.path.join(meshes_dir, "Serpentine_2D.msh") gmsh.write(mesh_filename) # save .vtk file for easy visualization gmsh.write(mesh_filename.replace(".msh", ".vtk")) # Launch GUI (optional) if 'close' not in sys.argv: gmsh.fltk.run() # Finalize gmsh.finalize()
内容的提问来源于stack exchange,提问作者Nick Brady
相关产品推荐
相关产品推荐

