LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
torus_mesh_builder.cc
1
9#define _USE_MATH_DEFINES
10
11#include "torus_mesh_builder.h"
12
13#include <lf/geometry/geometry.h>
14#include <spdlog/spdlog.h>
15
16#include <cmath>
17#include <iostream>
18
19#include "lf/mesh/mesh_interface.h"
20
21namespace lf::mesh::utils {
22
23std::shared_ptr<spdlog::logger>& TorusMeshBuilder::Logger() {
24 static auto logger =
25 base::InitLogger("lf::mesh::utils::TorusMeshBuilder::Logger");
26 return logger;
27}
28
29std::shared_ptr<mesh::Mesh> TorusMeshBuilder::Build() {
30 using coord_t = Eigen::Vector3d;
31
32 const size_type nx = num_of_x_cells_;
33 const size_type ny = num_of_y_cells_;
34
35 // opposite edges and vertices are identical and only counted once
36 const unsigned no_of_cells = nx * ny;
37 const unsigned no_of_edges = 2 * nx * ny;
38 const unsigned no_of_vertices = nx * ny;
39
40 if (no_of_cells == 0) {
41 return nullptr;
42 }
43
44 const double x_size = top_right_corner_[0] - bottom_left_corner_[0];
45 const double y_size = top_right_corner_[1] - bottom_left_corner_[1];
46
47 if ((x_size <= 0.0) || (y_size <= 0.0)) {
48 return nullptr;
49 }
50
51 // calculate mesh width of uniform grid on rectangle
52 const double hx = x_size / nx;
53 const double hy = y_size / ny;
54
55 // parametrize torus: https://en.wikipedia.org/wiki/Torus#Geometry
56 const double r = x_size / (2. * M_PI);
57 const double R = y_size / (2. * M_PI);
58 auto theta = [r, hx](double i) -> double { return (i * hx) / r; };
59 auto phi = [R, hy](double j) -> double { return (j * hy) / R; };
60
61 SPDLOG_LOGGER_DEBUG(
62 Logger(),
63 "TorusMesh: {} cells, {} edges, {} vertices, mesh widths hx/hy = {}/{}",
64 no_of_cells, no_of_edges, no_of_vertices, hx, hy);
65
66 // compute vertices of mesh on torus with lexicographic numbering
67 std::vector<size_type> v_idx(no_of_vertices);
68 int node_cnt = 0;
69
70 for (size_type j = 0; j < ny; ++j) {
71 for (size_type i = 0; i < nx; ++i, ++node_cnt) {
72 // compute vertex coordinates
73 coord_t node_coord;
74 node_coord << (R + r * std::cos(theta(i))) * std::cos(phi(j)),
75 (R + r * std::cos(theta(i))) * std::sin(phi(j)),
76 r * std::sin(theta(i));
77
78 SPDLOG_LOGGER_TRACE(Logger(), "Adding vertex {}: {}", node_cnt,
79 node_coord.transpose());
80 // register vertex
81 v_idx[node_cnt] = mesh_factory_->AddPoint(node_coord);
82 }
83 }
84
85 // compute cells of mesh on torus
86 std::vector<size_type> t_idx(no_of_cells);
87 size_type quad_cnt = 0;
88
89 for (size_type i = 0; i < nx; ++i) {
90 for (size_type j = 0; j < ny; ++j, quad_cnt++) {
91 // gather vertex indices of given cell wrapping around edges of rectangle
92 std::vector<size_type> vertex_index_list{
93 v_idx[VertexIndex(i, j)], v_idx[VertexIndex((i + 1) % nx, j)],
94 v_idx[VertexIndex((i + 1) % nx, (j + 1) % ny)],
95 v_idx[VertexIndex(i, (j + 1) % ny)]};
96
97 Eigen::Matrix<double, 3, 4> quad_geo;
98 quad_geo << (R + r * std::cos(theta(i))) * std::cos(phi(j)),
99 (R + r * std::cos(theta(i + 1))) * std::cos(phi(j)),
100 (R + r * std::cos(theta(i + 1))) * std::cos(phi(j + 1)),
101 (R + r * std::cos(theta(i))) * std::cos(phi(j + 1)),
102 (R + r * std::cos(theta(i))) * std::sin(phi(j)),
103 (R + r * std::cos(theta(i + 1))) * std::sin(phi(j)),
104 (R + r * std::cos(theta(i + 1))) * std::sin(phi(j + 1)),
105 (R + r * std::cos(theta(i))) * std::sin(phi(j + 1)),
106 r * std::sin(theta(i)), r * std::sin(theta(i + 1)),
107 r * std::sin(theta(i + 1)), r * std::sin(theta(i));
108
109 SPDLOG_LOGGER_TRACE(Logger(), "Adding quad {}:\n{}", quad_cnt, quad_geo);
110
111 // request cell production from MeshFactory (straight edges will be
112 // created as needed)
113 t_idx[quad_cnt] = mesh_factory_->AddEntity(
114 lf::base::RefEl::kQuad(), vertex_index_list,
115 std::make_unique<geometry::QuadO1>(quad_geo));
116 }
117 }
118
119 return mesh_factory_->Build();
120} // TorusMeshBuilder::Build()
121
122} // namespace lf::mesh::utils
static constexpr RefEl kQuad()
Returns the reference quadrilateral.
Definition: ref_el.h:166
std::unique_ptr< mesh::MeshFactory > mesh_factory_
size_type VertexIndex(size_type i, size_type j) const
vertex index from grid position
std::shared_ptr< mesh::Mesh > Build() override
actual construction of the mesh
static std::shared_ptr< spdlog::logger > & Logger()
logger that is used by Build() to provide additional debug info.
std::shared_ptr< spdlog::logger > InitLogger(const std::string &name)
Create a spdlog logger, register it in the spdlog registry and initialize it with LehrFEM++ specific ...
Definition: spdlog_utils.cc:16
Contains helper functions and classes that all operate on the interface classes defined in lf::mesh.