PeriDEM 0.3.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
builtinGmshGeometry.cpp
Go to the documentation of this file.
1/*
2 * -------------------------------------------
3 * Copyright (c) 2021 - 2026 Prashant K. Jha
4 * -------------------------------------------
5 * PeriDEM https://github.com/prashjha/PeriDEM
6 *
7 * Distributed under the Boost Software License, Version 1.0. (See accompanying
8 * file LICENSE)
9 */
10
11#include "builtinGmshGeometry.h"
12#include "annulusMesh2D.h"
13#include "annulusMesh3D.h"
14#include "openBoundaryWalls2D.h"
15#include "primitiveOccMesh.h"
17#include "geom/geomObjects.h"
20#include "openBoundaryWalls3D.h"
21#include "util/point.h"
22#include <cmath>
23#include <gmsh.h>
24#include <stdexcept>
25#include <vector>
26
27namespace mesh_gen {
28namespace {
29
30void meshPolygon2DGeoFromVertices(const std::vector<util::Point> &verts, double h) {
31 if (verts.size() < 3)
32 throw std::runtime_error("meshPolygon2DGeoFromVertices: need at least 3 vertices.");
33
34 std::vector<int> pids;
35 pids.reserve(verts.size());
36 for (const auto &v : verts)
37 pids.push_back(gmsh::model::geo::addPoint(v.d_x, v.d_y, v.d_z, h));
38
39 std::vector<int> lines;
40 const size_t n = verts.size();
41 lines.reserve(n);
42 for (size_t i = 0; i < n; ++i)
43 lines.push_back(gmsh::model::geo::addLine(pids[i], pids[(i + 1) % n]));
44
45 int cl = gmsh::model::geo::addCurveLoop(lines);
46 gmsh::model::geo::addPlaneSurface({cl});
47 gmsh::model::geo::synchronize();
48}
49
52 std::vector<std::pair<int, int>> ents;
53 gmsh::model::getEntities(ents, 2);
54 if (!ents.empty()) {
55 const double tol = std::max(1.0e-9, 1.0e-6 * std::max(g.d_y1 - g.d_y0, g.d_x1 - g.d_x0));
56 physicalGroupsWallOpenFromY2D(ents.back().second, g.d_y1, tol);
57 }
58}
59
60static int firstVolumeTagFromCut(const std::vector<std::pair<int, int>> &ov) {
61 for (const auto &pr : ov)
62 if (pr.first == 3)
63 return pr.second;
64 return -1;
65}
66
72 const double x0 = g.d_lo.d_x, y0 = g.d_lo.d_y, z0 = g.d_lo.d_z;
73 const double x1 = g.d_hi.d_x, y1 = g.d_hi.d_y, z1 = g.d_hi.d_z;
74 const double t = g.d_t;
75 const double hx = 0.5 * t, hy = 0.5 * t, hz = 0.5 * t;
76 switch (g.d_openFace) {
77 case 0:
78 return {x0 + hx, y0 + hy, z0 + hz};
79 case 1:
80 return {x1 - hx, y0 + hy, z0 + hz};
81 case 2:
82 return {x0 + hx, y0 + hy, z0 + hz};
83 case 3:
84 return {x0 + hx, y1 - hy, z0 + hz};
85 case 4:
86 return {x0 + hx, y0 + hy, z0 + hz};
87 case 5:
88 return {x0 + hx, y0 + hy, z1 - hz};
89 default:
90 throw std::runtime_error("embedPointOpenCuboidChannel3DForMesh: open_face must be 0..5.");
91 }
92}
93
96 const double x0 = g.d_lo.d_x, y0 = g.d_lo.d_y, z0 = g.d_lo.d_z;
97 const double x1 = g.d_hi.d_x, y1 = g.d_hi.d_y, z1 = g.d_hi.d_z;
98 const double Lx = x1 - x0, Ly = y1 - y0, Lz = z1 - z0;
99 const double t = g.d_t;
100 const int face = g.d_openFace;
101
102 const int out_vol = gmsh::model::occ::addBox(x0, y0, z0, Lx, Ly, Lz);
103 gmsh::model::occ::synchronize();
104 const int in_vol = gmsh::model::occ::addBox(x0 + t, y0 + t, z0 + t, Lx - 2. * t, Ly - 2. * t,
105 Lz - 2. * t);
106 gmsh::model::occ::synchronize();
107 std::vector<std::pair<int, int>> ov;
108 std::vector<std::vector<std::pair<int, int>>> ovv;
109 gmsh::model::occ::cut({{3, out_vol}}, {{3, in_vol}}, ov, ovv, -1, true, true);
110 gmsh::model::occ::synchronize();
111 gmsh::model::occ::removeAllDuplicates();
112 gmsh::model::occ::synchronize();
113
114 int shell = firstVolumeTagFromCut(ov);
115 if (shell < 0) {
116 std::vector<std::pair<int, int>> ents;
117 gmsh::model::getEntities(ents, 3);
118 if (!ents.empty())
119 shell = ents.back().second;
120 }
121 if (shell < 0)
122 throw std::runtime_error("buildOpenCuboidChannel3DGeo: no volume after outer−inner cut.");
123
124 int slab = -1;
125 switch (face) {
126 case 0:
127 slab = gmsh::model::occ::addBox(x1 - t, y0, z0, t, Ly, Lz);
128 break;
129 case 1:
130 slab = gmsh::model::occ::addBox(x0, y0, z0, t, Ly, Lz);
131 break;
132 case 2:
133 slab = gmsh::model::occ::addBox(x0, y1 - t, z0, Lx, t, Lz);
134 break;
135 case 3:
136 slab = gmsh::model::occ::addBox(x0, y0, z0, Lx, t, Lz);
137 break;
138 case 4:
139 slab = gmsh::model::occ::addBox(x0, y0, z1 - t, Lx, Ly, t);
140 break;
141 case 5:
142 slab = gmsh::model::occ::addBox(x0, y0, z0, Lx, Ly, t);
143 break;
144 default:
145 throw std::runtime_error("buildOpenCuboidChannel3DGeo: open_face must be 0..5.");
146 }
147 gmsh::model::occ::synchronize();
148
149 std::vector<std::pair<int, int>> ov2;
150 gmsh::model::occ::cut({{3, shell}}, {{3, slab}}, ov2, ovv, -1, true, true);
151 gmsh::model::occ::synchronize();
152 gmsh::model::occ::removeAllDuplicates();
153 gmsh::model::occ::synchronize();
154
155 int vol = firstVolumeTagFromCut(ov2);
156 if (vol < 0) {
157 std::vector<std::pair<int, int>> ents;
158 gmsh::model::getEntities(ents, 3);
159 if (!ents.empty())
160 vol = ents.back().second;
161 }
162 if (vol < 0)
163 throw std::runtime_error("buildOpenCuboidChannel3DGeo: no volume after removing opening slab.");
164
166 const int p = gmsh::model::occ::addPoint(c.d_x, c.d_y, c.d_z, h);
167 gmsh::model::occ::synchronize();
168 gmsh::model::mesh::embed(0, {p}, 3, vol);
169 gmsh::model::occ::synchronize();
170
171 const double tol = std::max(1.0e-9, 1.0e-6 * std::max({Lx, Ly, Lz}));
172 physicalGroupsWallOpenFromFace3D(vol, face, g.d_lo, g.d_hi, g.d_t, tol);
173}
174
176std::vector<util::Point> drum2dPolygonBoundary(const geom::Drum2D &d) {
177 static const int kOrder[] = {3, 2, 1, 0, 5, 4};
178 std::vector<util::Point> poly;
179 poly.reserve(6);
180 for (int k : kOrder)
181 poly.push_back(d.d_vertices[static_cast<size_t>(k)]);
182 return poly;
183}
184
185void buildCircleOcc(const geom::Circle &c, double h) {
186 const int circ =
187 gmsh::model::occ::addCircle(c.d_x.d_x, c.d_x.d_y, c.d_x.d_z, c.d_r);
188 const int cl = gmsh::model::occ::addCurveLoop({circ});
189 const int s = gmsh::model::occ::addPlaneSurface({cl});
190 const int p = gmsh::model::occ::addPoint(c.d_x.d_x, c.d_x.d_y, c.d_x.d_z, h);
191 gmsh::model::occ::synchronize();
192 gmsh::model::mesh::embed(0, {p}, 2, s);
193}
194
196 gmsh::model::occ::addSphere(s.d_x.d_x, s.d_x.d_y, s.d_x.d_z, s.d_r);
197 gmsh::model::occ::synchronize();
198}
199
201 auto bx = g.box();
202 const auto &lo = bx.first;
203 const auto &hi = bx.second;
204 gmsh::model::occ::addBox(lo.d_x, lo.d_y, lo.d_z, hi.d_x - lo.d_x, hi.d_y - lo.d_y,
205 hi.d_z - lo.d_z);
206 gmsh::model::occ::synchronize();
207}
208
212 if (c.d_obj.empty() || c.d_objFlagInt.size() != c.d_obj.size())
213 throw std::runtime_error("buildComplexRectangles2DOcc: empty or mismatched flags.");
214 if (c.d_objFlagInt[0] != 1)
215 throw std::runtime_error("buildComplexRectangles2DOcc: first object must be plus.");
216
217 auto surfaceTag = [&](const geom::GeomObject &o) -> int {
218 if (o.d_name == "rectangle") {
219 const auto &r = static_cast<const geom::Rectangle &>(o);
220 const auto &lo = r.d_vertices[0];
221 const auto &hi = r.d_vertices[2];
222 return gmsh::model::occ::addRectangle(lo.d_x, lo.d_y, lo.d_z, hi.d_x - lo.d_x,
223 hi.d_y - lo.d_y);
224 }
225 if (o.d_name == "triangle") {
226 const auto &t = static_cast<const geom::Triangle &>(o);
227 std::vector<int> pts(3), lines(3);
228 for (int i = 0; i < 3; ++i)
229 pts[i] = gmsh::model::occ::addPoint(t.d_vertices[i].d_x, t.d_vertices[i].d_y,
230 t.d_vertices[i].d_z);
231 for (int i = 0; i < 3; ++i)
232 lines[i] = gmsh::model::occ::addLine(pts[i], pts[(i + 1) % 3]);
233 const int cl = gmsh::model::occ::addCurveLoop(lines);
234 return gmsh::model::occ::addPlaneSurface({cl});
235 }
236 throw std::runtime_error(
237 "buildComplexRectangles2DOcc: only rectangle/triangle parts supported (got " +
238 o.d_name + ").");
239 };
240
241 if (c.d_obj[0]->d_name != "rectangle")
242 throw std::runtime_error("buildComplexRectangles2DOcc: outer object must be a rectangle.");
243
244 int base = surfaceTag(*c.d_obj[0]);
245 gmsh::model::occ::synchronize();
246 std::vector<std::pair<int, int>> tools;
247 for (size_t i = 1; i < c.d_obj.size(); ++i) {
248 if (c.d_objFlagInt[i] != -1)
249 throw std::runtime_error("buildComplexRectangles2DOcc: only plus then minus cuts supported.");
250 tools.push_back({2, surfaceTag(*c.d_obj[i])});
251 }
252 gmsh::model::occ::synchronize();
253
254 std::vector<std::pair<int, int>> ov;
255 std::vector<std::vector<std::pair<int, int>>> ovv;
256 if (!tools.empty()) {
257 gmsh::model::occ::cut({{2, base}}, tools, ov, ovv, -1, true, true);
258 gmsh::model::occ::synchronize();
259 gmsh::model::occ::removeAllDuplicates();
260 gmsh::model::occ::synchronize();
261 } else {
262 ov = {{2, base}};
263 }
264
265 int surface_tag = -1;
266 for (const auto &pr : ov)
267 if (pr.first == 2) {
268 surface_tag = pr.second;
269 break;
270 }
271 if (surface_tag < 0) {
272 std::vector<std::pair<int, int>> ents;
273 gmsh::model::getEntities(ents, 2);
274 if (!ents.empty())
275 surface_tag = ents.back().second;
276 }
277 if (surface_tag < 0)
278 throw std::runtime_error("buildComplexRectangles2DOcc: no surface after cut.");
279
280 // Embed a point in the solid (center ligament for KW).
281 const auto bx = c.d_obj[0]->box();
282 const double cx = 0.5 * (bx.first.d_x + bx.second.d_x);
283 const double cy = 0.5 * (bx.first.d_y + bx.second.d_y);
284 const double cz = bx.first.d_z;
285 const int p = gmsh::model::occ::addPoint(cx, cy, cz, h);
286 gmsh::model::occ::synchronize();
287 gmsh::model::mesh::embed(0, {p}, 2, surface_tag);
288 gmsh::model::occ::synchronize();
289}
290
291} // namespace
292
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}
341
342} // namespace mesh_gen
Defines annulus rectangle.
Defines circle.
double d_r
Radius.
util::Point d_x
Center.
Defines complex geometrical object.
std::vector< int > d_objFlagInt
Object integer flags. Here, +1 means object is filling and -1 means object is void.
std::vector< std::shared_ptr< GeomObject > > d_obj
Object.
Defines cylinder.
Defines Drum2D.
std::vector< util::Point > d_vertices
Vertices.
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 abstract geometrical domain.
virtual std::pair< util::Point, util::Point > box() const
Computes the bounding box of object.
const std::string d_name
name of object
Defines Hexagon.
Hollow axis-aligned cuboid shell with uniform wall thickness and one outer face open.
int d_openFace
Which outer face is open: 0=+x, 1=−x, 2=+y, 3=−y, 4=+z, 5=−z (world axes after transform).
util::Point d_lo
Outer AABB low corner.
double d_t
Wall thickness.
util::Point d_hi
Outer AABB high corner.
2D U-shaped cavity: thick rectangular frame with the top (+y) side open.
std::vector< util::Point > d_vertices
CCW boundary of the U-shaped solid (10 vertices, uniform thickness t).
Defines Rectangle.
std::vector< util::Point > d_vertices
Vertices.
Defines sphere.
double d_r
Radius.
util::Point d_x
Center.
Defines Square.
Defines Triangle.
void buildOpenCuboidChannel3DGeo(const geom::OpenCuboidChannel3D &g, double h)
void buildComplexRectangles2DOcc(const geom::ComplexGeomObject &c, double h)
void meshPolygon2DGeoFromVertices(const std::vector< util::Point > &verts, double h)
void buildOpenRectChannel2DGeo(const geom::OpenRectChannel2D &g, double h)
static int firstVolumeTagFromCut(const std::vector< std::pair< int, int > > &ov)
std::vector< util::Point > drum2dPolygonBoundary(const geom::Drum2D &d)
static util::Point embedPointOpenCuboidChannel3DForMesh(const geom::OpenCuboidChannel3D &g)
void buildEllipsoidOcc(const geom::Ellipsoid &e)
void buildGmshGeometryInCurrentModel(const geom::GeomObject &g, double h)
void buildAnnulus3DInCurrentModel(const geom::AnnulusGeomObject &a, double h)
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)
void buildAnnulus2DInCurrentModel(const geom::AnnulusGeomObject &a, double h)
void buildEllipseOcc(const geom::Ellipse &e, double h)
void buildCylinderOcc(const geom::Cylinder &c)
void physicalGroupsWallOpenFromY2D(int surfaceTag, double yOpen, double tol, const std::string &physWall, const std::string &physOpen)
A structure to represent 3d vectors.
Definition point.h:30
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