PeriDEM 0.3.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
mesh_gen Namespace Reference

Namespaces

namespace  anonymous_namespace{annulusMesh2D.cpp}
 
namespace  anonymous_namespace{annulusMesh3D.cpp}
 
namespace  anonymous_namespace{builtinGmshGeometry.cpp}
 
namespace  anonymous_namespace{meshGenerator.cpp}
 
namespace  anonymous_namespace{openBoundaryWalls3D.cpp}
 

Functions

void buildAnnulus2DInCurrentModel (const geom::AnnulusGeomObject &a, double h)
 
void buildAnnulus3DInCurrentModel (const geom::AnnulusGeomObject &a, double h)
 
void buildGmshGeometryInCurrentModel (const geom::GeomObject &g, double h)
 
int gmshMeshGenerateDim (const inp::ModelDeck *modelDeck)
 
void fillMeshFromActiveGmshModel (mesh::Mesh *mesh_p, const inp::MeshDeck *meshDeck, const inp::ModelDeck *modelDeck)
 
int addDiskOcc (double xc, double yc, double zc, double rx, double ry, double theta=0.)
 OCC disk compatible with older Gmsh (no zAxis/xAxis) and newer APIs.
 
void generateBuiltinParticleMeshGmsh (const std::shared_ptr< geom::GeomObject > &geomObj, double h, const std::string &filenameStem, bool vtk_out, bool write_mesh_file, mesh::Mesh *out_mesh, const inp::MeshDeck *meshDeck, const inp::ModelDeck *modelDeck)
 In-process Gmsh mesh from geom::GeomObject (after createGeomObject on deck / Particle data).
 
void physicalGroupsWallOpenFromY2D (int surfaceTag, double yOpen, double tol, const std::string &physWall, const std::string &physOpen)
 
void physicalGroupsWallOpenFromFace3D (int volumeTag, int openFace, const util::Point &lo, const util::Point &hi, double t, double tol, const std::string &physWall, const std::string &physOpen)
 
std::shared_ptr< mesh::MeshcreateParticleMesh (const inp::MeshDeck &zmeshDeck, const geom::GeomData &zgeomDeck, const inp::ModelDeck *modelDeck, const std::string &modelName)
 Build a reference-particle mesh: file, uniform rectangle, or in-process Gmsh.
 
void buildCylinderOcc (const geom::Cylinder &c)
 
void buildEllipseOcc (const geom::Ellipse &e, double h)
 
void buildEllipsoidOcc (const geom::Ellipsoid &e)
 

Function Documentation

◆ addDiskOcc()

int mesh_gen::addDiskOcc ( double  xc,
double  yc,
double  zc,
double  rx,
double  ry,
double  theta = 0. 
)
inline

OCC disk compatible with older Gmsh (no zAxis/xAxis) and newer APIs.

Gmsh before ~4.11 only accepts addDisk(xc,yc,zc,rx,ry,tag). Later versions add optional axis vectors for in-plane rotation. On older Gmsh, apply a z-rotation about the disk center when theta is nonzero.

Definition at line 26 of file gmshOccCompat.h.

27 {
28#if (GMSH_API_VERSION_MAJOR > 4) || \
29 (GMSH_API_VERSION_MAJOR == 4 && GMSH_API_VERSION_MINOR >= 11)
30 const std::vector<double> zAxis = {0., 0., 1.};
31 const std::vector<double> xAxis = {std::cos(theta), std::sin(theta), 0.};
32 return gmsh::model::occ::addDisk(xc, yc, zc, rx, ry, -1, zAxis, xAxis);
33#else
34 const int tag = gmsh::model::occ::addDisk(xc, yc, zc, rx, ry, -1);
35 if (std::abs(theta) > 1.0e-15)
36 gmsh::model::occ::rotate({{2, tag}}, xc, yc, zc, 0., 0., 1., theta);
37 return tag;
38#endif
39}

Referenced by mesh_gen::anonymous_namespace{annulusMesh2D.cpp}::addEllipseDiskOcc(), mesh_gen::anonymous_namespace{annulusMesh2D.cpp}::buildCircleAnnulus2D(), and buildEllipseOcc().

Here is the caller graph for this function:

◆ buildAnnulus2DInCurrentModel()

void mesh_gen::buildAnnulus2DInCurrentModel ( const geom::AnnulusGeomObject a,
double  h 
)

OCC: outer rectangle minus inner rectangle (coplanar XY), then mesh-size point embed.

Definition at line 201 of file annulusMesh2D.cpp.

201 {
202
203 if (a.d_dim != 2)
204 throw std::runtime_error("buildAnnulus2DInCurrentModel: expected d_dim == 2.");
205 if (!a.d_inObj_p || !a.d_outObj_p)
206 throw std::runtime_error("buildAnnulus2DInCurrentModel: null inner or outer geometry.");
207
208 if (a.d_inObj_p->d_name == "rectangle" && a.d_outObj_p->d_name == "rectangle") {
209 buildRectangleAnnulus2D(a, h);
210 return;
211 }
212 if (a.d_inObj_p->d_name == "circle" && a.d_outObj_p->d_name == "circle") {
213 buildCircleAnnulus2D(a, h);
214 return;
215 }
216 if (a.d_inObj_p->d_name == "ellipse" && a.d_outObj_p->d_name == "ellipse") {
218 return;
219 }
220
221 throw std::runtime_error(
222 "buildAnnulus2DInCurrentModel: unsupported 2D pair (supported: rectangle−rectangle, "
223 "circle−circle, ellipse−ellipse).");
224}
GeomObject * d_outObj_p
Outer object.
size_t d_dim
Dimension objects live in.
GeomObject * d_inObj_p
Inner object.
const std::string d_name
name of object
void buildEllipseAnnulus2D(const geom::AnnulusGeomObject &a, double h)

References geom::AnnulusGeomObject::d_dim, geom::AnnulusGeomObject::d_inObj_p, geom::GeomObject::d_name, and geom::AnnulusGeomObject::d_outObj_p.

Referenced by buildGmshGeometryInCurrentModel().

Here is the caller graph for this function:

◆ buildAnnulus3DInCurrentModel()

void mesh_gen::buildAnnulus3DInCurrentModel ( const geom::AnnulusGeomObject a,
double  h 
)

OCC: outer cuboid minus inner cuboid (axis-aligned shell), then mesh-size point embed.

Definition at line 143 of file annulusMesh3D.cpp.

143 {
144
145 if (a.d_dim != 3)
146 throw std::runtime_error("buildAnnulus3DInCurrentModel: expected d_dim == 3.");
147 if (!a.d_inObj_p || !a.d_outObj_p)
148 throw std::runtime_error("buildAnnulus3DInCurrentModel: null inner or outer geometry.");
149
150 if (a.d_inObj_p->d_name == "cuboid" && a.d_outObj_p->d_name == "cuboid") {
151 buildCuboidAnnulus3D(a, h);
152 return;
153 }
154 if (a.d_inObj_p->d_name == "sphere" && a.d_outObj_p->d_name == "sphere") {
155 buildSphereAnnulus3D(a, h);
156 return;
157 }
158
159 throw std::runtime_error(
160 "buildAnnulus3DInCurrentModel: unsupported 3D pair (supported: cuboid−cuboid, sphere−sphere).");
161}

References geom::AnnulusGeomObject::d_dim, geom::AnnulusGeomObject::d_inObj_p, geom::GeomObject::d_name, and geom::AnnulusGeomObject::d_outObj_p.

Referenced by buildGmshGeometryInCurrentModel().

Here is the caller graph for this function:

◆ buildCylinderOcc()

void mesh_gen::buildCylinderOcc ( const geom::Cylinder c)

OCC cylinder matching geom::Cylinder (base center, axis × length, radius).

Definition at line 23 of file primitiveOccMesh.cpp.

23 {
24
25 if (c.d_r <= 0.)
26 throw std::runtime_error("buildCylinderOcc: radius must be positive.");
27 if (c.d_l <= 0.)
28 throw std::runtime_error("buildCylinderOcc: length must be positive.");
29
30 const double dx = c.d_l * c.d_xa.d_x;
31 const double dy = c.d_l * c.d_xa.d_y;
32 const double dz = c.d_l * c.d_xa.d_z;
33
34 gmsh::model::occ::addCylinder(c.d_xBegin.d_x, c.d_xBegin.d_y, c.d_xBegin.d_z, dx, dy, dz, c.d_r);
35 gmsh::model::occ::synchronize();
36}
util::Point d_xBegin
Center point of cross-section at the beginning.
util::Point d_xa
Axis of cylinder (unit vector)
double d_l
Length.
double d_r
Radius.
double d_y
the y coordinate
Definition point.h:36
double d_z
the z coordinate
Definition point.h:39
double d_x
the x coordinate
Definition point.h:33

References geom::Cylinder::d_l, geom::Cylinder::d_r, util::Point::d_x, geom::Cylinder::d_xa, geom::Cylinder::d_xBegin, util::Point::d_y, and util::Point::d_z.

Referenced by buildGmshGeometryInCurrentModel().

Here is the caller graph for this function:

◆ buildEllipseOcc()

void mesh_gen::buildEllipseOcc ( const geom::Ellipse e,
double  h 
)

OCC disk / ellipse in the plane z = center.d_z (see geom::Ellipse).

Definition at line 38 of file primitiveOccMesh.cpp.

38 {
39
40 if (e.d_a <= 0. || e.d_b <= 0.)
41 throw std::runtime_error("buildEllipseOcc: semi-axes must be positive.");
42
43 const double rx = std::max(e.d_a, e.d_b);
44 const double ry = std::min(e.d_a, e.d_b);
45 double theta = e.d_theta;
46 if (e.d_a < e.d_b)
47 theta += M_PI / 2.;
48
49 const int s = addDiskOcc(e.d_x.d_x, e.d_x.d_y, e.d_x.d_z, rx, ry, theta);
50 gmsh::model::occ::synchronize();
51 const int p = gmsh::model::occ::addPoint(e.d_x.d_x, e.d_x.d_y, e.d_x.d_z, h);
52 gmsh::model::occ::synchronize();
53 gmsh::model::mesh::embed(0, {p}, 2, s);
54}
double d_a
Semi-axis along local x before rotation (in-plane)
util::Point d_x
Center.
double d_b
Semi-axis along local y before rotation (in-plane)
double d_theta
Counter-clockwise rotation about +z through the center (radians)
int addDiskOcc(double xc, double yc, double zc, double rx, double ry, double theta=0.)
OCC disk compatible with older Gmsh (no zAxis/xAxis) and newer APIs.

References addDiskOcc(), geom::Ellipse::d_a, geom::Ellipse::d_b, geom::Ellipse::d_theta, geom::Ellipse::d_x, util::Point::d_x, util::Point::d_y, and util::Point::d_z.

Referenced by buildGmshGeometryInCurrentModel().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ buildEllipsoidOcc()

void mesh_gen::buildEllipsoidOcc ( const geom::Ellipsoid e)

OCC ellipsoid: unit sphere + affine map R diag(r1,r2,r3) and translation.

Definition at line 56 of file primitiveOccMesh.cpp.

56 {
57
58 if (e.d_a <= 0. || e.d_b <= 0. || e.d_c <= 0.)
59 throw std::runtime_error("buildEllipsoidOcc: semi-axes must be positive.");
60
61 // Unit sphere at origin, then x' = R diag(r1,r2,r3) x + c (row-major 4×4 for gmsh).
62 double R[9];
64
65 std::vector<double> mat(16);
66 for (int i = 0; i < 3; ++i) {
67 mat[static_cast<size_t>(i * 4 + 0)] = R[i * 3 + 0] * e.d_a;
68 mat[static_cast<size_t>(i * 4 + 1)] = R[i * 3 + 1] * e.d_b;
69 mat[static_cast<size_t>(i * 4 + 2)] = R[i * 3 + 2] * e.d_c;
70 mat[static_cast<size_t>(i * 4 + 3)] = (i == 0) ? e.d_x.d_x : (i == 1) ? e.d_x.d_y : e.d_x.d_z;
71 }
72 mat[12] = mat[13] = mat[14] = 0.;
73 mat[15] = 1.;
74
75 const int v = gmsh::model::occ::addSphere(0., 0., 0., 1.);
76 gmsh::model::occ::synchronize();
77 gmsh::model::occ::affineTransform({{3, v}}, mat);
78 gmsh::model::occ::synchronize();
79 gmsh::model::occ::removeAllDuplicates();
80 gmsh::model::occ::synchronize();
81}
util::Point d_x
void ellipsoidRotationMatrix(const Ellipsoid &e, double R[9])
Row-major 3×3 rotation from ellipsoid axis–angle (identity if ).

References geom::Ellipsoid::d_a, geom::Ellipsoid::d_b, geom::Ellipsoid::d_c, geom::Ellipsoid::d_x, util::Point::d_x, util::Point::d_y, util::Point::d_z, and geom::ellipsoidRotationMatrix().

Referenced by buildGmshGeometryInCurrentModel().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ buildGmshGeometryInCurrentModel()

void mesh_gen::buildGmshGeometryInCurrentModel ( const geom::GeomObject geom,
double  h 
)

Build OCC/geo entities in the current Gmsh model from a concrete geom::GeomObject.

New shapes: add a branch here or in helpers (e.g. primitiveOccMesh.cpp), and register the name in geom::acceptable_geometries / createGeomObject. AnnulusGeomObject uses d_name annulus_object; meshGenerator also allows that name (deck types are circle_minus_circle / rectangle_minus_rectangle / …). open_rect_channel_2d: U-channel polygon (geom::OpenRectChannel2D) + optional physical groups via openBoundaryWalls2D. open_cuboid_channel_3d: cuboidal shell with one outer face slab removed (geom::OpenCuboidChannel3D) + physical groups via openBoundaryWalls3D.

Definition at line 293 of file builtinGmshGeometry.cpp.

293 {
294 const std::string &n = g.d_name;
295
296 if (n == "annulus_object") {
297 const auto &ag = static_cast<const geom::AnnulusGeomObject &>(g);
298 if (ag.d_dim == 2)
299 return buildAnnulus2DInCurrentModel(ag, h);
300 if (ag.d_dim == 3)
301 return buildAnnulus3DInCurrentModel(ag, h);
302 throw std::runtime_error("buildGmshGeometryInCurrentModel: annulus_object has invalid d_dim.");
303 }
304
305 if (n == "circle")
306 return buildCircleOcc(static_cast<const geom::Circle &>(g), h);
307 if (n == "ellipse")
308 return buildEllipseOcc(static_cast<const geom::Ellipse &>(g), h);
309 if (n == "sphere")
310 return buildSphereOcc(static_cast<const geom::Sphere &>(g));
311 if (n == "ellipsoid")
312 return buildEllipsoidOcc(static_cast<const geom::Ellipsoid &>(g));
313 if (n == "cube")
314 return buildOccBoxFromAabb(g);
315 if (n == "cuboid")
316 return buildOccBoxFromAabb(g);
317 if (n == "cylinder")
318 return buildCylinderOcc(static_cast<const geom::Cylinder &>(g));
319
320 if (n == "square")
321 return meshPolygon2DGeoFromVertices(static_cast<const geom::Square &>(g).d_vertices, h);
322 if (n == "rectangle")
323 return meshPolygon2DGeoFromVertices(static_cast<const geom::Rectangle &>(g).d_vertices, h);
324 if (n == "triangle")
325 return meshPolygon2DGeoFromVertices(static_cast<const geom::Triangle &>(g).d_vertices, h);
326 if (n == "hexagon")
327 return meshPolygon2DGeoFromVertices(static_cast<const geom::Hexagon &>(g).d_vertices, h);
328 if (n == "drum2d")
329 return meshPolygon2DGeoFromVertices(drum2dPolygonBoundary(static_cast<const geom::Drum2D &>(g)),
330 h);
331 if (n == "open_rect_channel_2d")
332 return buildOpenRectChannel2DGeo(static_cast<const geom::OpenRectChannel2D &>(g), h);
333 if (n == "open_cuboid_channel_3d")
334 return buildOpenCuboidChannel3DGeo(static_cast<const geom::OpenCuboidChannel3D &>(g), h);
335 if (n == "complex")
336 return buildComplexRectangles2DOcc(static_cast<const geom::ComplexGeomObject &>(g), h);
337
338 throw std::runtime_error("buildGmshGeometryInCurrentModel: no Gmsh recipe for geometry \"" + n +
339 "\".");
340}
Defines annulus rectangle.
Defines circle.
Defines complex geometrical object.
Defines cylinder.
Defines Drum2D.
Filled ellipse in the plane z = center.d_z, semi-axes in the xy plane.
Ellipsoid: center , semi-axes in a body frame rotated from world by axis–angle (Rodrigues)....
Defines Hexagon.
Hollow axis-aligned cuboid shell with uniform wall thickness and one outer face open.
2D U-shaped cavity: thick rectangular frame with the top (+y) side open.
Defines Rectangle.
Defines sphere.
Defines Square.
Defines Triangle.
void buildAnnulus3DInCurrentModel(const geom::AnnulusGeomObject &a, double h)
void buildAnnulus2DInCurrentModel(const geom::AnnulusGeomObject &a, double h)

References buildAnnulus2DInCurrentModel(), buildAnnulus3DInCurrentModel(), buildCylinderOcc(), buildEllipseOcc(), buildEllipsoidOcc(), and geom::GeomObject::d_name.

Referenced by generateBuiltinParticleMeshGmsh().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ createParticleMesh()

std::shared_ptr< mesh::Mesh > mesh_gen::createParticleMesh ( const inp::MeshDeck zmeshDeck,
const geom::GeomData zgeomDeck,
const inp::ModelDeck modelDeck,
const std::string &  modelName 
)

Build a reference-particle mesh: file, uniform rectangle, or in-process Gmsh.

Definition at line 40 of file particleMesh.cpp.

43 {
44 if (!zmeshDeck.d_createMesh) {
45 return std::make_shared<mesh::Mesh>(&zmeshDeck, modelDeck);
46 }
47
48 if (zmeshDeck.d_createMeshInfo == "uniform" &&
49 (zgeomDeck.d_geomName == "rectangle" || zgeomDeck.d_geomName == "cuboid" ||
50 zgeomDeck.d_geomName == "square" || zgeomDeck.d_geomName == "cube")) {
51
52 if (!zgeomDeck.d_geom_p)
53 throw std::runtime_error(
54 modelName + ": uniform mesh on a box requires particle geometry object "
55 "(geom::createGeomObject on Particle.Set_i).");
56
57 const size_t dim = modelDeck->d_dim;
58 const auto bb = zgeomDeck.d_geom_p->box();
59 std::pair<std::vector<double>, std::vector<double>> box;
60 box.first.reserve(dim);
61 box.second.reserve(dim);
62 for (size_t i = 0; i < dim; ++i) {
63 const double lo_i =
64 (i == 0) ? bb.first.d_x : (i == 1) ? bb.first.d_y : bb.first.d_z;
65 const double hi_i =
66 (i == 0) ? bb.second.d_x : (i == 1) ? bb.second.d_y : bb.second.d_z;
67 box.first.push_back(lo_i);
68 box.second.push_back(hi_i);
69 }
70
71 std::vector<size_t> nGrid(dim);
72 for (size_t i = 0; i < dim; ++i) {
73 const double span = box.second[i] - box.first[i];
74 if (span <= 0.)
75 throw std::runtime_error(
76 modelName + ": uniform mesh: non-positive axis extent from geom box "
77 "(axis " +
78 std::to_string(i) + ").");
79 nGrid[i] = static_cast<size_t>(span / zmeshDeck.d_hMeshing);
80 }
81
82 mesh::Mesh temp_mesh;
83 mesh::createUniformMesh(&temp_mesh, dim, box, nGrid);
84 if (!zmeshDeck.d_voidRegions.empty())
85 mesh::removeNodesInBoxes(&temp_mesh, zmeshDeck.d_voidRegions);
86 maybeWriteMeshFile(zmeshDeck, temp_mesh);
87 return std::make_shared<mesh::Mesh>(temp_mesh);
88 }
89
90 if (zmeshDeck.d_createMeshInfo == "gmsh_builtin_mesh") {
91 if (!zgeomDeck.d_geom_p)
92 throw std::runtime_error(
93 modelName + ": gmsh_builtin_mesh requires particle geometry object "
94 "(geom::createGeomObject on Particle.Set_i).");
95 mesh::Mesh temp_mesh;
96 const std::string mesh_stem =
97 zmeshDeck.d_filename.empty()
98 ? std::string()
99 : util::io::removeExtensionFromFile(zmeshDeck.d_filename);
101 zgeomDeck.d_geom_p, zmeshDeck.d_hMeshing, mesh_stem, false,
102 zmeshDeck.d_writeMeshFile, &temp_mesh, &zmeshDeck, modelDeck);
103 return std::make_shared<mesh::Mesh>(temp_mesh);
104 }
105
106 throw std::runtime_error(
107 "Error: Unsupported in-built mesh: CreateMesh.Info = " +
108 zmeshDeck.d_createMeshInfo + " with geometry = " + zgeomDeck.d_geomName);
109}
A class for mesh data.
Definition mesh.h:53
void maybeWriteMeshFile(const inp::MeshDeck &zmeshDeck, const mesh::Mesh &mesh)
void generateBuiltinParticleMeshGmsh(const std::shared_ptr< geom::GeomObject > &geomObj, double h, const std::string &filenameStem, bool vtk_out, bool write_mesh_file, mesh::Mesh *out_mesh, const inp::MeshDeck *meshDeck, const inp::ModelDeck *modelDeck)
In-process Gmsh mesh from geom::GeomObject (after createGeomObject on deck / Particle data).
void createUniformMesh(mesh::Mesh *mesh_p, size_t dim, std::pair< std::vector< double >, std::vector< double > > box, std::vector< size_t > nGrid)
Creates uniform mesh for rectangle/cuboid domain.
Definition meshUtil.cpp:62
void removeNodesInBoxes(mesh::Mesh *mesh_p, const std::vector< std::vector< double > > &boxes)
Removes nodes lying inside any of the given axis-aligned boxes.
Definition meshUtil.cpp:214
std::string removeExtensionFromFile(std::string const &filename)
Remove extension from the filename Source - https://stackoverflow.com/a/24386991.
Definition io.h:296
Collection of methods useful in simulation.
Definition constants.h:14
std::shared_ptr< geom::GeomObject > d_geom_p
Zone geometry.
std::string d_geomName
Zone type.
double d_hMeshing
Target spacing for in-built meshers only (Gmsh uniform / uniform rectangle grid).
Definition meshDeck.h:38
bool d_writeMeshFile
If true (default), Gmsh-based create-mesh paths write a .msh file; set false for in-memory only.
Definition meshDeck.h:53
bool d_createMesh
Specify if we create mesh using in-built gmsh or in-built routine for uniform discretization of recta...
Definition meshDeck.h:44
std::vector< std::vector< double > > d_voidRegions
Axis-aligned boxes emptied from an in-built uniform grid (CreateMesh.Void_Regions: [xlo,...
Definition meshDeck.h:59
std::string d_createMeshInfo
Selector for in-built mesh creation (e.g. uniform rectangle, gmsh_builtin_mesh for built-in geometrie...
Definition meshDeck.h:50
std::string d_filename
Filename to read mesh data.
Definition meshDeck.h:29
size_t d_dim
Dimension.
Definition modelDeck.h:106

References mesh::createUniformMesh(), inp::MeshDeck::d_createMesh, inp::MeshDeck::d_createMeshInfo, inp::ModelDeck::d_dim, inp::MeshDeck::d_filename, geom::GeomData::d_geom_p, geom::GeomData::d_geomName, inp::MeshDeck::d_hMeshing, inp::MeshDeck::d_voidRegions, inp::MeshDeck::d_writeMeshFile, generateBuiltinParticleMeshGmsh(), anonymous_namespace{particleMesh.cpp}::maybeWriteMeshFile(), util::io::removeExtensionFromFile(), and mesh::removeNodesInBoxes().

Referenced by particle::createReferenceParticles().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fillMeshFromActiveGmshModel()

void mesh_gen::fillMeshFromActiveGmshModel ( mesh::Mesh mesh_p,
const inp::MeshDeck meshDeck,
const inp::ModelDeck modelDeck 
)

Fill PeriDEM Mesh from the active Gmsh model (after mesh::generate).

Definition at line 31 of file gmshMeshPipeline.cpp.

32 {
33
34 std::vector<std::size_t> nodeTags;
35 std::vector<double> coord;
36 std::vector<double> paramCoord;
37 gmsh::model::mesh::getNodes(nodeTags, coord, paramCoord);
38
39 std::unordered_map<std::size_t, std::size_t> tagToIdx;
40 tagToIdx.reserve(nodeTags.size());
41 for (size_t i = 0; i < nodeTags.size(); ++i)
42 tagToIdx[nodeTags[i]] = i;
43
44 std::vector<util::Point> nodes(nodeTags.size());
45 for (size_t i = 0; i < nodeTags.size(); ++i)
46 nodes[i] = util::Point(coord[3 * i], coord[3 * i + 1], coord[3 * i + 2]);
47
48 std::vector<int> elementTypes;
49 std::vector<std::vector<std::size_t>> elementTags, elementNodeTags;
50 gmsh::model::mesh::getElements(elementTypes, elementTags, elementNodeTags, -1, -1);
51
52 bool hasTetra = false;
53 for (size_t t = 0; t < elementTypes.size(); ++t) {
54 if (elementTypes[t] == util::msh_type_tetrahedron) {
55 hasTetra = true;
56 break;
57 }
58 }
59
60 if (hasTetra) {
61 std::vector<size_t> enc;
62 for (size_t t = 0; t < elementTypes.size(); ++t) {
63 if (elementTypes[t] != util::msh_type_tetrahedron)
64 continue;
65 const auto &nt = elementNodeTags[t];
66 for (size_t j = 0; j < nt.size(); j += 4) {
67 enc.push_back(tagToIdx.at(nt[j]));
68 enc.push_back(tagToIdx.at(nt[j + 1]));
69 enc.push_back(tagToIdx.at(nt[j + 2]));
70 enc.push_back(tagToIdx.at(nt[j + 3]));
71 }
72 }
73 if (enc.empty())
74 throw std::runtime_error("fillMeshFromActiveGmshModel: no Gmsh tetrahedron elements found.");
75 mesh_p->loadFromTetraElements3D(std::move(nodes), std::move(enc), meshDeck, modelDeck);
76 return;
77 }
78
79 std::vector<size_t> enc;
80 for (size_t t = 0; t < elementTypes.size(); ++t) {
81 if (elementTypes[t] != util::msh_type_triangle)
82 continue;
83 const auto &nt = elementNodeTags[t];
84 for (size_t j = 0; j < nt.size(); j += 3) {
85 enc.push_back(tagToIdx.at(nt[j]));
86 enc.push_back(tagToIdx.at(nt[j + 1]));
87 enc.push_back(tagToIdx.at(nt[j + 2]));
88 }
89 }
90
91 if (enc.empty())
92 throw std::runtime_error("fillMeshFromActiveGmshModel: no Gmsh triangle elements found.");
93
94 mesh_p->loadFromTriangleElements2D(std::move(nodes), std::move(enc), meshDeck, modelDeck);
95}
void loadFromTetraElements3D(std::vector< util::Point > nodes, std::vector< size_t > enc, const inp::MeshDeck *meshDeck, const inp::ModelDeck *modelDeck)
Populate mesh from 3D tetrahedron data (0-based node indices in enc) without reading a file.
Definition mesh.cpp:209
void loadFromTriangleElements2D(std::vector< util::Point > nodes, std::vector< size_t > enc, const inp::MeshDeck *meshDeck, const inp::ModelDeck *modelDeck)
Populate mesh from 2D triangle data (0-based node indices in enc) without reading a file.
Definition mesh.cpp:171
static const int msh_type_triangle
Integer flag for triangle element.
static const int msh_type_tetrahedron
Integer flag for tetrahedron element.
A structure to represent 3d vectors.
Definition point.h:30

References mesh::Mesh::loadFromTetraElements3D(), mesh::Mesh::loadFromTriangleElements2D(), util::msh_type_tetrahedron, and util::msh_type_triangle.

Referenced by generateBuiltinParticleMeshGmsh().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generateBuiltinParticleMeshGmsh()

void mesh_gen::generateBuiltinParticleMeshGmsh ( const std::shared_ptr< geom::GeomObject > &  geomObj,
double  h,
const std::string &  filenameStem,
bool  vtk_out,
bool  write_mesh_file,
mesh::Mesh out_mesh,
const inp::MeshDeck meshDeck,
const inp::ModelDeck modelDeck 
)

In-process Gmsh mesh from geom::GeomObject (after createGeomObject on deck / Particle data).

Single entry point: geometry is only the shared object; mesh size, VTK, file stem, and write flags are explicit. Simulation code unpacks MeshDeck + GeomData.d_geom_p at the call site.

Definition at line 66 of file meshGenerator.cpp.

69 {
70 // Geometry is only `geomObj`; decks supply mesh/model metadata for `out_mesh` fill — no parallel param arrays.
71
72 if (!geomObj)
73 throw std::runtime_error("generateBuiltinParticleMeshGmsh: GeomObject pointer is null.");
74
75 const std::string &geomName = geomObj->d_name;
76
77 // AnnulusGeomObject always uses d_name == "annulus_object" (deck may say
78 // circle_minus_circle / rectangle_minus_rectangle / etc.).
79 bool known = (geomName == "annulus_object");
80 if (!known) {
81 for (const auto &g : geom::getAcceptableGeometries()) {
82 if (g == geomName) {
83 known = true;
84 break;
85 }
86 }
87 }
88 if (!known)
89 throw std::runtime_error(
90 "generateBuiltinParticleMeshGmsh: geometry type is not in geom::acceptable_geometries.");
91
92 gmsh::initialize();
93 gmsh::option::setNumber("Mesh.MshFileVersion", 2.2);
94 gmsh::clear();
95
96 try {
98 // OCC-built 3D shapes (e.g. sphere, ellipsoid) do not attach `h` to geometry; without this,
99 // Gmsh uses a default size and can produce far too few tets so mesh spacing > PD horizon.
100 if (h > 0.) {
101 gmsh::option::setNumber("Mesh.MeshSizeMin", h);
102 gmsh::option::setNumber("Mesh.MeshSizeMax", h);
103 }
104 const int genDim = gmshMeshGenerateDim(modelDeck);
105 if (genDim == 2) {
106 // Frontal-Delaunay (6) is Gmsh's 2D default and, with MeshSizeMin=Max=h,
107 // reproduces the v0.1.0 circle disk (hmin ≈ 0.142 mm for h = R/5).
108 // Delaunay (5) on the same circle is ~15% finer in min nodal spacing and
109 // was only needed for GEO-kernel polygons (frontal can fail on those).
110 const std::string &n = geomObj->d_name;
111 const bool geo_polygon =
112 n == "square" || n == "rectangle" || n == "triangle" || n == "hexagon" ||
113 n == "drum2d" || n == "open_rect_channel_2d";
114 // complex (OCC cuts) and annuli use Frontal-Delaunay (6)
115 gmsh::option::setNumber("Mesh.Algorithm", geo_polygon ? 5 : 6);
116 }
117 gmsh::model::mesh::generate(genDim);
118 } catch (...) {
119 gmsh::finalize();
120 throw;
121 }
122
123 if (!write_mesh_file && out_mesh == nullptr)
124 throw std::runtime_error(
125 "generateBuiltinParticleMeshGmsh: when write_mesh_file is false, out_mesh is required.");
126
127 if (out_mesh != nullptr) {
128 if (meshDeck == nullptr || modelDeck == nullptr)
129 throw std::runtime_error(
130 "generateBuiltinParticleMeshGmsh: meshDeck and modelDeck are required when out_mesh is set.");
131 fillMeshFromActiveGmshModel(out_mesh, meshDeck, modelDeck);
132 }
133
134 if (write_mesh_file) {
135 if (filenameStem.empty())
136 throw std::runtime_error(
137 "generateBuiltinParticleMeshGmsh: non-empty filename stem is required when writing a .msh file.");
138 const std::string mshPath = filenameStem + ".msh";
139 if (modelDeck != nullptr && modelDeck->d_dim == 2 && out_mesh != nullptr)
140 writeGmshMsh22From2DTriangleMesh(*out_mesh, mshPath);
141 else
142 gmsh::write(mshPath);
143 }
144
145 if (vtk_out) {
146 if (filenameStem.empty())
147 throw std::runtime_error(
148 "generateBuiltinParticleMeshGmsh: non-empty filename stem is required for VTK output.");
149 gmsh::write(filenameStem + ".vtk");
150 }
151
152 gmsh::finalize();
153}
void writeGmshMsh22From2DTriangleMesh(const mesh::Mesh &m, const std::string &path)
void fillMeshFromActiveGmshModel(mesh::Mesh *mesh_p, const inp::MeshDeck *meshDeck, const inp::ModelDeck *modelDeck)
void buildGmshGeometryInCurrentModel(const geom::GeomObject &g, double h)
int gmshMeshGenerateDim(const inp::ModelDeck *modelDeck)

References buildGmshGeometryInCurrentModel(), inp::ModelDeck::d_dim, fillMeshFromActiveGmshModel(), geom::getAcceptableGeometries(), and gmshMeshGenerateDim().

Referenced by anonymous_namespace{testMeshGen.cpp}::builtinMeshCheckForGeometry(), createParticleMesh(), getInputJson(), and anonymous_namespace{testMeshGen.cpp}::testCircleMeshWritesFiles().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ gmshMeshGenerateDim()

int mesh_gen::gmshMeshGenerateDim ( const inp::ModelDeck modelDeck)

Meshing dimension for Gmsh::generate (1–3), aligned with ModelDeck::d_dim.

Definition at line 22 of file gmshMeshPipeline.cpp.

22 {
23 if (modelDeck == nullptr)
24 return 3;
25 const int d = static_cast<int>(modelDeck->d_dim);
26 if (d < 1 || d > 3)
27 return 3;
28 return d;
29}

References inp::ModelDeck::d_dim.

Referenced by generateBuiltinParticleMeshGmsh().

Here is the caller graph for this function:

◆ physicalGroupsWallOpenFromFace3D()

void mesh_gen::physicalGroupsWallOpenFromFace3D ( int  volumeTag,
int  openFace,
const util::Point lo,
const util::Point hi,
double  t,
double  tol,
const std::string &  physWall = "wall",
const std::string &  physOpen = "open" 
)

After a 3D volume is built in the current Gmsh model, partition its boundary surfaces into physical groups "wall" vs "open" for an open cuboidal shell (one outer face slab removed).

Parameters
volumeTagGmsh volume tag (dimension 3).
openFaceSame convention as geom::OpenCuboidChannel3D::d_openFace (0..5).
loOuter AABB low corner (world axes).
hiOuter AABB high corner.
tWall thickness (used to locate the opening plane).
tolLength tolerance for classifying nearly planar faces.
physWallPhysical name for wall surfaces.
physOpenPhysical name for opening / cavity-facing rim surfaces.

Definition at line 32 of file openBoundaryWalls3D.cpp.

34 {
35
36 const double x0 = lo.d_x, y0 = lo.d_y, z0 = lo.d_z;
37 const double x1 = hi.d_x, y1 = hi.d_y, z1 = hi.d_z;
38 const double Lx = x1 - x0;
39 const double Ly = y1 - y0;
40 const double Lz = z1 - z0;
41 const double horizTol = std::max(tol, 1.0e-9 * std::max({Lx, Ly, Lz, 1.0}));
42
43 std::vector<std::pair<int, int>> bnd;
44 // Request unoriented boundary entities so tags are always valid entity IDs.
45 gmsh::model::getBoundary({{3, volumeTag}}, bnd, false, false);
46
47 std::vector<int> wallTags;
48 std::vector<int> openTags;
49 wallTags.reserve(bnd.size());
50 openTags.reserve(bnd.size());
51
52 for (const auto &pr : bnd) {
53 if (pr.first != 2)
54 continue;
55 const int surfTag = std::abs(pr.second);
56 double xmin = 0., ymin = 0., zmin = 0., xmax = 0., ymax = 0., zmax = 0.;
57 gmsh::model::getBoundingBox(pr.first, surfTag, xmin, ymin, zmin, xmax, ymax, zmax);
58 const double dx = xmax - xmin;
59 const double dy = ymax - ymin;
60 const double dz = zmax - zmin;
61 const double cx = 0.5 * (xmin + xmax);
62 const double cy = 0.5 * (ymin + ymax);
63 const double cz = 0.5 * (zmin + zmax);
64 const double emin = minEdge2D(dx, dy, dz);
65 const double emax = maxEdge2D(dx, dy, dz);
66 const bool thin = emin < horizTol * std::max(1.0, 0.1 * emax);
67
68 bool isOpen = false;
69 if (thin) {
70 switch (openFace) {
71 case 0: // +x
72 isOpen = cx > x1 - t - 2. * horizTol && std::abs(dx - t) < 0.25 * t + horizTol;
73 break;
74 case 1: // -x
75 isOpen = cx < x0 + t + 2. * horizTol && std::abs(dx - t) < 0.25 * t + horizTol;
76 break;
77 case 2: // +y
78 isOpen = cy > y1 - t - 2. * horizTol && std::abs(dy - t) < 0.25 * t + horizTol;
79 break;
80 case 3: // -y
81 isOpen = cy < y0 + t + 2. * horizTol && std::abs(dy - t) < 0.25 * t + horizTol;
82 break;
83 case 4: // +z — opening at top: rim / horizontal faces near z1 or cavity top
84 isOpen = cz > z1 - t - 2. * horizTol && dz < horizTol * 10.;
85 break;
86 case 5: // -z
87 isOpen = cz < z0 + t + 2. * horizTol && dz < horizTol * 10.;
88 break;
89 default:
90 break;
91 }
92 }
93
94 if (isOpen)
95 openTags.push_back(surfTag);
96 else
97 wallTags.push_back(surfTag);
98 }
99
100 if (!wallTags.empty()) {
101 const int g = gmsh::model::addPhysicalGroup(2, wallTags, -1);
102 gmsh::model::setPhysicalName(2, g, physWall);
103 }
104 if (!openTags.empty()) {
105 const int g = gmsh::model::addPhysicalGroup(2, openTags, -1);
106 gmsh::model::setPhysicalName(2, g, physOpen);
107 }
108}

References util::Point::d_x, util::Point::d_y, and util::Point::d_z.

Referenced by mesh_gen::anonymous_namespace{builtinGmshGeometry.cpp}::buildOpenCuboidChannel3DGeo().

Here is the caller graph for this function:

◆ physicalGroupsWallOpenFromY2D()

void mesh_gen::physicalGroupsWallOpenFromY2D ( int  surfaceTag,
double  yOpen,
double  tol,
const std::string &  physWall = "wall",
const std::string &  physOpen = "open" 
)

After a 2D plane surface is built in the current Gmsh model, partition its boundary curves into physical groups: "wall" vs "open" for a top opening at +y.

Curves classified as "open" are nearly horizontal segments whose elevation is near yOpen (outer top of a closed rectangular annulus). U-channels have no such edge (the opening is a gap), so all curves are typically "wall".

Parameters
surfaceTagGmsh surface tag (dimension 2).
yOpenReference y-coordinate of the intended open (top) side.
tolLength tolerance for "horizontal" vs slanted edges.

Definition at line 18 of file openBoundaryWalls2D.cpp.

20 {
21
22 std::vector<std::pair<int, int>> bnd;
23 gmsh::model::getBoundary({{2, surfaceTag}}, bnd, false);
24
25 std::vector<int> wallTags;
26 std::vector<int> openTags;
27 wallTags.reserve(bnd.size());
28 openTags.reserve(bnd.size());
29
30 const double horizEps = std::max(tol * 1.0e-3, 1.0e-12 * (1.0 + std::abs(yOpen)));
31
32 for (const auto &pr : bnd) {
33 if (pr.first != 1)
34 continue;
35 double xmin = 0., ymin = 0., zmin = 0., xmax = 0., ymax = 0., zmax = 0.;
36 gmsh::model::getBoundingBox(pr.first, pr.second, xmin, ymin, zmin, xmax, ymax, zmax);
37 const double dy = ymax - ymin;
38 const double yc = 0.5 * (ymin + ymax);
39 const bool nearlyHorizontal = dy < horizEps;
40 const bool nearTopOpen = yc >= yOpen - tol && nearlyHorizontal;
41 if (nearTopOpen)
42 openTags.push_back(pr.second);
43 else
44 wallTags.push_back(pr.second);
45 }
46
47 if (!wallTags.empty()) {
48 const int g = gmsh::model::addPhysicalGroup(1, wallTags, -1);
49 gmsh::model::setPhysicalName(1, g, physWall);
50 }
51 if (!openTags.empty()) {
52 const int g = gmsh::model::addPhysicalGroup(1, openTags, -1);
53 gmsh::model::setPhysicalName(1, g, physOpen);
54 }
55}

Referenced by mesh_gen::anonymous_namespace{builtinGmshGeometry.cpp}::buildOpenRectChannel2DGeo().

Here is the caller graph for this function: