29 #if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES) 30 #define _USE_MATH_DEFINES 79 std::string file = fname;
80 std::vector<std::pair<int, int>> imported;
84 std::cerr <<
"Error: Input Geometry File " << file <<
" not found." 90 gmsh::model::occ::importShapes(file, imported,
false);
91 gmsh::model::occ::synchronize();
97 gmsh::vectorpair volumes;
98 gmsh::model::getEntities(volumes, 3);
100 gmsh::vectorpair outTags;
101 std::vector<gmsh::vectorpair> outDimTagsMap;
102 gmsh::model::occ::fragment(volumes, {}, outTags, outDimTagsMap);
103 gmsh::model::occ::synchronize();
115 gmsh::model::mesh::generate(3);
116 gmsh::model::mesh::removeDuplicateNodes();
123 if (ext !=
".msh" && ext !=
".vtu") {
125 auto pos = std::find(meshExtensions.begin(), meshExtensions.end(), ext);
126 if (pos == meshExtensions.end()) {
127 std::cerr <<
"Error: Output file extension " << ext
128 <<
" not supported in this mesh engine." << std::endl;
129 std::cout <<
"Supported formats are ";
130 for (
auto meshExtension : meshExtensions) {
131 std::cout << meshExtension <<
" ";
133 std::cout <<
"\n" << std::endl;
136 if (ext ==
".inp" || ext ==
".unv") {
137 gmsh::option::setNumber(
"Mesh.SaveGroupsOfElements", 1);
138 gmsh::option::setNumber(
"Mesh.SaveGroupsOfNodes", 1);
153 gmsh::option::setNumber(
"General.Terminal", 1);
157 gmsh::option::setNumber(
"Geometry.OCCImportLabels", 1);
161 gmsh::option::setNumber(
"Mesh.MshFileVersion", 2.2);
165 gmsh::option::setNumber(
"Mesh.CharacteristicLengthExtendFromBoundary", 1);
167 gmsh::option::setNumber(
"Mesh.CharacteristicLengthExtendFromBoundary", 0);
169 gmsh::option::setNumber(
"Mesh.CharacteristicLengthFromCurvature", 1);
171 gmsh::option::setNumber(
"Mesh.CharacteristicLengthFromCurvature", 0);
172 gmsh::option::setNumber(
"Mesh.MinimumElementsPerTwoPi",
175 gmsh::option::setNumber(
"Mesh.Optimize", 1);
177 gmsh::option::setNumber(
"Mesh.Optimize", 0);
178 gmsh::option::setNumber(
"Mesh.OptimizeThreshold",
181 gmsh::option::setNumber(
"Mesh.RecombineAll", 0);
182 gmsh::option::setNumber(
"Mesh.Smoothing", 1);
183 gmsh::option::setNumber(
"Mesh.CharacteristicLengthFactor", 1);
184 gmsh::option::setNumber(
"Mesh.CharacteristicLengthFromPoints", 1);
185 gmsh::option::setNumber(
"Mesh.LcIntegrationPrecision", 1e-09);
186 gmsh::option::setNumber(
"Mesh.MaxIterDelaunay3D", 0);
187 gmsh::option::setNumber(
"Mesh.RandomFactor", 1e-09);
188 gmsh::option::setNumber(
"Mesh.RandomFactor3D", 1e-12);
189 gmsh::option::setNumber(
"Mesh.ElementOrder",
191 gmsh::option::setNumber(
"Mesh.SubdivisionAlgorithm",
196 if (algo ==
"Frontal")
198 else if (algo ==
"MeshAdapt")
200 else if (algo ==
"Automatic")
202 else if (algo ==
"Delaunay")
204 else if (algo ==
"Frontal Quads" || algo ==
"Frontal Quad")
206 else if (algo ==
"Packing of Parallelograms")
209 std::cerr <<
"Warning: Surface algorithm " << algo <<
" not supported. \n" 210 <<
"Using default Frontal algorithm." << std::endl;
212 gmsh::option::setNumber(
"Mesh.Algorithm", a);
216 if (algo ==
"Delaunay")
218 else if (algo ==
"Frontal")
220 else if (algo ==
"HXT")
223 std::cerr <<
"Warning: Volume algorithm " << algo <<
" not supported. \n" 224 <<
"Using default Delaunay algorithm." << std::endl;
226 gmsh::option::setNumber(
"Mesh.Algorithm3D", a);
234 std::vector<std::pair<int, int>>
surfaces;
235 gmsh::model::getEntities(surfaces, 2);
236 std::string name =
"";
237 for (
const std::pair<int, int> &s : surfaces) {
240 gmsh::model::getEntityName(dim, tag, name);
241 std::cout <<
"Surface " << tag <<
" name: " << name << std::endl;
243 gmsh::model::getEntityName(3, 1, name);
244 std::cout <<
"Volume " << 1 <<
" name: " << name << std::endl;
252 std::vector<std::pair<int, int>>
surfaces;
253 gmsh::model::getEntities(surfaces, 2);
254 for (
const std::pair<int, int> &s : surfaces) {
258 gmsh::model::getColor(dim, tag, r, g, b, a);
259 std::cout <<
"Surface " << tag <<
" color: " << r <<
"," << g <<
"," << b
268 bool bgfAssigned =
false;
274 std::string type = sf.type;
275 if (sf.type ==
"Frustum") {
277 for (
auto &prm : sf.params) {
278 if (prm.first ==
"Thickness") {
280 std::cout <<
"thickness = " << thick << std::endl;
284 for (
auto &prm : sf.params) {
285 std::string key = prm.first;
286 int val =
static_cast<int>(prm.second);
287 if (key ==
"IField") {
289 if (sf2.type ==
"Cylinder" && sf2.id == val) {
301 for (
auto &prm2 : sf2.params) {
302 if (prm2.first ==
"Radius") radius = prm2.second;
304 if (prm2.first ==
"VIn") vin = prm2.second;
305 if (prm2.first ==
"VOut") vout = prm2.second;
306 if (prm2.first ==
"XCenter") xc = prm2.second;
307 if (prm2.first ==
"YCenter") yc = prm2.second;
308 if (prm2.first ==
"ZCenter") zc = prm2.second;
309 if (prm2.first ==
"XAxis") xa = prm2.second;
310 if (prm2.first ==
"YAxis") ya = prm2.second;
311 if (prm2.first ==
"ZAxis") za = prm2.second;
318 std::pair<std::string, double> p;
319 p = {
"R1_inner", radius};
320 sf.params.push_back(p);
321 p = {
"R1_outer", radius + thick};
322 sf.params.push_back(p);
323 p = {
"R2_inner", radius};
324 sf.params.push_back(p);
325 p = {
"R2_outer", radius + thick};
326 sf.params.push_back(p);
328 p = {
"V1_inner", vin};
329 sf.params.push_back(p);
330 p = {
"V2_inner", vin};
331 sf.params.push_back(p);
332 p = {
"V1_outer", vout};
333 sf.params.push_back(p);
334 p = {
"V2_outer", vout};
335 sf.params.push_back(p);
337 double mag = sqrt(xa * xa + ya * ya + za * za);
339 p = {
"X1", xc - xa / 2 - xa * (thick / mag)};
340 sf.params.push_back(p);
341 p = {
"Y1", yc - ya / 2 - ya * (thick / mag)};
342 sf.params.push_back(p);
343 p = {
"Z1", zc - za / 2 - za * (thick / mag)};
344 sf.params.push_back(p);
346 p = {
"X2", xc + xa / 2 + xa * (thick / mag)};
347 sf.params.push_back(p);
348 p = {
"Y2", yc + ya / 2 + ya * (thick / mag)};
349 sf.params.push_back(p);
350 p = {
"Z2", zc + za / 2 + za * (thick / mag)};
351 sf.params.push_back(p);
368 gmsh::model::mesh::field::add(sf->type, sf->id);
369 for (
auto prm = (sf->params).begin(); prm != (sf->params).end(); prm++) {
370 if (prm->first !=
"")
371 gmsh::model::mesh::field::setNumber(sf->id, prm->first, prm->second);
384 for (
auto prm = (sf->num_list_params).begin();
385 prm != (sf->num_list_params).end(); prm++) {
386 gmsh::model::mesh::field::setNumbers(sf->id, prm->first, prm->second);
395 std::cout <<
"Using size field ID = " <<
id << std::endl;
397 gmsh::model::mesh::field::setAsBackgroundMesh(highest_id);
398 std::cout <<
"Warning: BackgroundField ID not found. " 399 <<
"Using size field with highest ID." << std::endl;
401 gmsh::model::occ::synchronize();
406 std::vector<std::pair<int, int>> volumes;
407 gmsh::model::getEntities(volumes, 3);
409 std::vector<int> volumeTags;
410 for(
const std::pair<int,int> &v : volumes) {
413 volumeTags.push_back(tag);
415 gmsh::model::addPhysicalGroup(3, volumeTags);
418 std::vector<std::pair<int, int>>
surfaces;
419 gmsh::model::getEntities(surfaces, 2);
432 const auto &groupColor = iter->first;
433 std::string groupColorStr = std::to_string(groupColor.at(0)) +
"," +
434 std::to_string(groupColor.at(1)) +
"," +
435 std::to_string(groupColor.at(2));
436 std::string groupName = iter->second;
437 std::vector<int> surfTags;
440 for(
const std::pair<int,int> &s : surfaces) {
444 gmsh::model::getColor(dim, tag, r, g, b, a);
445 if (groupColor != std::array<int, 3>{r, g, b})
continue;
446 std::string surfName = groupName +
"_" + std::to_string(
id);
447 gmsh::model::setEntityName(dim, tag, surfName);
448 surfTags.push_back(tag);
451 if(surfTags.size() == 0) {
452 std::cout <<
"NO SURFACES WITH COLOR " << groupColorStr <<
" FOUND." 455 std::cout <<
"Found " 457 << ((surfTags.size() == 1) ?
" surface" :
" surfaces")
460 <<
" mapped by color " 463 std::cout <<
"Adding physical group " << groupName << std::endl;
464 int groupTag = gmsh::model::addPhysicalGroup(2, surfTags);
465 gmsh::model::setPhysicalName(2, groupTag, groupName.c_str());
468 gmsh::model::occ::synchronize();
472 gmsh::vectorpair volumes;
473 gmsh::model::getEntities(volumes, 3);
475 for(
const std::pair<int,int> &v : volumes) {
477 int volumeTag = v.second;
480 auto blockIter = std::lower_bound(
486 blockIter->id != volumeTag) {
490 const auto &block = *blockIter;
492 gmsh::vectorpair volume = { v };
494 gmsh::vectorpair curves;
496 gmsh::model::getBoundary(volume, surfaces,
false,
false,
false);
497 gmsh::model::getBoundary(surfaces, curves,
false,
false,
false);
500 gmsh::vectorpair uniqueCurves;
501 for(
const std::pair<int,int> &c : curves) {
502 auto iter = std::find(uniqueCurves.begin(), uniqueCurves.end(), c);
503 if (iter == uniqueCurves.end()) {
504 uniqueCurves.push_back(c);
508 if(uniqueCurves.size() != 12) {
509 std::cout <<
"Found " << uniqueCurves.size() <<
" unique curves in volume " << volumeTag <<
510 ". There should be 12." << std::endl;
511 std::cout <<
"Error : only hexahedral transfinite volumes are supported." << std::endl;
515 std::cout <<
"Found transfinite block : " << volumeTag << std::endl;
519 std::pair<int,int> curve;
523 std::vector<CurveData> orientedCurves;
525 for(
const std::pair<int,int> &c : uniqueCurves) {
527 gmsh::vectorpair curves = { c };
529 gmsh::model::getBoundary(curves, points,
false,
true,
true);
531 std::pair<int,int> a = points[0];
532 std::pair<int,int> b = points[1];
534 std::vector<double> a_vert, b_vert;
535 gmsh::model::getValue(a.first, a.second, {}, a_vert);
536 gmsh::model::getValue(b.first, b.second, {}, b_vert);
539 double ab[] = { b_vert[0]-a_vert[0],
541 b_vert[2]-a_vert[2] };
542 double ab_den = std::sqrt(ab[0]*ab[0] + ab[1]*ab[1] + ab[2]*ab[2]);
543 ab[0] = ab[0]/ab_den;
544 ab[1] = ab[1]/ab_den;
545 ab[2] = ab[2]/ab_den;
551 for(
int axis = 0; axis < 3; ++axis) {
552 double dot = ab[0]*block.axis[axis][0] +
553 ab[1]*block.axis[axis][1] +
554 ab[2]*block.axis[axis][2];
555 double theta = std::acos(dot);
556 if(theta < M_PI/4 || theta > 3*M_PI/4) {
557 bool reverse = theta >= M_PI / 4;
561 data.reverse = reverse;
562 orientedCurves.push_back(data);
567 for(
auto &oc : orientedCurves) {
569 std::pair<int,int> curve = oc.curve;
570 bool reverse = oc.reverse;
573 int vert = block.vert[oc.axis];
574 double coef = block.coef[oc.axis];
575 std::string type = block.type[oc.axis];
577 if(type ==
"Progression") {
579 coef = reverse ? 1/coef : coef;
582 gmsh::model::mesh::setTransfiniteCurve(curve.second, vert, type, coef);
585 std::cout <<
"Setting transfinite surfaces..." << std::endl;
586 for(
const std::pair<int,int> &s : surfaces) {
587 gmsh::model::mesh::setTransfiniteSurface(s.second);
588 gmsh::model::mesh::setRecombine(s.first, s.second);
591 std::cout <<
"Setting transfinite volume..." << std::endl;
592 gmsh::model::mesh::setTransfiniteVolume(v.second);
double maxSize
Maximum global mesh size.
~gmshGen()
gmshGen standard destructor
data_type data
Edge/face with sorted point ids (a, b, c, ...) is located at some index i in data[b], with data[b][i].first == [a, c] (for edges, third point id treated as -1).
std::string mshFname
Name of .msh file output by gmsh.
int elementOrder
Element order.
static const std::array< const char *, 6 > & getMeshExtensions()
Get list of file extensions supported by gmsh.
bool sizeFromCurvature
Mesh size based on curvature option.
void globalOptions()
Sets the global geometry and meshing options.
int bgField
Size field ID to use as background field.
A struct for defining hexahedral transfinite volumes.
std::string find_ext(const std::string &fname)
int createMeshFromSTL(const char *fname) override
Creates mesh from input STEP file.
gmshGen()
gmshGen default constructor
std::set< TransfiniteBlock > transfiniteBlocks
Map from volume id to transfinite hexahedron information.
void meshSizeFields()
Applies mesh size fields.
bool extSizeFromBoundary
Extend mesh size from boundary option.
void getSurfaceColors()
Gets the surface colors of STEP geometry.
double minSize
Minimum global mesh size.
std::string trim_fname(const std::string &name, const std::string &ext)
std::string algo3D
Volume meshing algorithm.
void applyTransfiniteVolumes()
Applies transfinite settings to prescribed hexahedral volumes.
std::map< std::array< int, 3 >, std::string > color2groupMap
Map from RGB to physical name.
gmshParams contains all parameters essential for mesh generation using gmshGen class methods...
bool saveAll
Save all elements.
vtkIdType id
id in .inp file
std::string ofname
Output mesh file name.
std::vector< vtkIdType > points
points given by id in .inp file
std::string algo2D
Surface meshing algorithm.
std::map< std::string, std::vector< std::pair< vtkIdType, int > > > surfaces
Map from SURFACE name to (element id, side) (id and side both use .inp IDs)
bool optimize
Whether to optimize mesh or not.
bool fragmentAll
Whether to call boolean fragments on all volumes.
double optimizeThreshold
Mesh optimization threshold, between 0 and 1.
int minElePer2Pi
Minimum number of mesh elements per two Pi.
int subdivisionAlg
Subdivision algorithm 0: none, 1: all quads, 2: all hexas.
int createMeshFromSTEP(const char *fname)
void applyColorNames()
Applies physical names based on color.
void getGeomNames()
Gets geometry entitiy names of STEP geometry.
gmshParams * meshParams
gmshParams object Parameters
std::vector< volSizeField > sizeFields
Vector for volSizeField struct.