Wildmeshing Toolkit
Loading...
Searching...
No Matches
MultiMeshFromTag.cpp
Go to the documentation of this file.
2
3#include <queue>
4#include <set>
5#include <wmtk/EdgeMesh.hpp>
6#include <wmtk/PointMesh.hpp>
7#include <wmtk/TetMesh.hpp>
8#include <wmtk/TriMesh.hpp>
11#include <wmtk/utils/Logger.hpp>
13
15
16constexpr static std::array<std::array<int64_t, 4>, 4> n_local_ids = {{
17 {{1, 0, 0, 0}}, // PointMesh
18 {{2, 1, 0, 0}}, // EdgeMesh
19 {{3, 3, 1, 0}}, // TriMesh
20 {{4, 6, 4, 1}} // TetMesh
21}};
22
23MultiMeshFromTag::MultiMeshFromTag(
24 Mesh& mesh,
25 const attribute::MeshAttributeHandle& tag_handle,
26 const int64_t tag_value)
27 : m_mesh(mesh)
28 , m_tag_acc(m_mesh.create_const_accessor<int64_t>(tag_handle))
29 , m_tag_value(tag_value)
30 , m_tag_ptype(tag_handle.primitive_type())
31{
32 // assert(m_mesh.get_child_meshes().empty());
33}
34
35Eigen::MatrixX<int64_t> MultiMeshFromTag::get_new_id_matrix(const PrimitiveType ptype) const
36{
37 return m_new_id_matrices.at(ptype);
38}
39
40VectorXl MultiMeshFromTag::get_new_top_coface_vector(const PrimitiveType ptype) const
41{
42 return m_new_top_coface_vectors.at(ptype);
43}
44
45Eigen::MatrixX<int64_t> MultiMeshFromTag::adjacency_matrix() const
46{
47 return m_adjacency_matrix;
48}
49
50std::shared_ptr<Mesh> MultiMeshFromTag::substructure_soup() const
51{
52 return m_soup_ptr;
53}
54
55std::shared_ptr<Mesh> MultiMeshFromTag::substructure() const
56{
57 return m_substructure_ptr;
58}
59
60void MultiMeshFromTag::remove_soup()
61{
63}
64
65void MultiMeshFromTag::compute_substructure_ids()
66{
67 Mesh& child = *m_soup_ptr;
68
69 const auto top_dimension_child_tuples = child.get_all(m_tag_ptype);
70
72 if (pt == m_tag_ptype) {
73 // there is nothing to do for the top dimension
74 continue;
75 }
76
77 auto local_id = [pt](const Tuple& t) -> int64_t {
78 int64_t local_id = -1;
79 switch (pt) {
80 case PrimitiveType::Vertex: local_id = t.local_vid(); break;
81 case PrimitiveType::Edge: local_id = t.local_eid(); break;
82 case PrimitiveType::Triangle: local_id = t.local_fid(); break;
84 default: assert(false); break;
85 }
86 return local_id;
87 };
88
89 auto get_id =
90 [&local_id](const attribute::Accessor<int64_t>& acc, const Tuple& t) -> int64_t {
91 return acc.const_vector_attribute(t)(local_id(t));
92 };
93
94 auto set_id = [&local_id](
96 const Tuple& t,
97 const int64_t val) -> void {
98 acc.vector_attribute(t)(local_id(t)) = val;
99 };
100
101 auto id_acc = child.create_accessor<int64_t>(m_new_id_handles[pt]);
102
103 int64_t simplex_counter = 0;
104 // assign ids with duplication at non-manifold simplices
105 for (const Tuple& cell_tuple : top_dimension_child_tuples) {
106 const auto simplex_tuples = simplex::faces_single_dimension_tuples(
107 child,
108 simplex::Simplex(child, m_tag_ptype, cell_tuple),
109 pt);
110
111 for (const Tuple& s_tuple : simplex_tuples) {
112 if (get_id(id_acc, s_tuple) != -1) {
113 // simplex already has an id assigned
114 continue;
115 }
116
117 const std::vector<Tuple> s_region = get_connected_region(s_tuple, pt);
118
119 for (const Tuple& t : s_region) {
120 set_id(id_acc, t, simplex_counter);
121 }
122
123 ++simplex_counter;
124 }
125 }
126
127 // build id and top-coface matrix
128 Eigen::MatrixX<int64_t> id_matrix;
129 id_matrix.resize(top_dimension_child_tuples.size(), id_acc.dimension());
130 VectorXl coface_vector;
131 coface_vector.resize(simplex_counter);
132
133
134 for (size_t i = 0; i < top_dimension_child_tuples.size(); ++i) {
135 const Tuple& cell_tuple = top_dimension_child_tuples[i];
136
137 const auto face_tuples = simplex::faces_single_dimension_tuples(
138 child,
139 simplex::Simplex(child, m_tag_ptype, cell_tuple),
140 pt);
141
142 assert(face_tuples.size() == id_acc.dimension());
143
144 for (size_t j = 0; j < face_tuples.size(); ++j) {
145 const int64_t id = get_id(id_acc, face_tuples[j]);
146 assert(id != -1);
147 id_matrix(i, local_id(face_tuples[j])) = id;
148 coface_vector(id) = i;
149 }
150 }
151
152 m_new_id_matrices[pt] = id_matrix;
153 m_new_top_coface_vectors[pt] = coface_vector;
154 }
155}
156
157std::vector<Tuple> MultiMeshFromTag::get_connected_region(
158 const Tuple& t_in,
159 const PrimitiveType ptype)
160{
161 Mesh& child = *m_soup_ptr;
162
163 const PrimitiveType connecting_ptype =
165
166 std::vector<Tuple> connected_region;
167
168 std::set<Tuple> touched_tuples;
169 std::queue<Tuple> q;
170 q.push(t_in);
171
172 while (!q.empty()) {
173 const Tuple t = q.front();
174 q.pop();
175
176 {
177 // check if cell already exists
178 const auto [it, did_insert] = touched_tuples.insert(t);
179 if (!did_insert) {
180 continue;
181 }
182 }
183 connected_region.emplace_back(t);
184
185 const std::vector<Tuple> pt_intersection =
187
188
189 for (const Tuple& t_version : pt_intersection) {
190 const simplex::Simplex face = simplex::Simplex(child, connecting_ptype, t_version);
191
192 const simplex::Simplex root_face = child.map_to_parent(face);
193
194 const std::vector<simplex::Simplex> child_faces = m_mesh.map_to_child(child, root_face);
195
196 if (child_faces.size() != 2) {
197 // the connection through this face is not manifold or a boundary
198 continue;
199 }
200
201 assert(child_faces[0].tuple() == t_version || child_faces[1].tuple() == t_version);
202
203 q.push(
204 child_faces[0].tuple() == t_version ? child_faces[1].tuple()
205 : child_faces[0].tuple());
206 }
207 }
208
209 return connected_region;
210}
211
212void MultiMeshFromTag::build_adjacency_matrix()
213{
215 // A point mesh does not have any adjacency
216 return;
217 }
218
219 Mesh& child = *m_soup_ptr;
220
221 const int64_t tag_ptype_id = get_primitive_type_id(m_tag_ptype);
222
223 const int64_t connecting_pt_id = tag_ptype_id - 1;
224 const PrimitiveType connecting_ptype = get_primitive_type_from_id(connecting_pt_id);
225
226 auto local_id = [connecting_ptype](const Tuple& t) -> int64_t {
227 int64_t local_id = -1;
228 switch (connecting_ptype) {
229 case PrimitiveType::Vertex: local_id = t.local_vid(); break;
230 case PrimitiveType::Edge: local_id = t.local_eid(); break;
231 case PrimitiveType::Triangle: local_id = t.local_fid(); break;
233 default: assert(false); break;
234 }
235 return local_id;
236 };
237
238 auto get_id = [&local_id](const attribute::Accessor<int64_t>& acc, const Tuple& t) -> int64_t {
239 return acc.const_vector_attribute(t)(local_id(t));
240 };
241
242 auto set_id =
243 [&local_id](attribute::Accessor<int64_t>& acc, const Tuple& t, const int64_t val) -> void {
244 acc.vector_attribute(t)(local_id(t)) = val;
245 };
246
247 m_adjacency_handle = child.register_attribute<int64_t>(
248 "multimesh_from_tag_adjacency",
250 n_local_ids[tag_ptype_id][connecting_pt_id],
251 false,
252 -1);
253
254 auto adj_acc = child.create_accessor<int64_t>(m_adjacency_handle);
255
256 const auto top_dimension_child_tuples = child.get_all(m_tag_ptype);
257
258 auto top_simplex_id_handle = child.register_attribute<int64_t>(
259 "multimesh_from_tag_top_substructure_simplex_id",
261 1,
262 false,
263 -1);
264 auto top_simplex_id_acc = child.create_accessor<int64_t>(top_simplex_id_handle);
265
266 // set cell ids
267 for (size_t i = 0; i < top_dimension_child_tuples.size(); ++i) {
268 top_simplex_id_acc.scalar_attribute(top_dimension_child_tuples[i]) = i;
269 }
270
271 // create adjacency matrix
272 for (const Tuple& cell_tuple : top_dimension_child_tuples) {
273 const auto face_tuples = simplex::faces_single_dimension_tuples(
274 child,
275 simplex::Simplex(child, m_tag_ptype, cell_tuple),
276 connecting_ptype);
277
278 for (const Tuple& ft : face_tuples) {
279 const simplex::Simplex face = simplex::Simplex(child, connecting_ptype, ft);
280
281 const simplex::Simplex root_face = child.map_to_parent(face);
282
283 const std::vector<simplex::Simplex> child_faces = m_mesh.map_to_child(child, root_face);
284
285 if (child_faces.size() != 2) {
286 // the connection through this face is either non-manifold or a boundary
287 continue;
288 }
289
290 assert(child_faces[0].tuple() == ft || child_faces[1].tuple() == ft);
291
292 const Tuple neighbor =
293 child_faces[0].tuple() == ft ? child_faces[1].tuple() : child_faces[0].tuple();
294
295 // set adjacency
296 set_id(adj_acc, ft, top_simplex_id_acc.const_scalar_attribute(neighbor));
297 }
298 }
299
300 Eigen::MatrixX<int64_t> adj_matrix;
301 adj_matrix.resize(top_dimension_child_tuples.size(), m_adjacency_handle.dimension());
302
303 for (size_t i = 0; i < top_dimension_child_tuples.size(); ++i) {
304 const auto face_tuples = simplex::faces_single_dimension_tuples(
305 child,
306 simplex::Simplex(child, m_tag_ptype, top_dimension_child_tuples[i]),
307 connecting_ptype);
308
309 assert(face_tuples.size() == adj_matrix.cols());
310
311 for (size_t j = 0; j < face_tuples.size(); ++j) {
312 const int64_t id = get_id(adj_acc, face_tuples[j]);
313 adj_matrix(i, local_id(face_tuples[j])) = id;
314 }
315 }
316
317 m_adjacency_matrix = adj_matrix;
318}
319
320void MultiMeshFromTag::create_substructure_soup()
321{
322 const int64_t n_vertices_per_simplex = n_local_ids[get_primitive_type_id(m_tag_ptype)][0];
323
324 std::vector<Tuple> tagged_tuples;
325 {
326 const auto tag_type_tuples = m_mesh.get_all(m_tag_ptype);
327 for (const Tuple& t : tag_type_tuples) {
329 continue;
330 }
331 tagged_tuples.emplace_back(t);
332 }
333 }
334
335 // vertex matrix
336 Eigen::MatrixX<int64_t> id_matrix;
337 id_matrix.resize(tagged_tuples.size(), n_vertices_per_simplex);
338
339
340 switch (m_tag_ptype) {
342 m_soup_ptr = std ::make_shared<PointMesh>();
343 static_cast<PointMesh&>(*m_soup_ptr).initialize(tagged_tuples.size());
344 break;
345 }
346 case PrimitiveType::Edge: {
347 m_soup_ptr = std ::make_shared<EdgeMesh>();
348 static_cast<EdgeMesh&>(*m_soup_ptr).initialize_free(tagged_tuples.size());
349 break;
350 }
352 m_soup_ptr = std ::make_shared<TriMesh>();
353 static_cast<TriMesh&>(*m_soup_ptr).initialize_free(tagged_tuples.size());
354 break;
355 }
357 m_soup_ptr = std ::make_shared<TetMesh>();
358 static_cast<TetMesh&>(*m_soup_ptr).initialize_free(tagged_tuples.size());
359 break;
360 }
361 default: log_and_throw_error("Unknown primitive type for tag");
362 }
363
364 std::vector<std::array<Tuple, 2>> child_to_parent_map(tagged_tuples.size());
365
366 const auto child_top_dimension_tuples = m_soup_ptr->get_all(m_tag_ptype);
367
368 assert(tagged_tuples.size() == child_top_dimension_tuples.size());
369
370 for (size_t i = 0; i < tagged_tuples.size(); ++i) {
371 child_to_parent_map[i] = {{child_top_dimension_tuples[i], tagged_tuples[i]}};
372 }
373
374 m_mesh.register_child_mesh(m_soup_ptr, child_to_parent_map);
375}
376
377void MultiMeshFromTag::compute_substructure_mesh()
378{
380
381 Mesh& child = *m_soup_ptr;
382
383 // create attributes to store new ids
385 if (pt == m_tag_ptype) {
386 continue;
387 }
388
389 const int64_t pt_id = get_primitive_type_id(pt);
390
391 const int64_t n_ids = n_local_ids[get_primitive_type_id(m_tag_ptype)][pt_id];
392
393 m_new_id_handles[pt] = child.register_attribute<int64_t>(
394 std::string("multimesh_from_tag_new_ids_") + std::to_string(pt_id),
396 n_ids,
397 false,
398 -1);
399 }
400
402
404
405 std::vector<Tuple> tagged_tuples;
406 {
407 const auto tag_type_tuples = m_mesh.get_all(m_tag_ptype);
408 for (const Tuple& t : tag_type_tuples) {
410 continue;
411 }
412 tagged_tuples.emplace_back(t);
413 }
414 }
415
416 switch (m_soup_ptr->top_simplex_type()) {
418 m_substructure_ptr = std::make_shared<PointMesh>();
419 static_cast<PointMesh&>(*m_substructure_ptr).initialize(tagged_tuples.size());
420 break;
421 }
422 case PrimitiveType::Edge: {
423 const Eigen::MatrixX<int64_t> EV = get_new_id_matrix(PrimitiveType::Vertex);
425 m_substructure_ptr = std::make_shared<EdgeMesh>();
426 static_cast<EdgeMesh&>(*m_substructure_ptr).initialize(EV, adjacency_matrix(), VE);
427 assert(static_cast<EdgeMesh&>(*m_substructure_ptr).is_connectivity_valid());
428 break;
429 }
431 const Eigen::MatrixX<int64_t> FV = get_new_id_matrix(PrimitiveType::Vertex);
432 const Eigen::MatrixX<int64_t> FE = get_new_id_matrix(PrimitiveType::Edge);
435 m_substructure_ptr = std::make_shared<TriMesh>();
436 static_cast<TriMesh&>(*m_substructure_ptr).initialize(FV, FE, adjacency_matrix(), VF, EF);
437 assert(static_cast<TriMesh&>(*m_substructure_ptr).is_connectivity_valid());
438 break;
439 }
441 const Eigen::MatrixX<int64_t> TV = get_new_id_matrix(PrimitiveType::Vertex);
442 const Eigen::MatrixX<int64_t> TE = get_new_id_matrix(PrimitiveType::Edge);
443 const Eigen::MatrixX<int64_t> TF = get_new_id_matrix(PrimitiveType::Triangle);
447 m_substructure_ptr = std::make_shared<TetMesh>();
448 static_cast<TetMesh&>(*m_substructure_ptr)
449 .initialize(TV, TE, TF, adjacency_matrix(), VT, ET, FT);
450 assert(static_cast<TetMesh&>(*m_substructure_ptr).is_connectivity_valid());
451 break;
452 }
453 default: log_and_throw_error("Unknown primitive type for substructure."); break;
454 }
455
456 std::vector<std::array<Tuple, 2>> child_to_parent_map(tagged_tuples.size());
457
458 const auto child_top_dimension_tuples = m_substructure_ptr->get_all(m_tag_ptype);
459
460 assert(tagged_tuples.size() == child_top_dimension_tuples.size());
461
462 for (size_t i = 0; i < tagged_tuples.size(); ++i) {
463 child_to_parent_map[i] = {{child_top_dimension_tuples[i], tagged_tuples[i]}};
464 }
465
466 m_mesh.register_child_mesh(m_substructure_ptr, child_to_parent_map);
467}
468
469bool MultiMeshFromTag::is_substructure_simplex_manifold(const simplex::Simplex& s) const
470{
471 const simplex::Simplex s_in_root = m_substructure_ptr->map_to_parent(s);
472
473 return is_root_simplex_manifold(s_in_root);
474}
475
476bool MultiMeshFromTag::is_root_simplex_manifold(const simplex::Simplex& s) const
477{
478 const std::vector<simplex::Simplex> s_in_sub = m_mesh.map_to_child(*m_substructure_ptr, s);
479
480 return s_in_sub.size() < 2;
481}
482
483} // namespace wmtk::components::internal
bool is_connectivity_valid() const override
Definition EdgeMesh.cpp:236
void initialize_free(int64_t count)
Definition EdgeMesh.cpp:141
void initialize(Eigen::Ref< const RowVectors2l > E, bool is_free=false)
Definition EdgeMesh.cpp:132
attribute::MeshAttributeHandle register_attribute(const std::string &name, PrimitiveType type, int64_t size, bool replace=false, T default_value=T(0))
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
std::vector< Tuple > get_all(PrimitiveType type) const
Generate a vector of Tuples from global vertex/edge/triangle/tetrahedron index.
Definition Mesh.cpp:18
void register_child_mesh(const std::shared_ptr< Mesh > &child_mesh_ptr, const std::vector< std::array< Tuple, 2 > > &map_tuples)
register a mesh as the child of this mesh
simplex::Simplex map_to_parent(const simplex::Simplex &my_simplex) const
optimized map from a simplex from this mesh to its direct parent
void deregister_child_mesh(const std::shared_ptr< Mesh > &child_mesh_ptr)
Deregister a child mesh.
std::vector< simplex::Simplex > map_to_child(const Mesh &child_mesh, const simplex::Simplex &my_simplex) const
optimized map fromsimplex from this mesh to one of its direct children
void initialize(int64_t count)
Definition PointMesh.cpp:51
void initialize_free(int64_t count)
Definition TetMesh.cpp:148
void initialize(Eigen::Ref< const RowVectors4l > TV, Eigen::Ref< const RowVectors6l > TE, Eigen::Ref< const RowVectors4l > TF, Eigen::Ref< const RowVectors4l > TT, Eigen::Ref< const VectorXl > VT, Eigen::Ref< const VectorXl > ET, Eigen::Ref< const VectorXl > FT)
Definition TetMesh.cpp:79
bool is_connectivity_valid() const final override
Definition TetMesh.cpp:400
bool is_connectivity_valid() const final override
Definition TriMesh.cpp:359
void initialize_free(int64_t count)
Definition TriMesh.cpp:236
void initialize(Eigen::Ref< const RowVectors3l > FV, Eigen::Ref< const RowVectors3l > FE, Eigen::Ref< const RowVectors3l > FF, Eigen::Ref< const VectorXl > VF, Eigen::Ref< const VectorXl > EF)
Definition TriMesh.cpp:176
The Tuple is the basic navigation tool in our mesh data structure.
Definition Tuple.hpp:19
A CachingAccessor that uses tuples for accessing attributes instead of indices.
Definition Accessor.hpp:28
T const_scalar_attribute(const ArgType &t) const
Definition Accessor.hxx:109
MapResult< D > vector_attribute(const ArgType &t)
ConstMapResult< D > const_vector_attribute(const ArgType &t) const
void build_adjacency_matrix()
Create the adjacency (stored as attribute) of the substructure.
Eigen::MatrixX< int64_t > get_new_id_matrix(const PrimitiveType ptype) const
const attribute::Accessor< int64_t > m_tag_acc
std::vector< Tuple > get_connected_region(const Tuple &t, const PrimitiveType ptype)
Get tuples with different global_cid that all represent simplex(t_in, ptype) and are in the same tag-...
bool is_root_simplex_manifold(const simplex::Simplex &s) const
std::map< PrimitiveType, VectorXl > m_new_top_coface_vectors
std::map< PrimitiveType, attribute::MeshAttributeHandle > m_new_id_handles
Eigen::MatrixX< int64_t > adjacency_matrix() const
void create_substructure_soup()
Create a multimesh where the child-mesh is just a soup (no connectivity) of m_mesh.
VectorXl get_new_top_coface_vector(const PrimitiveType ptype) const
std::map< PrimitiveType, Eigen::MatrixX< int64_t > > m_new_id_matrices
attribute::MeshAttributeHandle m_adjacency_handle
void compute_substructure_ids()
Compute the ids of the manifold substructure.
std::vector< Tuple > tuples_preserving_primitive_types(const Mesh &mesh, const Tuple &t, const PrimitiveType simplex_ptype, const PrimitiveType face_ptype)
Compute all tuples that contain simplex(ptype1, t) and that are contained by simplex(ptype2,...
std::vector< Tuple > faces_single_dimension_tuples(const Mesh &mesh, const Simplex &simplex, const PrimitiveType face_type)
constexpr PrimitiveType get_primitive_type_from_id(int8_t id)
Get the primitive type corresponding to its unique integer id.
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:101
constexpr int8_t get_primitive_type_id(PrimitiveType t)
Get a unique integer id corresponding to each primitive type.
VectorX< int64_t > VectorXl
Definition Types.hpp:33