19 #include "axom/core.hpp"
28 std::string msg = std::format(
"Opening mesh file: '{0}'", mesh_file);
32 smith::logger::flush();
33 if (!axom::utilities::filesystem::pathExists(mesh_file)) {
34 msg = std::format(
"Given mesh file does not exist: '{0}'", mesh_file);
40 mfem::named_ifgzstream imesh(mesh_file);
43 smith::logger::flush();
44 std::string err_msg = std::format(
"Can not open mesh file: '{0}'", mesh_file);
45 SLIC_ERROR_ROOT(err_msg);
48 return mfem::Mesh{imesh, 1, 1,
true};
58 int num_vertices = mesh.GetNV();
59 int dim = mesh.SpaceDimension();
61 mfem::Vector vertices;
62 mesh.GetVertices(vertices);
63 mfem::Vector vertex(dim);
64 for (
int i = 0; i < num_vertices; i++) {
65 for (
int d = 0; d < dim; d++) {
66 vertex(d) = vertices[d * num_vertices + i];
69 double L1_norm = vertex.Norml1();
70 double L2_norm = vertex.Norml2();
71 vertex *= (L2_norm < 1.0e-6) ? 0.0 : (L1_norm / L2_norm);
73 for (
int d = 0; d < dim; d++) {
74 vertices[d * num_vertices + i] = vertex(d);
77 mesh.SetVertices(vertices);
82 static constexpr
int dim = 2;
83 static constexpr
int num_elems = 4;
84 static constexpr
int num_vertices = 5;
85 static constexpr
int num_boundary_elements = 4;
87 static constexpr
double vertices[num_vertices][dim] = {{0, 0}, {1, 0}, {0, 1}, {-1, 0}, {0, -1}};
88 static constexpr
int triangles[num_elems][3] = {{1, 2, 0}, {2, 3, 0}, {3, 4, 0}, {4, 1, 0}};
89 static constexpr
int segments[num_elems][2] = {{1, 2}, {2, 3}, {3, 4}, {4, 1}};
91 auto mesh = mfem::Mesh(dim, num_vertices, num_elems, num_boundary_elements);
93 for (
auto vertex : vertices) {
94 mesh.AddVertex(vertex);
96 for (
auto triangle : triangles) {
97 mesh.AddTriangle(triangle);
99 for (
auto segment : segments) {
100 mesh.AddBdrSegment(segment);
102 mesh.FinalizeTriMesh();
104 while (mesh.GetNE() < (0.5 * approx_number_of_elements)) {
105 mesh.UniformRefinement();
115 static constexpr
int dim = 3;
116 static constexpr
int num_elems = 8;
117 static constexpr
int num_vertices = 7;
118 static constexpr
int num_boundary_elements = 8;
120 static constexpr
double vertices[num_vertices][dim] = {{0, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, 0, -1},
121 {0, 0, 1}, {0, -1, 0}, {1, 0, 0}};
122 static constexpr
int triangles[num_elems][3] = {{4, 5, 6}, {4, 6, 2}, {4, 2, 1}, {4, 1, 5},
123 {5, 1, 3}, {5, 3, 6}, {3, 1, 2}, {6, 3, 2}};
124 static constexpr
int tetrahedra[num_elems][4] = {{0, 4, 5, 6}, {0, 4, 6, 2}, {0, 4, 2, 1}, {0, 4, 1, 5},
125 {0, 5, 1, 3}, {0, 5, 3, 6}, {0, 3, 1, 2}, {0, 6, 3, 2}};
127 auto mesh = mfem::Mesh(dim, num_vertices, num_elems, num_boundary_elements);
129 for (
auto vertex : vertices) {
130 mesh.AddVertex(vertex);
132 for (
auto tetrahedron : tetrahedra) {
133 mesh.AddTet(tetrahedron);
135 for (
auto triangle : triangles) {
136 mesh.AddBdrTriangle(triangle);
139 mesh.FinalizeTetMesh();
141 while (mesh.GetNE() < (0.25 * approx_number_of_elements)) {
142 mesh.UniformRefinement();
152 return mfem::Mesh::MakeCartesian2D(elements_in_x, elements_in_y, mfem::Element::QUADRILATERAL,
true, size_x, size_y);
155 mfem::Mesh
buildCuboidMesh(
int elements_in_x,
int elements_in_y,
int elements_in_z,
double size_x,
double size_y,
158 return mfem::Mesh::MakeCartesian3D(elements_in_x, elements_in_y, elements_in_z, mfem::Element::HEXAHEDRON, size_x,
162 mfem::Mesh
buildCylinderMesh(
int radial_refinement,
int elements_lengthwise,
double radius,
double height)
164 static constexpr
int dim = 2;
165 static constexpr
int num_vertices = 17;
166 static constexpr
int num_elems = 12;
167 static constexpr
int num_boundary_elements = 8;
175 constexpr
double a = 1.3;
176 static constexpr
double vertices[num_vertices][dim] = {{0.0000000000000000, 0.0000000000000000},
177 {0.5773502691896258, 0.0000000000000000},
178 {0.4082482904638630 * a, 0.4082482904638630 * a},
179 {0.0000000000000000, 0.5773502691896258},
180 {-0.4082482904638630 * a, 0.4082482904638630 * a},
181 {-0.5773502691896258, 0.0000000000000000},
182 {-0.4082482904638630 * a, -0.4082482904638630 * a},
183 {0.0000000000000000, -0.5773502691896258},
184 {0.4082482904638630 * a, -0.4082482904638630 * a},
185 {1.000000000000000, 0.0000000000000000},
186 {0.7071067811865475, 0.7071067811865475},
187 {0.0000000000000000, 1.000000000000000},
188 {-0.707106781186548, 0.7071067811865475},
189 {-1.000000000000000, 0.0000000000000000},
190 {-0.707106781186548, -0.707106781186548},
191 {0.0000000000000000, -1.000000000000000},
192 {0.7071067811865475, -0.707106781186548}};
194 static constexpr
int elems[num_elems][4] = {{0, 1, 2, 3}, {0, 3, 4, 5}, {0, 5, 6, 7}, {0, 7, 8, 1},
195 {1, 9, 10, 2}, {2, 10, 11, 3}, {3, 11, 12, 4}, {4, 12, 13, 5},
196 {5, 13, 14, 6}, {6, 14, 15, 7}, {7, 15, 16, 8}, {8, 16, 9, 1}};
198 static constexpr
int boundary_elems[num_boundary_elements][2] = {{9, 10}, {10, 11}, {11, 12}, {12, 13},
199 {13, 14}, {14, 15}, {15, 16}, {16, 9}};
201 auto mesh = mfem::Mesh(dim, num_vertices, num_elems, num_boundary_elements);
203 for (
auto vertex : vertices) {
204 mesh.AddVertex(vertex);
206 for (
auto elem : elems) {
209 for (
auto boundary_elem : boundary_elems) {
210 mesh.AddBdrSegment(boundary_elem);
213 for (
int i = 0; i < radial_refinement; i++) {
214 mesh.UniformRefinement();
221 int n = mesh.GetNV();
223 mfem::Vector new_vertices;
224 mesh.GetVertices(new_vertices);
225 mfem::Vector vertex(dim);
226 for (
int i = 0; i < n; i++) {
227 for (
int d = 0; d < dim; d++) {
228 vertex(d) = new_vertices[d * n + i];
232 double theta =
atan2(vertex(1), vertex(0));
233 double phi = fmod(theta + M_PI, M_PI_4);
234 vertex *= radius * (
cos(phi) + (-1.0 +
sqrt(2.0)) *
sin(phi));
236 for (
int d = 0; d < dim; d++) {
237 new_vertices[d * n + i] = vertex(d);
240 mesh.SetVertices(new_vertices);
243 mfem::Mesh* extruded_ptr = mfem::Extrude2D(&mesh, elements_lengthwise, height);
244 mfem::Mesh extruded_obj(*extruded_ptr);
250 mfem::Mesh
buildRing(
int radial_refinement,
double inner_radius,
double outer_radius,
double total_angle,
int sectors)
252 using index_type = int;
253 using size_type = std::vector<index_type>::size_type;
255 static constexpr
int dim = 2;
257 SLIC_ASSERT_MSG(total_angle > 0.,
"only positive angles supported");
260 total_angle =
std::min(total_angle, 2. * M_PI);
261 const double angle = total_angle / sectors;
263 auto num_elems =
static_cast<size_type
>(sectors);
264 auto num_vertices_ring =
static_cast<size_type
>((total_angle == 2. * M_PI) ? sectors : sectors + 1);
265 auto num_vertices = num_vertices_ring * 2;
266 auto num_boundary_elements = num_elems * 2;
268 SLIC_ERROR_ROOT_IF(outer_radius <= inner_radius,
269 "Outer radius is smaller than inner radius while building a cylinder mesh.");
271 std::vector<std::vector<double>> vertices(
static_cast<size_type
>(num_vertices), std::vector<double>(dim, 0.));
272 for (size_type i = 0; i < num_vertices_ring; i++) {
273 double s =
sin(angle *
static_cast<double>(i));
274 double c =
cos(angle *
static_cast<double>(i));
275 vertices[i][0] = inner_radius * c;
276 vertices[i][1] = inner_radius * s;
278 vertices[i + num_vertices_ring][0] = outer_radius * c;
279 vertices[i + num_vertices_ring][1] = outer_radius * s;
282 std::vector<std::vector<index_type>> elems(
static_cast<size_type
>(num_elems), std::vector<index_type>(4, 0));
283 std::vector<std::vector<index_type>> boundary_elems(
static_cast<size_type
>(num_boundary_elements),
284 std::vector<index_type>(2, 0));
285 for (size_type i = 0; i < num_elems; i++) {
286 elems[i][0] =
static_cast<index_type
>(i);
287 elems[i][1] =
static_cast<index_type
>(num_vertices_ring + i);
288 elems[i][2] =
static_cast<index_type
>(num_vertices_ring + (i + 1) % (num_vertices_ring));
289 elems[i][3] =
static_cast<index_type
>((i + 1) % num_vertices_ring);
292 boundary_elems[i][0] = elems[i][3];
293 boundary_elems[i][1] = elems[i][0];
296 boundary_elems[i + num_elems][0] = elems[i][1];
297 boundary_elems[i + num_elems][1] = elems[i][2];
300 mfem::Mesh mesh(dim,
static_cast<int>(num_vertices),
static_cast<int>(num_elems),
301 static_cast<int>(num_boundary_elements));
303 for (
auto vertex : vertices) {
304 mesh.AddVertex(vertex.data());
306 for (
auto elem : elems) {
307 mesh.AddQuad(elem[0], elem[1], elem[2], elem[3]);
309 for (
auto boundary_elem : boundary_elems) {
310 mesh.AddBdrSegment(boundary_elem[0], boundary_elem[1]);
313 for (
int i = 0; i < radial_refinement; i++) {
314 mesh.UniformRefinement();
321 int n = mesh.GetNV();
323 mfem::Vector new_vertices;
324 mesh.GetVertices(new_vertices);
325 mfem::Vector vertex(dim);
326 for (
int i = 0; i < n; i++) {
327 for (
int d = 0; d < dim; d++) {
328 vertex(d) = new_vertices[d * n + i];
333 double theta =
atan2(vertex(1), vertex(0));
334 double phi = fmod(theta + 2. * M_PI, angle);
340 double factor =
cos(fabs(0.5 * angle - phi)) /
cos(0.5 * angle);
343 for (
int d = 0; d < dim; d++) {
344 new_vertices[d * n + i] = vertex(d);
347 mesh.SetVertices(new_vertices);
353 mfem::Mesh
buildRingMesh(
int radial_refinement,
double inner_radius,
double outer_radius,
double total_angle,
356 return buildRing(radial_refinement, inner_radius, outer_radius, total_angle, sectors);
360 double outer_radius,
double height,
double total_angle,
int sectors)
362 auto mesh =
buildRing(radial_refinement, inner_radius, outer_radius, total_angle, sectors);
363 mfem::Mesh* extruded_ptr = mfem::Extrude2D(&mesh, elements_lengthwise, height);
364 mfem::Mesh extruded_obj(*extruded_ptr);
371 std::size_t vertical_divisions,
double inner_radius,
double outer_radius,
374 constexpr
int dim = 3;
377 mfem::Mesh mesh = mfem::Mesh::MakeCartesian3D(
static_cast<int>(radial_divisions),
static_cast<int>(angular_divisions),
378 static_cast<int>(vertical_divisions), mfem::Element::HEXAHEDRON);
380 int num_vertices = mesh.GetNV();
381 mfem::Vector new_vertices;
382 mesh.GetVertices(new_vertices);
383 mfem::Vector vertex(dim);
384 for (
int i = 0; i < num_vertices; i++) {
385 for (
int d = 0; d < dim; d++) {
386 vertex(d) = new_vertices[d * num_vertices + i];
390 double r = inner_radius + (outer_radius - inner_radius) * vertex[0];
391 double theta = vertex[1] * M_PI_2;
392 vertex(0) = r *
cos(theta);
393 vertex(1) = r *
sin(theta);
394 vertex(2) = vertex(2) * height;
396 for (
int d = 0; d < dim; d++) {
397 new_vertices[d * num_vertices + i] = vertex(d);
400 mesh.SetVertices(new_vertices);
409 container.addInt(
"ser_ref_levels",
"Number of times to refine the mesh uniformly in serial.").defaultValue(0);
410 container.addInt(
"par_ref_levels",
"Number of times to refine the mesh uniformly in parallel.").defaultValue(0);
413 container.addString(
"type",
"Type of mesh").required().validValues({
"ball",
"box",
"disk",
"file"});
416 container.addString(
"mesh",
"Path to Mesh file");
419 auto& elements = container.addStruct(
"elements");
421 elements.addInt(
"x",
"x-dimension");
422 elements.addInt(
"y",
"y-dimension");
423 elements.addInt(
"z",
"z-dimension");
425 auto&
size = container.addStruct(
"size");
427 size.addDouble(
"x",
"Size in the x-dimension");
428 size.addDouble(
"y",
"Size in the y-dimension");
429 size.addDouble(
"z",
"Size in the z-dimension");
432 container.addInt(
"approx_elements",
"Approximate number of elements in an n-ball mesh");
437 std::optional<mfem::Mesh> serial_mesh;
439 if (
const auto file_opts = std::get_if<FileInputOptions>(&options.
extra_options)) {
440 SLIC_ERROR_ROOT_IF(file_opts->absolute_mesh_file_name.empty(),
441 "Absolute path to mesh file was not configured, did you forget to call findMeshFilePath?");
443 }
else if (
const auto box_opts = std::get_if<BoxInputOptions>(&options.
extra_options)) {
444 const auto& elems = box_opts->elements;
445 const auto& sizes = box_opts->overall_size;
446 if (elems.size() == 2) {
447 serial_mesh.emplace(
buildRectangleMesh(elems.at(0), elems.at(1), sizes.at(0), sizes.at(1)));
450 buildCuboidMesh(elems.at(0), elems.at(1), elems.at(2), sizes.at(0), sizes.at(1), sizes.at(2)));
452 }
else if (
const auto ball_opts = std::get_if<NBallInputOptions>(&options.
extra_options)) {
453 if (ball_opts->dimension == 2) {
454 serial_mesh.emplace(
buildDiskMesh(ball_opts->approx_elements));
456 serial_mesh.emplace(
buildBallMesh(ball_opts->approx_elements));
460 SLIC_ERROR_ROOT_IF(!serial_mesh,
"Mesh input options were invalid");
465 const int refine_parallel,
const MPI_Comm comm)
468 for (
int lev = 0; lev < refine_serial; lev++) {
469 serial_mesh.UniformRefinement();
473 auto parallel_mesh = std::make_unique<mfem::ParMesh>(comm, serial_mesh);
474 for (
int lev = 0; lev < refine_parallel; lev++) {
475 parallel_mesh->UniformRefinement();
478 parallel_mesh->EnsureNodes();
479 parallel_mesh->ExchangeFaceNbrData();
481 return parallel_mesh;
489 int ser_ref = base[
"ser_ref_levels"];
490 int par_ref = base[
"par_ref_levels"];
493 std::string mesh_type = base[
"type"];
494 if (mesh_type ==
"box") {
495 auto elements_input = base[
"elements"];
496 bool z_present = elements_input.contains(
"z");
498 std::vector<int> elements(z_present ? 3 : 2);
499 elements[0] = elements_input[
"x"];
500 elements[1] = elements_input[
"y"];
501 if (z_present) elements[2] = elements_input[
"z"];
503 std::vector<double> overall_size;
504 if (base.contains(
"size")) {
505 auto size_input = base[
"size"];
506 overall_size.push_back(size_input[
"x"]);
507 overall_size.push_back(size_input[
"y"]);
509 if (size_input.contains(
"z")) {
510 overall_size.push_back(size_input[
"z"]);
513 overall_size = std::vector<double>(elements.size(), 1.);
517 }
else if (mesh_type ==
"disk" || mesh_type ==
"ball") {
518 int approx_elements = base[
"approx_elements"];
520 if (mesh_type ==
"disk") {
524 }
else if (mesh_type ==
"file") {
525 std::string mesh_path = base[
"mesh"];
530 smith::logger::flush();
531 std::string err_msg = std::format(
"Specified type not supported: '{0}'", mesh_type);
532 SLIC_ERROR_ROOT(err_msg);
This file contains the all the necessary functions and macros required for logging as well as a helpe...
This file contains helper functions for importing and managing various mesh objects.
std::unique_ptr< mfem::ParMesh > buildParallelMesh(const InputOptions &options, const MPI_Comm comm)
Constructs an MFEM parallel mesh from a set of input options.
std::unique_ptr< mfem::ParMesh > refineAndDistribute(mfem::Mesh &&serial_mesh, const int refine_serial, const int refine_parallel, const MPI_Comm comm)
Finalizes a serial mesh into a refined parallel mesh.
Accelerator functionality.
SMITH_HOST_DEVICE auto sqrt(dual< gradient_type > x)
implementation of square root for dual numbers
SMITH_HOST_DEVICE auto cos(dual< gradient_type > a)
implementation of cosine for dual numbers
mfem::Mesh buildRingMesh(int radial_refinement, double inner_radius, double outer_radius, double total_angle, int sectors)
Constructs a 2D MFEM mesh of a ring.
mfem::Mesh buildRectangleMesh(int elements_in_x, int elements_in_y, double size_x, double size_y)
Constructs a 2D MFEM mesh of a rectangle.
constexpr SMITH_HOST_DEVICE int size(const tensor< T, n... > &)
returns the total number of stored values in a tensor
mfem::Mesh buildHollowCylinderMesh(int radial_refinement, int elements_lengthwise, double inner_radius, double outer_radius, double height, double total_angle, int sectors)
Constructs a 3D MFEM mesh of a hollow cylinder.
mfem::Mesh buildCylinderMesh(int radial_refinement, int elements_lengthwise, double radius, double height)
Constructs a 3D MFEM mesh of a cylinder.
mfem::Mesh buildBallMesh(int approx_number_of_elements)
Constructs a 3D MFEM mesh of a unit ball, centered at the origin.
void squish(mfem::Mesh &mesh)
a transformation from the unit disk/sphere (in L1 norm) to a unit disk/sphere (in L2 norm)
mfem::Mesh buildCuboidMesh(int elements_in_x, int elements_in_y, int elements_in_z, double size_x, double size_y, double size_z)
Constructs a 3D MFEM mesh of a cuboid.
mfem::Mesh buildDiskMesh(int approx_number_of_elements)
Constructs a 2D MFEM mesh of a unit disk, centered at the origin.
mfem::Mesh buildMeshFromFile(const std::string &mesh_file)
Constructs an MFEM mesh from a file.
SMITH_HOST_DEVICE auto sin(dual< gradient_type > a)
implementation of sine for dual numbers
mfem::Mesh build_hollow_quarter_cylinder(std::size_t radial_divisions, std::size_t angular_divisions, std::size_t vertical_divisions, double inner_radius, double outer_radius, double height)
Constructs an MFEM mesh of a hollow cylinder restricted to the first orthant.
SMITH_HOST_DEVICE auto min(dual< gradient_type > a, double b)
Implementation of min for dual numbers.
SMITH_HOST_DEVICE auto atan2(dual< gradient_type > y, dual< gradient_type > x)
implementation of atan2 for dual numbers
mfem::Mesh buildRing(int radial_refinement, double inner_radius, double outer_radius, double total_angle, int sectors)
Constructs a 2D MFEM mesh of a ring.