Wildmeshing Toolkit
MultiMeshFromTag.cpp
Go to the documentation of this file.
1 #include "MultiMeshFromTag.hpp"
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 
16 constexpr 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 
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 
35 Eigen::MatrixX<int64_t> MultiMeshFromTag::get_new_id_matrix(const PrimitiveType ptype) const
36 {
37  return m_new_id_matrices.at(ptype);
38 }
39 
41 {
42  return m_new_top_coface_vectors.at(ptype);
43 }
44 
45 Eigen::MatrixX<int64_t> MultiMeshFromTag::adjacency_matrix() const
46 {
47  return m_adjacency_matrix;
48 }
49 
50 std::shared_ptr<Mesh> MultiMeshFromTag::substructure_soup() const
51 {
52  return m_soup_ptr;
53 }
54 
55 std::shared_ptr<Mesh> MultiMeshFromTag::substructure() const
56 {
57  return m_substructure_ptr;
58 }
59 
61 {
63 }
64 
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 
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 
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",
249  m_tag_ptype,
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",
260  m_tag_ptype,
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 
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) {
341  case PrimitiveType::Vertex: {
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 
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),
395  m_tag_ptype,
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()) {
417  case PrimitiveType::Vertex: {
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 
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 
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))
std::vector< Tuple > get_all(PrimitiveType type) const
Generate a vector of Tuples from global vertex/edge/triangle/tetrahedron index.
Definition: Mesh.cpp:18
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
simplex::Simplex map_to_parent(const simplex::Simplex &my_simplex) const
optimized map from a simplex from this mesh to its direct parent
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
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:145
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:78
bool is_connectivity_valid() const final override
Definition: TetMesh.cpp:414
bool is_connectivity_valid() const final override
Definition: TriMesh.cpp:370
void initialize_free(int64_t count)
Definition: TriMesh.cpp:235
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:175
MapResult< D > vector_attribute(const ArgType &t)
T const_scalar_attribute(const ArgType &t) const
Definition: Accessor.hxx:112
ConstMapResult< D > const_vector_attribute(const ArgType &t) const
void build_adjacency_matrix()
Create the adjacency (stored as attribute) of the substructure.
void remove_soup()
Remove the substructure soup from the multimesh.
std::shared_ptr< Mesh > substructure_soup() const
Returns a pointer to the substructure soup.
std::shared_ptr< Mesh > substructure() const
Returns a pointer to the manifold substructure mesh.
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
void compute_substructure_mesh()
Create a manifold mesh from the substructure.
std::map< PrimitiveType, attribute::MeshAttributeHandle > m_new_id_handles
Eigen::MatrixX< int64_t > adjacency_matrix() const
MultiMeshFromTag(Mesh &mesh, const attribute::MeshAttributeHandle &tag_handle, const int64_t tag_value)
void create_substructure_soup()
Create a multimesh where the child-mesh is just a soup (no connectivity) of m_mesh.
bool is_substructure_simplex_manifold(const simplex::Simplex &s) const
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)
std::vector< PrimitiveType > primitive_below(PrimitiveType pt, bool lower_to_upper)
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