AMCAX Kernel
Geometry kernel for CAD/CAE/CAM
AMCAX Kernel 1.0.0.0
Loading...
Searching...
No Matches
Mesh Generation Example

Overview

This tutorial outlines the basic usage of mesh generation. It involves the process of importing STEP format files and automatic generation of the volumetric mesh, which is controlled by parameters specified by a JSON file.

Preview of CAD Model and the generated mesh

The left image shows the imported CAD model, while the right image displays the final generated mesh model.

Namespaces

using namespace AMCAX::NextMesh;
Namespace of all interface in the AMCAX NextMesh module.
Definition misc.docu:42

Preparation

Set the log format, provide the cad file and the mesh generation control JSON file.

const std::string cadstr = "./data/qiuwotaojian.stp";
const std::string jsonPath = "./data/mesh_para-mesh000.json";
static AMCAX_API void InitLogger(const std::string &logFileName="", const std::string &logPattern="[%Y-%m-%dT%X%z] [%l] %v", const int64_t logFileSize=20 *1024 *1024, const int maxLogFiles=100)
set the logger. the logger is closed by default, if this function is not called

Json example

Control mesh generation by setting the following partitioning parameters: the dimension of the entity to be partitioned, MeshingDim; the maximum and minimum size of the mesh elements, MaxSize/MinSize (absolute size), which can be the bounding box diagonal length bblen of the geometric model multiplied by a certain ratio r, such as [0.01, 0.1]*bblen; the mesh growth rate, GrowthRate; the sequence of tags of the entities to be partitioned, SelectedEntities; the curvature factor, CurvatureFactor; the type of mesh elements, ElementType; the mesh partitioning method, MeshingMethod; and the number of parallel threads, ThreadNum.

{
"MeshSize": [
{
"CurvatureFactor": 0.6,
"GrowthRate": 1.0,
"MaxSize": 0.5,
"MeshingDim": 3,
"MinSize": 0.1,
"ElementType": "Tri",
"MeshingMethod": "D2AFT",
"SelectedEntities": []
}
],
"ThreadNum": 1
}

JSON example - Planar boundary layer

This example generates a planar boundary layer hybrid mesh for a two-dimensional airfoil.

{
"BoundaryLayer": [
{
"DistributionType": "Separation",
"EntityType": "Edge",
"EFPairs": [
{
"E": 5,
"F": 1
},
{
"E": 6,
"F": 1
}
],
"Basic": {
"GrowthRate": {
"Constant": 1.2
},
"InitLayerHeight": {
"Absolute": 0.01
},
"NLayers": 20,
"ProblematicAreasTreatment": "STOP"
}
}
],
"MeshSize": [
{
"CurvatureFactor": 0.2,
"GrowthRate": 1.1,
"MaxSize": 0.2,
"MeshingDim": 1,
"MinSize": 0.1,
"SelectedEntities": [ 5, 6 ]
},
{
"CurvatureFactor": 0.2,
"GrowthRate": 1.0,
"MaxSize": 2,
"MeshingDim": 2,
"MinSize": 1,
"SelectedEntities": []
}
],
"ThreadNum": 1
}
Class Key Required Value Range Default Value Remarks
MeshSize CurvatureFactore No [0, 1.0] 0 0 means off; 1.0 means partitioning a full circle into 3 segments
MeshSize GrowthRate No [1.0, inf] 1.0
MeshSize MaxSize No [eps, inf] inf Absolute size
MeshSize MinSize [0, inf] 0 Absolute size,MinSize<=MaxSize
MeshSize MeshingDim Yes [1,2,3] ——
MeshSize SelectedEntities Yes Subset of entity tags under MeshingDim dimension —— Empty value means all entities under the specified dimension
MeshSize ElementType No [Tri, Quad, Mixed, RTri] Tri Only valid when MeshingDim=2, otherwise ignored; Tri for triangles; Quad for all quadrilaterals; RTri for right-angled triangles; Mixed for mixed triangle and quadrilateral meshes
MeshSize MeshingMethod No [Transfinite,D2Delaunay,D2AFT] Default "D2AFT" when ElementType="Tri" Only valid when MeshingDim=2, otherwise ignored; Transfinite method generates structured grids, only effective for faces with 2/3/4 edges; D2Delaunay generates triangles using Delaunay method; D2AFT generates triangles using advancing front method

The following are the imported CAD model and the final generated mesh model.

For more complex configurations, please refer to 2D Boundary Layer Detailed JSON Example

JSON Example - Spatial boundary layer

This example generates a spatial boundary layer hybrid mesh for a three-dimensional airfoil.

{
"Distribution": [],
"BoundaryLayer": [
{
"DistributionType": "Separation",
"EntityType": "Edge",
"EFPairs":
[
{
"E": 2,
"F": 7
},
{
"E": 17,
"F": 7
}
],
"Basic":
{
"GrowthRate":
{
"Constant": 1.2
},
"InitLayerHeight":
{
"Absolute": 0.002
},
"NLayers": 20,
"ProblematicAreasTreatment": "STOP"
}
},
{
"GrowthRate": 1.2,
"InitLayerHeight": 0.002,
"NLayers": 20,
"DistributionType": "Separation",
"SelectedEntities": [ 1, 8, 9 ],
"EntityType": "Face"
}
],
"MeshSize": [
{
"CurvatureFactor": 0.2,
"GrowthRate": 1.3,
"MaxSize": 0.2,
"MeshingDim": 1,
"MinSize": 0.1,
"SelectedEntities": [ 1, 2, 3, 4, 17, 18 ]
},
{
"CurvatureFactor": 0.2,
"GrowthRate": 1.1,
"MaxSize": 5,
"MeshingDim": 2,
"MinSize": 1,
"SelectedEntities": [ 2, 3, 4, 5, 6, 7 ]
},
{
"CurvatureFactor": 0.2,
"GrowthRate": 1.1,
"MaxSize": 5,
"MeshingDim": 2,
"MinSize": 0.1,
"SelectedEntities": [ 1, 8, 9 ]
},
{
"CurvatureFactor": 0.2,
"GrowthRate": 1.1,
"MaxSize": 5,
"MeshingDim": 3,
"MinSize": 1,
"SelectedEntities": []
}
],
"ThreadNum": 1
}

The following are the imported CAD model and the final generated mesh model, along with the section view.

JSON example - Sweep mesh

Sweep meshing only supports a single sweep body, the source surface may consist of multiple faces, while the target surface can only include a single face. The side faces must be either 2-sided, 3-sided, or 4-sided faces.

{
"Sweep": [
{
"EntityType": "Face",
"Domain": 1,
"Source": [9],
"Target": [10]
}
],
"MeshSize": [
{
"CurvatureFactor": 0.2,
"GrowthRate": 1.0,
"MaxSize": 1,
"MeshingDim": 3,
"MinSize": 0.1,
"SelectedEntities": []
}
],
"ThreadNum": 1
}

The following are the imported CAD model and the generated mesh model.

JSON Example - Copy mesh

The mesh of one or multiple entities (edges or faces) can be copied onto a single target entity. This is applicable in scenarios where the mesh topology of the source and target must be completely consistent, such as in periodic meshes.Important Notes:The source can include multiple entities, but the target must consist of only a single entity;The topological structure of the source and target must be entirely consistent;When copying face meshes, if the source face and target face have consistent topology, it is not necessary to specify the boundary correspondence "EdgeCorrespondence";If multiple boundary edges correspond to a single boundary edge, the correspondence of the boundary edges must be correctly specified.

{
"Copy": [
{
"EntityType": "Face",
"Source": [ 43 ],
"Target": [ 47 ]
}
],
"MeshSize": [
{
"CurvatureFactor": 0,
"GrowthRate": 1.0,
"MaxSize": 3,
"MeshingDim": 2,
"MinSize": 1,
"SelectedEntities": [ 43, 47 ]
}
],
"ThreadNum": 1
}

Using "Entity" as a face, the following are the imported CAD model and the copied mesh.

JSON Example - Multiple line mesh generation methods

Method 1: Specify the number of elements on an edge;

Method 2: Explicitly specify the length ratio of each segment of elements on the edge;

Method 3: Partition based on a pre-defined function (Linear/Geometric);

{
"Distribution": [
{
"EntityType": "Edge",
"SelectedEntities": [ 1 ],
"DistributionType": "NumberOfElements",
"NElement": 20
},
{
"EntityType": "Edge",
"SelectedEntities": [ 2 ],
"DistributionType": "Explicit",
"Orientation": "Forward",
"DistributionPara": [ 0.1, 0.3, 0.6, 0.8 ]
},
{
"EntityType": "Edge",
"SelectedEntities": [ 3 ],
"DistributionType": "Linear",
"Orientation": "Forward",
"Symmetric": true,
"NElement": 9,
"EndBeginElementRatio": 5
},
{
"EntityType": "Edge",
"SelectedEntities": [ 4 ],
"DistributionType": "Geometric",
"Orientation": "Forward",
"Symmetric": false,
"NElement": 9,
"EndBeginElementRatio": 5
}
],
"MeshSize": [
{
"CurvatureFactor": 1,
"GrowthRate": 1.0,
"MaxSize": 5,
"MeshingDim": 2,
"MinSize": 0.1,
"SelectedEntities": [1]
}
],
"ThreadNum": 1
}


Class Key Required Value Range Default Value Notes
Distribution EntityType Yes Edge
Distribution SelectedEntities Yes Can be empty Edge tags
Distribution DistributionType Yes NumberOfElements, Explicit, Linear, Geometric Distribution type
Distribution Orientation No Forward, Reverse Forward Orientation
Distribution Symmetric No true, false false Symmetric distribution
Distribution NElement Yes >=1 Number of segments
Distribution EndBeginElementRatio Yes >0 Ratio of the length of the last segment to the first segment
Distribution DistributionPara Yes (0.0, 1.0) Strictly increasing sequence

The following are the results of various line mesh mesh generation methods.

JSON Example - High-Order Mesh

Supports the generation of second-order high-order meshes and exports files in VTK or Gmsh format.

{
"MeshSize": [
{
"CurvatureFactor": 0.2,
"GrowthRate": 1.0,
"MaxSize": 5.0,
"MeshingDim": 3,
"MinSize": 2.0,
"SelectedEntities": []
}
],
"ElementOrder": {
"Order": 2
},
"ThreadNum": 1
}

Below is an example of a high-order mesh.

Build the model

Import the cad file and build the model.

NMAPIModel nmapi;
nmapi.ImportModel(cadstr);
Class of model in NextMesh.
Definition NMAPIModel.hpp:22
AMCAX_API void ImportModel(const std::string &filePath, const bool replace=true)
Load a cad file, only support step currently. Note: this import method does not specify any entity ta...

Generate/get mesh

generate mesh by importing mesh generation control parameter via JSON file.

nlohmann::json paraJ = nlohmann::json::parse(std::ifstream(jsonPath));
nmapi.GenerateMesh(paraJ.dump());
auto meshapi = nmapi.GetMesh();
AMCAX_API void GenerateMesh(const std::string &configJson)
Generates the mesh for the current model based on provided configuration parameters.
AMCAX_API NMMesh GetMesh()
Get the mesh handle. Note one model only holds a unique mesh.

Get mesh and geometry information

Get the model's entity list, the BRep (boundary representation) relationships of entities, and their boundingboxes. For each entity, obtain the types of meshes it contains, the mesh elements, vertices, and the global IDs of the mesh elements and vertices, along with other related information.

for (DimType dim : {DimType::D0, DimType::D1, DimType::D2, DimType::D3})
{
std::vector<NMEntity> etVec;
// get all entities in the dim-dimensional space.
nmapi.GetEntities(etVec, dim);
for (auto ent : etVec)
{
auto eTag = nmapi.EntityGetTag(ent);
auto dim = nmapi.EntityGetDim(ent);
// get the sequence of dim+1-dimensional entities containing the specified Entity.
std::vector<NMEntity> parentVec;
nmapi.GetParentAdjacentEntities(parentVec, ent);
// get the sequence of dim-1-dimensional entities contained in the specified Entity.
std::vector<NMEntity> childVec;
std::vector<Orientation> ories;
nmapi.GetChildAdjacentEntities(childVec, ories, ent);
// traverse the Element contained in the specified Entity.
auto entElemNum = meshapi.EntityGetElementCount(ent);
for (size_t i = 0; i < entElemNum; i++)
{
auto elem = meshapi.EntityGetElementByIndex(ent, i);
}
// traverse the Node contained in the specified Entity.
auto entNodeNum = meshapi.EntityGetNodeCount(ent);
for (size_t i = 0; i < entNodeNum; i++)
{
auto node = meshapi.EntityGetNodeByIndex(ent, i);
}
}
}
NMPoint3 pmin, pmax;
// get the boundingbox of the entire model.
nmapi.GetBBox(pmin, pmax);
// traverse all Element in the Mesh.
auto elemTotalNum = meshapi.GetElementCount();
for (size_t i = 0; i < elemTotalNum; i++)
{
// get the i-th Element.
auto elem = meshapi.GetElementByIndex(i);
// get the global ID, element type, and the number of Node in the Element.
auto elemId = meshapi.ElementGetID(elem);
auto elemType = meshapi.ElementGetType(elem);
auto nodeCount = meshapi.ElementGetNodeCount(elem);
// traverse all Node on the specified Element.
for (size_t in = 0; in < nodeCount; in++)
{
// get the i-th node on the Element.
auto node = meshapi.ElementGetNode(elem, in);
// get the node's global ID, associated Entity, spatial location, and parameters.
auto nodeId = meshapi.NodeGetID(node);
auto nodeEnt = meshapi.NodeGetEntity(node);
auto nodePos = meshapi.NodeGetPosition(node);
// valid only for Node on edges and faces.
if (nmapi.EntityGetDim(nodeEnt) == DimType::D1 ||
nmapi.EntityGetDim(nodeEnt) == DimType::D2)
double u = meshapi.NodeGetFirstParameter(node);
// valid only for Node on faces.
if (nmapi.EntityGetDim(nodeEnt) == DimType::D2)
double v = meshapi.NodeGetSecondParameter(node);
}
}
// traverse all Node in the entire Mesh.
auto nodeTotalNum = meshapi.GetNodeCount();
for (size_t i = 0; i < nodeTotalNum; i++)
{
auto node = meshapi.GetNodeByIndex(i);
}
AMCAX_API void GetEntities(std::vector< NMEntity > &ents, const DimType dim)
get all the entities in the specified dim
AMCAX_API EntTag EntityGetTag(const NMEntity &ent)
get the tag of the given entity
AMCAX_API DimType EntityGetDim(const NMEntity &ent)
get the dimension of the given entity
AMCAX_API void GetChildAdjacentEntities(std::vector< NMEntity > &children, std::vector< Orientation > &oris, const NMEntity &ent)
get all the entities in dim-1 contained by the entity
AMCAX_API void GetParentAdjacentEntities(std::vector< NMEntity > &parents, const NMEntity &ent)
get all the entities in dim+1 that contain the entity
AMCAX_API void GetBBox(NMPoint3 &pmin, NMPoint3 &pmax, const NMEntity &ent=nullptr)
get the boundingbox of the entity. when ent = nullptr, return the model bbox
AMCAX::Coord3d NMPoint3
Type of point/vector.
Definition Macros.hpp:25
DimType
Type of dimension.
Definition Macros.hpp:58

Set the face groups

Add, delete, modify, and query of the face groups.

nmapi.CreatePhysicalSet(DimType::D2, { 1, 2 }, "inlet");
nmapi.CreatePhysicalSet(DimType::D2, { 3, 4 }, "outlet");
nmapi.CreatePhysicalSet(DimType::D2, { 5 }, "symmetry");
std::vector<EntTag> entTags;
nmapi.GetEntitiesInPhysicalSet(entTags, DimType::D2, "outlet");
std::set<std::string> pNames;
nmapi.GetPhysicalSets(pNames, DimType::D2);
AMCAX_API void GetEntitiesInPhysicalSet(std::vector< EntTag > &entTags, const DimType dim, const std::string &pName)
get entities in the specified physical set
AMCAX_API void GetPhysicalSets(std::set< std::string > &pNames, const DimType dim)
get all the physical sets in the specified dim
AMCAX_API void CreatePhysicalSet(const DimType dim, const std::vector< EntTag > &entTags, const std::string &pName)
create a new physical set for the specified entities with specified dimension

Output mesh files

Output mesh files in user-specified formats, such as OBJ/VTK/Fluent MSH/Gmsh MSH.

meshapi.Write("result.vtk", OutFileType::VTK);
meshapi.Write("result.obj", OutFileType::OBJ);
meshapi.Write("result.msh", OutFileType::FLUENT_MSH);
meshapi.WriteGmsh4("result.msh", false, true);

Click here example01 to get the full source code of the mesh partitioning example. Everyone can download it as needed.

Appendix

The complete code for this example is listed below:

#include <fstream>
#include <nlohmann/json.hpp>
#include <set>
using namespace AMCAX::NextMesh;
void GenMesh()
{
// the cad file
const std::string cadstr = "./data/qiuwotaojian.stp";
// the json file containing mesh generation control parameters
const std::string jsonPath = "./data/mesh_para-mesh000.json";
// set the log format
// import the cad file and create a new NMAPIModel object
NMAPIModel nmapi;
nmapi.ImportModel(cadstr);
nlohmann::json paraJ = nlohmann::json::parse(std::ifstream(jsonPath));
// mesh generation controlled by the parameters in the json
nmapi.GenerateMesh(paraJ.dump());
// get the generated mesh
auto meshapi = nmapi.GetMesh();
for (DimType dim : {DimType::D0, DimType::D1, DimType::D2, DimType::D3})
{
std::vector<NMEntity> etVec;
// get all entities in the dim-dimensional space.
nmapi.GetEntities(etVec, dim);
for (auto ent : etVec)
{
auto eTag = nmapi.EntityGetTag(ent);
auto dim = nmapi.EntityGetDim(ent);
// get the sequence of dim+1-dimensional entities containing the specified Entity.
std::vector<NMEntity> parentVec;
nmapi.GetParentAdjacentEntities(parentVec, ent);
// get the sequence of dim-1-dimensional entities contained in the specified Entity.
std::vector<NMEntity> childVec;
std::vector<Orientation> ories;
nmapi.GetChildAdjacentEntities(childVec, ories, ent);
// traverse the Element contained in the specified Entity.
auto entElemNum = meshapi.EntityGetElementCount(ent);
for (size_t i = 0; i < entElemNum; i++)
{
auto elem = meshapi.EntityGetElementByIndex(ent, i);
}
// traverse the Node contained in the specified Entity.
auto entNodeNum = meshapi.EntityGetNodeCount(ent);
for (size_t i = 0; i < entNodeNum; i++)
{
auto node = meshapi.EntityGetNodeByIndex(ent, i);
}
}
}
NMPoint3 pmin, pmax;
// get the boundingbox of the entire model.
nmapi.GetBBox(pmin, pmax);
// traverse all Element in the Mesh.
auto elemTotalNum = meshapi.GetElementCount();
for (size_t i = 0; i < elemTotalNum; i++)
{
// get the i-th Element.
auto elem = meshapi.GetElementByIndex(i);
// get the global ID, element type, and the number of Node in the Element.
auto elemId = meshapi.ElementGetID(elem);
auto elemType = meshapi.ElementGetType(elem);
auto nodeCount = meshapi.ElementGetNodeCount(elem);
// traverse all Node on the specified Element.
for (size_t in = 0; in < nodeCount; in++)
{
// get the i-th node on the Element.
auto node = meshapi.ElementGetNode(elem, in);
// get the node's global ID, associated Entity, spatial location, and parameters.
auto nodeId = meshapi.NodeGetID(node);
auto nodeEnt = meshapi.NodeGetEntity(node);
auto nodePos = meshapi.NodeGetPosition(node);
// valid only for Node on edges and faces.
if (nmapi.EntityGetDim(nodeEnt) == DimType::D1 ||
nmapi.EntityGetDim(nodeEnt) == DimType::D2)
double u = meshapi.NodeGetFirstParameter(node);
// valid only for Node on faces.
if (nmapi.EntityGetDim(nodeEnt) == DimType::D2)
double v = meshapi.NodeGetSecondParameter(node);
}
}
// traverse all Node in the entire Mesh.
auto nodeTotalNum = meshapi.GetNodeCount();
for (size_t i = 0; i < nodeTotalNum; i++)
{
auto node = meshapi.GetNodeByIndex(i);
}
// Set the face groups
nmapi.CreatePhysicalSet(DimType::D2, { 1, 2 }, "inlet");
nmapi.CreatePhysicalSet(DimType::D2, { 3, 4 }, "outlet");
nmapi.CreatePhysicalSet(DimType::D2, { 5 }, "symmetry");
std::vector<EntTag> entTags;
nmapi.GetEntitiesInPhysicalSet(entTags, DimType::D2, "outlet");
std::set<std::string> pNames;
nmapi.GetPhysicalSets(pNames, DimType::D2);
// Export the mesh file
meshapi.Write("result.vtk", OutFileType::VTK);
meshapi.Write("result.obj", OutFileType::OBJ);
meshapi.Write("result.msh", OutFileType::FLUENT_MSH);
meshapi.WriteGmsh4("result.msh", false, true);
}
Class of NextMesh Model.