OpenBEM
Open-source framework for electromagnetic simulation with the boundary element method.
Loading...
Searching...
No Matches
triangle_mesh.cpp
Go to the documentation of this file.
1// OpenBEM - Copyright (C) 2026 Shashwat Sharma
2
3// This file is part of OpenBEM.
4
5// OpenBEM is free software: you can redistribute it and/or modify it under the terms of the
6// GNU General Public License as published by the Free Software Foundation, either version 3
7// of the License, or (at your option) any later version.
8
9// You should have received a copy of the GNU General Public License along with OpenBEM.
10// If not, see <https://www.gnu.org/licenses/>.
11
12
19
20#include <map>
21#include <utility>
22#include <algorithm>
23#include <vector>
24#include <array>
25#include <set>
26#include <stdexcept>
27
28#include "types.hpp"
30
31
32namespace bem
33{
34
35template <uint8_t dim>
40 const bool decoupled_edges
41 )
42{
43 base::verts_ = verts;
44 base::elems_ = elems;
45 base::elem_tags_ = elem_tags;
46 decoupled_edges_ = decoupled_edges;
47 generate_edges();
48 return;
49};
50
51
52template <uint8_t dim>
54 MeshBase<dim, 3>& partition,
56 ) const
57{
58
59 Index num_new_verts = 0;
60 std::map<Index, Index> new_vert_map;
61
62 for (Index jj = 0; jj < elem_inds.size(); ++jj)
63 {
64 for (uint8_t kk = 0; kk < 3; ++kk)
65 {
66 bool inserted = new_vert_map.insert(
67 std::make_pair(base::elems_(kk, elem_inds[jj]), num_new_verts)
68 ).second;
69 if (inserted)
70 num_new_verts++;
71 }
72 }
73
74 EigMatNX<Float, dim> new_verts = EigMatNX<Float, dim>::Zero(dim, num_new_verts);
75 for (auto const& x: new_vert_map)
76 new_verts.col(x.second) = base::verts_.col(x.first);
77
78 EigMatNX<Index, 3> new_elems = EigMatNX<Index, 3>::Zero(3, elem_inds.size());
79
80 EigRowVec<Index> new_elem_tags = EigRowVec<Index>::Zero(1, elem_inds.size());
81
82 for (Index jj = 0; jj < elem_inds.size(); ++jj)
83 {
84 for (uint8_t kk = 0; kk < 3; ++kk)
85 {
86 new_elems(kk, jj) = new_vert_map[
87 base::elems_(kk, elem_inds[jj])
88 ];
89 }
90 new_elem_tags[jj] = base::elem_tags_[elem_inds[jj]];
91 }
92
93 TriangleMesh<dim>& partition_cast = dynamic_cast<TriangleMesh<dim>&> (partition);
94 partition_cast.set_data(new_verts, new_elems, new_elem_tags, decoupled_edges_);
95
96 return;
97
98};
99
100
101template <uint8_t dim>
103 MeshBase<dim, 3>& partition,
105 const bool strict
106 ) const
107{
108
109 std::vector<Index> elems_in_bbox;
110
111 for (Index ii = 0; ii < base::elems_.cols(); ++ii)
112 {
113 EigMatMN<Float, dim, 3> coords = base::verts_(
114 Eigen::placeholders::all, base::elems_.col(ii)
115 );
116 EigColVecN<Float, dim> centroid = coords.rowwise().mean();
117 bool centroid_in_bbox =
118 (centroid.array() <= (bbox.rowwise().maxCoeff()).array()).all() &&
119 (centroid.array() >= (bbox.rowwise().minCoeff()).array()).all();
120
121 if (centroid_in_bbox)
122 {
123 if (!strict)
124 elems_in_bbox.push_back(ii);
125 else
126 {
127 bool fully_in_bbox =
128 ((coords.rowwise().maxCoeff()).array() <= (bbox.rowwise().maxCoeff()).array()
129 ).all() &&
130 ((coords.rowwise().minCoeff()).array() >= (bbox.rowwise().minCoeff()).array()
131 ).all();
132
133 if (fully_in_bbox)
134 elems_in_bbox.push_back(ii);
135 }
136 }
137 }
138
139 partition_by_elems(
140 partition,
141 Eigen::Map<EigRowVec<Index>> (elems_in_bbox.data(), elems_in_bbox.size())
142 );
143
144 return;
145
146};
147
148
149template <uint8_t dim>
151{
152
153 Index num_edges = 0;
154 std::vector<std::pair<Index, uint8_t>> edge_counts;
155 std::vector<std::pair<std::pair<Index, Index>, Index>> edges;
156
157 elem_edges_.resize(3, base::elems_.cols());
158 elem_edge_polarities_.resize(3, base::elems_.cols());
159
160 std::set<Index> unique_tags { base::elem_tags_.begin(), base::elem_tags_.end() };
161
162 for (Index tag: unique_tags)
163 {
164 std::map<std::pair<Index, Index>, Index> unique_edges;
165
166 for (Index elem = 0; elem < base::elems_.cols(); ++elem)
167 {
168 if (base::elem_tags_[elem] != tag)
169 continue;
170
171 for (uint8_t edge = 0; edge < 3; ++edge)
172 {
173 std::pair<Index, Index> verts = std::make_pair(
174 base::elems_(edge, elem),
175 base::elems_((edge + 1) % 3, elem)
176 );
177
178 if (!decoupled_edges_ && verts.first > verts.second)
179 std::swap(verts.first, verts.second);
180
181 bool inserted = unique_edges.insert(std::make_pair(verts, num_edges)).second;
182
183 if (inserted)
184 {
185 elem_edges_(edge, elem) = num_edges;
186 elem_edge_polarities_(edge, elem) = 1;
187 edge_counts.push_back(std::make_pair(num_edges, 1));
188 edges.push_back(std::make_pair(verts, num_edges));
189 num_edges++;
190 }
191 else
192 {
193 elem_edges_(edge, elem) = unique_edges[verts];
194 elem_edge_polarities_(edge, elem) = -1;
195 edge_counts[unique_edges[verts]].second++;
196 }
197 }
198 }
199 }
200
201 edges_.resize(2, num_edges);
202 for (const auto& edge: edges)
203 edges_.col(edge.second) = EigColVecN<Index, 2> ({ edge.first.first, edge.first.second });
204
205 std::vector<Index> boundary_edges, junction_edges, internal_edges;
206 for (Index edge = 0; edge < num_edges; ++edge)
207 {
208 if (edge_counts[edge].second == 1 && !decoupled_edges_)
209 boundary_edges.push_back(edge);
210 else if (edge_counts[edge].second > 2 && !decoupled_edges_)
211 junction_edges.push_back(edge);
212 if (edge_counts[edge].second > 1 && !decoupled_edges_)
213 internal_edges.push_back(edge);
214 }
215
216 boundary_edges_ = Eigen::Map<EigRowVec<Index>, Eigen::Unaligned> (
217 boundary_edges.data(), boundary_edges.size()
218 );
219 junction_edges_ = Eigen::Map<EigRowVec<Index>, Eigen::Unaligned> (
220 junction_edges.data(), junction_edges.size()
221 );
222 internal_edges_ = Eigen::Map<EigRowVec<Index>, Eigen::Unaligned> (
223 internal_edges.data(), internal_edges.size()
224 );
225
226 std::vector<Index> boundary_elems, junction_elems, internal_elems;
227 for (Index elem = 0; elem < base::elems_.cols(); ++elem)
228 {
229 for (uint8_t edge = 0; edge < 3; ++edge)
230 {
231 if (edge_counts[elem_edges_(edge, elem)].second == 1 && !decoupled_edges_)
232 boundary_elems.push_back(elem);
233 else if (edge_counts[elem_edges_(edge, elem)].second > 2 && !decoupled_edges_)
234 junction_elems.push_back(elem);
235 if (edge_counts[elem_edges_(edge, elem)].second > 1 && !decoupled_edges_)
236 internal_elems.push_back(elem);
237 }
238 }
239
240 auto remove_duplicates = [] (std::vector<Index> &v)
241 {
242 std::sort(v.begin(), v.end());
243 auto last = std::unique(v.begin(), v.end());
244 v.erase(last, v.end());
245 return;
246 };
247
248 remove_duplicates(boundary_elems);
249 remove_duplicates(junction_elems);
250 remove_duplicates(internal_elems);
251
252 boundary_elems_ = Eigen::Map<EigRowVec<Index>, Eigen::Unaligned> (
253 boundary_elems.data(), boundary_elems.size()
254 );
255 junction_elems_ = Eigen::Map<EigRowVec<Index>, Eigen::Unaligned> (
256 junction_elems.data(), junction_elems.size()
257 );
258 internal_elems_ = Eigen::Map<EigRowVec<Index>, Eigen::Unaligned> (
259 internal_elems.data(), internal_elems.size()
260 );
261
262 return;
263
264};
265
266
267template class TriangleMesh<2>;
268template class TriangleMesh<3>;
269
270}
Mesh base class.
Definition base.hpp:41
Class defining a mesh with triangle elements.
void generate_edges()
Generates edges for the mesh based on element vertices.
void partition_by_elems(MeshBase< dim, 3 > &partition, ConstEigRef< EigRowVec< Index > > elem_inds) const
Returns a sub-mesh that contains only specified elements of this mesh.
void partition_by_bbox(MeshBase< dim, 3 > &partition, ConstEigRef< EigMatMN< Float, dim, 2 > > bbox, const bool strict=true) const
Returns a sub-mesh that contains only elements of this mesh that lie within a given bounding box.
void set_data(ConstEigRef< EigMatNX< Float, dim > > verts, ConstEigRef< EigMatNX< Index, 3 > > elems, ConstEigRef< EigRowVec< Index > > elem_tags, const bool decoupled_edges=false)
Sets the mesh data.
const Eigen::Ref< const EigObj > ConstEigRef
Read-only reference to an Eigen object.
Definition types.hpp:98
Eigen::Matrix< T, 1, Eigen::Dynamic > EigRowVec
Dynamic-size row vector containing type T.
Definition types.hpp:90
Eigen::Matrix< T, M, N > EigMatMN
Fixed-size matrix with M rows and N columns containing type T.
Definition types.hpp:70
Eigen::Matrix< T, N, 1 > EigColVecN
Fixed-size column vector of size N containing type T.
Definition types.hpp:86
Eigen::Matrix< T, N, Eigen::Dynamic > EigMatNX
Fixed-height matrix with N rows containing type T.
Definition types.hpp:78
std::size_t Index
Unsigned integer type for indices and container sizes.
Definition types.hpp:54
Primary namespace for the OpenBEM library.
Definition constants.hpp:31