概述
本教程提供了使用网格剖分的基本用法,导入step格式文件,通过json文件传入网格剖分控制参数,自动生成体网格。
CAD模型和生成网格预览
左图为导入的CAD模型,右图为最终生成的网格模型。
命名空间
AMCAX NextMesh 模块提供的所有接口所在的命名空间。
定义 misc.docu:42
准备工作
设置log格式,提供cad文件和网格生成控制json文件。
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示例
通过设置以下剖分参数控制网格生成:待剖分实体维度MeshingDim;网格单元最大最小尺寸MaxSize/MinSize(绝对尺寸),可用几何模型boundingbox对角线长度bblen乘以一定比例r,比如[0.01, 0.1]*bblen;网格增长率GrowthRate;待剖分实体Tag序列SelectedEntities;曲率因子CurvatureFactor;网格剖分类型ElementType;网格剖分方法MeshingMethod;并行线程数ThreadNum。
{
"MeshSize": [
{
"CurvatureFactor": 0.6,
"GrowthRate": 1.0,
"MaxSize": 0.5,
"MeshingDim": 3,
"MinSize": 0.1,
"ElementType": "Tri",
"MeshingMethod": "D2AFT",
"SelectedEntities": []
}
],
"ThreadNum": 1
}
类 | 键 | 是否必需 | 取值范围 | 默认值 | 备注 |
MeshSize | CurvatureFactore | 否 | [0, 1.0] | 0 | 0表示关闭;1.0表示整圆剖分成3段 |
MeshSize | GrowthRate | 否 | [1.0, inf] | 1.0 | |
MeshSize | MaxSize | 否 | [eps, inf] | inf | 绝对尺寸 |
MeshSize | MinSize | 否 | [0, inf] | 0 | 绝对尺寸,MinSize<=MaxSize |
MeshSize | MeshingDim | 是 | [1,2,3] | —— | |
MeshSize | SelectedEntities | 是 | MeshingDim维度下实体tag的子集 | —— | 取空值表示指定维度下的所有实体 |
MeshSize | ElementType | 否 | [Tri, Quad, Mixed, RTri] | Tri | 只在MeshingDim=2时有效,其余忽略;Tri 三角形;Quad 全四边形;RTri 直角三角形;Mixed 三角形四边形混合网格 |
MeshSize | MeshingMethod | 否 | [Transfinite,D2Delaunay,D2AFT] | ElementType="Tri"时默认"D2AFT" | 只在MeshingDim=2时有效,其余忽略;Transfinite方法生成结构化网格,仅对含2/3/4边的face有效;D2Delaunay 德劳内方法生成三角形;D2AFT 波前法生成三角形 |
Json示例-平面边界层
以二维翼型生成平面边界层混合网格为例。
{
"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
}
以下分别为导入的cad模型和最终生成的网格模型。
更多复杂配置请看:二维边界层详细 JSON 示例
Json示例-空间边界层
以三维翼型生成空间边界层混合网格为例。
{
"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"
},
"VectorTreatment": {
"SmoothTopCapShellMesh": false
}
},
{
"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
}
以下分别为导入的cad模型和最终生成的网格模型以及剖面图。
Json示例-扫掠网格
注意事项:扫掠体网格只支持单一扫掠体,source源面可以包含多个面,target目标面只能包含单个面。侧面要求是2/3/4边面。
{
"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
}
以下分别为导入的cad模型和最终生成的网格模型。
Json示例-复制网格
可以将单个或者多个Entity(边或者面)的网格复制到单个目标Entity上。应用在要求源和目标的网格拓扑完全一致的场景,如周期网格;注意事项:源可以包含多个Entity,目标只能包含一个Entity;源和目标的拓扑结构必须完全一致;当复制面网格时,如果源面和目标面拓扑一致,无须指定边界对应关系"EdgeCorrespondence";如果存在多条边界边对应单一边界边情形,必须正确指定边界边的对应关系。
{
"Copy": [
{
"EntityType": "Face",
"Source": [ 43 ],
"Target": [ 47 ]
}
],
"MeshSize": [
{
"CurvatureFactor": 0,
"GrowthRate": 1.0,
"MaxSize": 3,
"MeshingDim": 2,
"MinSize": 1,
"SelectedEntities": [ 43, 47 ]
}
],
"ThreadNum": 1
}
以Entity为面为例,以下分别为导入的cad模型和复制网格。
Json示例-多种线网格剖分方式
方式一:指定边上单元的数目;
方式二:显式地指定边上每段单元的长度比例;
方式三:按照预设定的函数(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
}
类 | 键 | 是否必需 | 取值范围 | 默认值 | 备注 |
Distribution | EntityType | 是 | Edge | – | |
Distribution | SelectedEntities | 是 | 可以为空 | – | Edge tags |
Distribution | DistributionType | 是 | NumberOfElements, Explicit, Linear, Geometric | – | 分布类型 |
Distribution | Orientation | 否 | Forward, Reverse | Forward | 朝向 |
Distribution | Symmetric | 否 | true, false | false | 是否对称分布 |
Distribution | NElement | 是 | >=1 | – | 分段数 |
Distribution | EndBeginElementRatio | 是 | >0 | – | 分布尾段与首段长度之比 |
Distribution | DistributionPara | 是 | (0.0, 1.0) | – | 严格递增数列 |
以下为多种线网格剖分结果。
Json示例-高阶网格
支持生成 2 阶高阶网格,导出 VTK 或者 Gmsh 格式文件。
{
"MeshSize": [
{
"CurvatureFactor": 0.2,
"GrowthRate": 1.0,
"MaxSize": 5.0,
"MeshingDim": 3,
"MinSize": 2.0,
"SelectedEntities": []
}
],
"ElementOrder": {
"Order": 2
},
"ThreadNum": 1
}
以下为高阶网格。
构建模型
导入cad文件,构建模型。
Class of model in NextMesh
定义 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...
生成/获取网格
导入网格生成控制参数json文件,生成网格。
nlohmann::json paraJ = nlohmann::json::parse(std::ifstream(jsonPath));
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.
获取网格和几何信息
获取模型实体列表,实体的BRep关系和包围盒,每个实体包含的网格类型与网格单元和顶点,获取网格单元和顶点的全局Id等相关信息。
for (
DimType dim : {DimType::D0, DimType::D1, DimType::D2, DimType::D3})
{
std::vector<NMEntity> etVec;
for (auto ent : etVec)
{
std::vector<NMEntity> parentVec;
std::vector<NMEntity> childVec;
std::vector<Orientation> ories;
auto entElemNum = meshapi.EntityGetElementCount(ent);
for (size_t i = 0; i < entElemNum; i++)
{
auto elem = meshapi.EntityGetElementByIndex(ent, i);
}
auto entNodeNum = meshapi.EntityGetNodeCount(ent);
for (size_t i = 0; i < entNodeNum; i++)
{
auto node = meshapi.EntityGetNodeByIndex(ent, i);
}
}
}
auto elemTotalNum = meshapi.GetElementCount();
for (size_t i = 0; i < elemTotalNum; i++)
{
auto elem = meshapi.GetElementByIndex(i);
auto elemId = meshapi.ElementGetID(elem);
auto elemType = meshapi.ElementGetType(elem);
auto nodeCount = meshapi.ElementGetNodeCount(elem);
for (size_t in = 0; in < nodeCount; in++)
{
auto node = meshapi.ElementGetNode(elem, in);
auto nodeId = meshapi.NodeGetID(node);
auto nodeEnt = meshapi.NodeGetEntity(node);
auto nodePos = meshapi.NodeGetPosition(node);
double u = meshapi.NodeGetFirstParameter(node);
double v = meshapi.NodeGetSecondParameter(node);
}
}
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
定义 Macros.hpp:25
DimType
Type of dimension
定义 Macros.hpp:58
设置面组
支持面组信息的增删改查。
std::vector<EntTag> entTags;
std::set<std::string> pNames;
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
输出网格文件
输出用户指定格式的网格文件,比如 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);
点击这里example01可获得网格剖分示例完整源码,大家根据学习需要自行下载。
附录
下面列出了此示例的完整代码:
#include <fstream>
#include <nlohmann/json.hpp>
#include <set>
void GenMesh()
{
const std::string cadstr = "./data/qiuwotaojian.stp";
const std::string jsonPath = "./data/mesh_para-mesh000.json";
nlohmann::json paraJ = nlohmann::json::parse(std::ifstream(jsonPath));
for (
DimType dim : {DimType::D0, DimType::D1, DimType::D2, DimType::D3})
{
std::vector<NMEntity> etVec;
for (auto ent : etVec)
{
std::vector<NMEntity> parentVec;
std::vector<NMEntity> childVec;
std::vector<Orientation> ories;
auto entElemNum = meshapi.EntityGetElementCount(ent);
for (size_t i = 0; i < entElemNum; i++)
{
auto elem = meshapi.EntityGetElementByIndex(ent, i);
}
auto entNodeNum = meshapi.EntityGetNodeCount(ent);
for (size_t i = 0; i < entNodeNum; i++)
{
auto node = meshapi.EntityGetNodeByIndex(ent, i);
}
}
}
auto elemTotalNum = meshapi.GetElementCount();
for (size_t i = 0; i < elemTotalNum; i++)
{
auto elem = meshapi.GetElementByIndex(i);
auto elemId = meshapi.ElementGetID(elem);
auto elemType = meshapi.ElementGetType(elem);
auto nodeCount = meshapi.ElementGetNodeCount(elem);
for (size_t in = 0; in < nodeCount; in++)
{
auto node = meshapi.ElementGetNode(elem, in);
auto nodeId = meshapi.NodeGetID(node);
auto nodeEnt = meshapi.NodeGetEntity(node);
auto nodePos = meshapi.NodeGetPosition(node);
double u = meshapi.NodeGetFirstParameter(node);
double v = meshapi.NodeGetSecondParameter(node);
}
}
auto nodeTotalNum = meshapi.GetNodeCount();
for (size_t i = 0; i < nodeTotalNum; i++)
{
auto node = meshapi.GetNodeByIndex(i);
}
std::vector<EntTag> entTags;
std::set<std::string> pNames;
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);
}