LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
Loading...
Searching...
No Matches
tp_triag_mesh_builder.cc
1#include "tp_triag_mesh_builder.h"
2
3#include <lf/geometry/geometry.h>
4#include <spdlog/spdlog.h>
5
6#include <iostream>
7
8#include "lf/mesh/mesh_interface.h"
9
10namespace lf::mesh::utils {
11
12std::shared_ptr<spdlog::logger>& TPTriagMeshBuilder::Logger() {
13 static auto logger =
14 base::InitLogger("lf::mesh::utils::TPTriagMeshBuilder::Logger");
15 return logger;
16}
17
18std::shared_ptr<mesh::Mesh> TPTriagMeshBuilder::Build() {
19 using coord_t = Eigen::Vector2d;
20 const size_type nx = num_of_x_cells_;
21 const size_type ny = num_of_y_cells_;
22 // Total number of entities in the mesh
23 // Each square is split into two triangles
24 const unsigned no_of_cells = 2 * nx * ny;
25 const unsigned no_of_edges = nx * ny + (nx + 1) * ny + nx * (ny + 1);
26 const unsigned no_of_vertices = (nx + 1) * (ny + 1);
27 // Diagnostics
28 SPDLOG_LOGGER_DEBUG(Logger(), "TPmesh: {} cells, {} edges, {} vertices",
29 no_of_cells, no_of_edges, no_of_vertices);
30
31 // No mesh to build
32 if (no_of_cells == 0) {
33 return nullptr;
34 }
35 // define rectangle; return if none
36 const double x_size = top_right_corner_[0] - bottom_left_corner_[0];
37 const double y_size = top_right_corner_[1] - bottom_left_corner_[1];
38 if ((x_size <= 0.0) || (y_size <= 0.0)) {
39 return nullptr;
40 }
41 // meshwidths
42 const double hx = x_size / nx;
43 const double hy = y_size / ny;
44
45 // Initialize vertices
46 std::vector<size_type> v_idx(no_of_vertices);
47 int node_cnt = 0; // index of current vertex: lexicographic numbering
48 for (size_type j = 0; j <= ny; ++j) {
49 for (size_type i = 0; i <= nx; ++i, ++node_cnt) {
50 // Tensor-product node locations
51 coord_t node_coord(2);
52 node_coord << bottom_left_corner_[0] + i * hx,
53 bottom_left_corner_[1] + j * hy;
54 // Diagnostics
55 SPDLOG_LOGGER_TRACE(Logger(), "Adding vertex {}: {}", node_cnt,
56 node_coord.transpose());
57
58 // Enlist vertex
59 v_idx[node_cnt] = mesh_factory_->AddPoint(node_coord);
60 }
61 }
62
63 // Initialize edges
64 // Just in case of index permutations
65 std::vector<size_type> e_idx(no_of_edges);
66 int edge_cnt = 0; // index of current edge
67 // First horizontal edges
68 for (size_type i = 0; i < nx; ++i) {
69 for (size_type j = 0; j <= ny; ++j, ++edge_cnt) {
70 // Indices of the two endpoints of the edge
71 auto first_endpoint_idx = v_idx[VertexIndex(i, j)];
72 auto second_endpoint_idx = v_idx[VertexIndex(i + 1, j)];
73 // Diagnostics
74 SPDLOG_LOGGER_TRACE(Logger(), "horizontal edge {}: {} <-> {}", edge_cnt,
75 first_endpoint_idx, second_endpoint_idx);
76
77 std::vector<size_type> nodes_index_list{first_endpoint_idx,
78 second_endpoint_idx};
79 // Coordinates of endpoints a columns of a 2x2 matrix
80 Eigen::Matrix<double, Eigen::Dynamic, 2> edge_geo(2, 2);
81 edge_geo << bottom_left_corner_[0] + i * hx,
82 bottom_left_corner_[0] + (i + 1) * hx,
83 bottom_left_corner_[1] + j * hy, bottom_left_corner_[1] + j * hy;
84 e_idx[edge_cnt] = mesh_factory_->AddEntity(
85 lf::base::RefEl::kSegment(), nodes_index_list,
86 std::make_unique<geometry::SegmentO1>(edge_geo));
87 }
88 }
89 // Next vertical edges
90 for (size_type i = 0; i <= nx; ++i) {
91 for (size_type j = 0; j < ny; ++j, ++edge_cnt) {
92 // Indices of the two endpoints of the edge
93 const size_type first_endpoint_idx = v_idx[VertexIndex(i, j)];
94 const size_type second_endpoint_idx = v_idx[VertexIndex(i, j + 1)];
95 // Diagnostics
96 SPDLOG_LOGGER_TRACE(Logger(), "vertical edge {}: {} <-> {}", edge_cnt,
97 first_endpoint_idx, second_endpoint_idx);
98
99 std::vector<size_type> nodes_index_list{first_endpoint_idx,
100 second_endpoint_idx};
101 // Coordinates of endpoints a columns of a 2x2 matrix
102 Eigen::Matrix<double, Eigen::Dynamic, 2> edge_geo(2, 2);
103 edge_geo << bottom_left_corner_[0] + i * hx,
104 bottom_left_corner_[0] + i * hx, bottom_left_corner_[1] + j * hy,
105 bottom_left_corner_[1] + (j + 1) * hy;
106 e_idx[edge_cnt] = mesh_factory_->AddEntity(
107 lf::base::RefEl::kSegment(), nodes_index_list,
108 std::make_unique<geometry::SegmentO1>(edge_geo));
109 }
110 }
111 // Then the skew edges (diagonals of squares)
112 for (size_type i = 0; i < nx; ++i) {
113 for (size_type j = 0; j < ny; ++j, ++edge_cnt) {
114 // Indices of the two endpoints of the edge
115 const size_type first_endpoint_idx = v_idx[VertexIndex(i, j)];
116 const size_type second_endpoint_idx = v_idx[VertexIndex(i + 1, j + 1)];
117 // Diagnostics
118 SPDLOG_LOGGER_TRACE(Logger(), "diagonal edge {}: {} <-> {}", edge_cnt,
119 first_endpoint_idx, second_endpoint_idx);
120
121 std::vector<size_type> nodes_index_list{first_endpoint_idx,
122 second_endpoint_idx};
123 // Coordinates of endpoints a columns of a 2x2 matrix
124 Eigen::Matrix<double, Eigen::Dynamic, 2> edge_geo(2, 2);
125 edge_geo << bottom_left_corner_[0] + i * hx,
126 bottom_left_corner_[0] + (i + 1) * hx,
127 bottom_left_corner_[1] + j * hy,
128 bottom_left_corner_[1] + (j + 1) * hy;
129 e_idx[edge_cnt] = mesh_factory_->AddEntity(
130 lf::base::RefEl::kSegment(), nodes_index_list,
131 std::make_unique<geometry::SegmentO1>(edge_geo));
132 }
133 }
134
135 // Finally initialize the triangles
136 // Index remapping for triangles
137 std::vector<size_type> t_idx(no_of_cells);
138
139 size_type tria_cnt = 0; // index of current triangle
140 for (size_type i = 0; i < nx; ++i) {
141 for (size_type j = 0; j < ny; ++j, tria_cnt += 2) {
142 // Triangle above the diagonal
143 // Indices of the vertices
144 std::vector<size_type> vertex_index_list_up{
145 v_idx[VertexIndex(i, j)], v_idx[VertexIndex(i + 1, j + 1)],
146 v_idx[VertexIndex(i, j + 1)]};
147 // Construct geometry
148 Eigen::Matrix<double, Eigen::Dynamic, 3> tria_geo_up(2, 3);
149 tria_geo_up << bottom_left_corner_[0] + i * hx,
150 bottom_left_corner_[0] + (i + 1) * hx,
151 bottom_left_corner_[0] + i * hx, bottom_left_corner_[1] + j * hy,
152 bottom_left_corner_[1] + (j + 1) * hy,
153 bottom_left_corner_[1] + (j + 1) * hy;
154 // Enroll the triangle entity
155 t_idx[tria_cnt] = mesh_factory_->AddEntity(
156 lf::base::RefEl::kTria(), vertex_index_list_up,
157 std::make_unique<geometry::TriaO1>(tria_geo_up));
158 // Triangle below the diagonal
159 // Indices of the vertices
160 std::vector<size_type> vertex_index_list_low{
161 v_idx[VertexIndex(i, j)], v_idx[VertexIndex(i + 1, j)],
162 v_idx[VertexIndex(i + 1, j + 1)]};
163 // Construct geometry
164 Eigen::Matrix<double, Eigen::Dynamic, 3> tria_geo_low(2, 3);
165 tria_geo_low << bottom_left_corner_[0] + i * hx,
166 bottom_left_corner_[0] + (i + 1) * hx,
167 bottom_left_corner_[0] + (i + 1) * hx,
168 bottom_left_corner_[1] + j * hy, bottom_left_corner_[1] + j * hy,
169 bottom_left_corner_[1] + (j + 1) * hy;
170 auto tria_geo_low_ptr = std::make_unique<geometry::TriaO1>(tria_geo_low);
171 // Generate the triangle entity
172 t_idx[tria_cnt + 1] = mesh_factory_->AddEntity(
173 lf::base::RefEl::kTria(), vertex_index_list_low,
174 std::make_unique<geometry::TriaO1>(tria_geo_low));
175 }
176 }
177 return mesh_factory_->Build();
178} // end Build()
179
180} // namespace lf::mesh::utils
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
Definition ref_el.h:153
static constexpr RefEl kTria()
Returns the reference triangle.
Definition ref_el.h:161
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()
Used by Build() method to output 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 ...
Contains helper functions and classes that all operate on the interface classes defined in lf::mesh.