PeriDEM 0.3.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
meshGenerator.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 "meshGenerator.h"
12#include "builtinGmshGeometry.h"
13#include "gmshMeshPipeline.h"
14#include "geom/geomObjects.h"
16#include "inp/meshDeck.h"
17#include "inp/modelDeck.h"
18#include "mesh/mesh.h"
19#include "util/feElementDefs.h"
20#include <fstream>
21#include <gmsh.h>
22#include <iomanip>
23#include <stdexcept>
24#include <string>
25
26namespace mesh_gen {
27
28namespace {
29
31void writeGmshMsh22From2DTriangleMesh(const mesh::Mesh &m, const std::string &path) {
33 throw std::runtime_error("writeGmshMsh22From2DTriangleMesh: only triangle meshes are supported.");
34 if (m.getDimension() != 2)
35 throw std::runtime_error("writeGmshMsh22From2DTriangleMesh: dimension must be 2.");
36
37 const auto &nodes = m.getNodes();
38 const auto &enc = m.getElementConnectivities();
39 const size_t n = nodes.size();
40 const size_t ne = enc.size() / 3;
41
42 std::ofstream out(path);
43 if (!out)
44 throw std::runtime_error("writeGmshMsh22From2DTriangleMesh: cannot open " + path);
45
46 out << std::setprecision(17);
47 out << "$MeshFormat\n2.2 0 8\n$EndMeshFormat\n";
48 out << "$Nodes\n" << n << "\n";
49 for (size_t i = 0; i < n; ++i) {
50 const auto &p = nodes[i];
51 out << (i + 1) << " " << p.d_x << " " << p.d_y << " 0\n";
52 }
53 out << "$EndNodes\n";
54 out << "$Elements\n" << ne << "\n";
55 for (size_t e = 0; e < ne; ++e) {
56 const size_t a = enc[3 * e] + 1;
57 const size_t b = enc[3 * e + 1] + 1;
58 const size_t c = enc[3 * e + 2] + 1;
59 out << (e + 1) << " 2 2 0 1 " << a << " " << b << " " << c << "\n";
60 }
61 out << "$EndElements\n";
62}
63
64} // namespace
65
66void generateBuiltinParticleMeshGmsh(const std::shared_ptr<geom::GeomObject> &geomObj, double h,
67 const std::string &filenameStem, bool vtk_out,
68 bool write_mesh_file, mesh::Mesh *out_mesh,
69 const inp::MeshDeck *meshDeck, const inp::ModelDeck *modelDeck) {
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}
154
155} // namespace mesh_gen
A class for mesh data.
Definition mesh.h:53
const std::vector< size_t > & getElementConnectivities() const
Get the reference to element-node connectivity data.
Definition mesh.h:236
const std::vector< util::Point > & getNodes() const
Get the nodes data.
Definition mesh.h:135
size_t getDimension() const
Get the dimension of the domain.
Definition mesh.h:85
size_t getElementType() const
Get the type of element in mesh.
Definition mesh.h:109
static const int vtk_type_triangle
Integer flag for triangle element.
const std::vector< std::string > & getAcceptableGeometries()
Returns list of acceptable geometries for PeriDEM simulation.
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)
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).
int gmshMeshGenerateDim(const inp::ModelDeck *modelDeck)
Structure to read and store mesh related input data.
Definition meshDeck.h:26
Structure to read and store model related input data.
Definition modelDeck.h:25
size_t d_dim
Dimension.
Definition modelDeck.h:106