Skip to content

CAD to 2D mesh

Matthew Hockley edited this page Oct 26, 2020 · 14 revisions

Once a design has been created in a CAD package, it should be exported as "STEP" file. From experimenting, "STEP" files appear to have a higher success rate compared to "STL" files. This is likely due to how "STL" files differ from "STEP" files. GMSH is recommended for the 2D import due to the physical labelling of lines, surfaces and volumes. For 2D meshes, the "MSH" mesh file needs to define lines and surfaces. Other packages such as Netgen only physically label surfaces and volumes.

GMSH STEP to MSH mesh generation

Once exported as an "STEP", the file should be imported into GMSH. This guide was made based upon GMSH version 4.6.0. Once in GMSH, physical labels need to be assigned to all lines and one to the bottom Z axis surface. Often it helps to save the physical labels to a ".geo" file which is an automated script for importing and setting up files in GMSH. For 2D meshes, all curves on the X-Y plane (Z = 0) and the X-Y plane surface must be labelled. Volume is not required to be labelled in 2D models. For 3D meshes, all surfaces and the volume inside the mesh must be labelled. Curves do not need to be labelled in 3D models.

GMSH Physical Labels

Merge "Spiral2D.stp";
Physical Surface("9") = {4};
//+
Physical Curve("16") = {16};
//+
Physical Curve("15") = {15};
//+
Physical Curve("14") = {14};
//+
Physical Curve("13") = {13};
//+
Physical Curve("12") = {12};
//+
Physical Curve("11") = {11};
//+
Physical Curve("2") = {2};
//+
Physical Curve("8") = {8};
//+
Physical Curve("9") = {9};

To define the mesh density, go to Tools > Options which opens a "Options" panel and select "Mesh" from the left hand side. Select the "General" tab and min/max element size can be set. The element size is relative to the mesh size. For example, if the mesh is in millimetres, 0.01 will be 0.01 millimetres.

The mesh should be created by selecting 2D or 3D from the left hand menu, for example Modules > Mesh > 2D. Once generated, the mesh can be exported by File > Export menu and choosing "Mesh - Gmsh MSH - (*.msh)" format from the file type drop down menu and saved with an appropriate name. The MSH file format should be "Version 4 ASCII" but "Version 2 ASCII" should work due to the wide support within Meshio.

Meshio "MSH" to 2D "XDMF" conversion

Once GMSH has generated a "MSH", the file needs to be converted to "XDMF" for FEniCS import using Meshio. "XDMF" is used due to the performance comparison compared to other mesh file formats (see Meshio performance comparison table below).

Comparison of mesh file types from Meshio

For 2D conversion, there is a importScript2D.py available. The file will automated the conversion from "MSH" to "XDMF". The script uses Meshio to remove the 3D aspects of the "MSH" by removing all Z axis points exceeding 0. Therefore, it is essential models are orientated on the X-Y plane with the extrusion into the Z axis.

The first line of the code imports the "MSH" file we created in either GMSH or Netgen. In this example, the filename was Spiral2D.msh.

msh = meshio.read("Spiral2D.msh")

The "triangle" cells signifies the 2D X-Y plane surface. The file is labelled mesh_Spiral2D.xdmf.

meshio.write("mesh_Spiral2D.xdmf", meshio.Mesh(points=msh.points[:,:2], cells={"triangle": msh.cells["triangle"]}))

The next part of the code extracts the physical line labels important for defining the subdomains boundaries. The "line" cells signifies 2D boundaries. The file is labelled "mf_Spiral2D.xdmf".

meshio.write("mf_Spiral2D.xdmf", meshio.Mesh(points=msh.points, cells={"line": msh.cells["line"]}, cell_data={"line": {"name_to_read": msh.cell_data["line"]["gmsh:physical"]}}))

The final, optional part tests the physical labelling. The code uses the dolfin package, from dolfin import *, to import the "XDMF" file mesh and subdomains. Through importing both meshes, It_facet = SubsetIterator(mf,10) can be used to find all physical labels which are labelled "10".

from dolfin import *
mesh = Mesh()
with XDMFFile("mesh_Spiral2D.xdmf") as infile:
    infile.read(mesh)
mvc = MeshValueCollection("size_t", mesh, 2)
with XDMFFile("mf_Spiral2D.xdmf") as infile:
    infile.read(mvc, "name_to_read")
mf = cpp.mesh.MeshFunctionSizet(mesh, mvc)
It_facet = SubsetIterator(mf,10)