Wildmeshing Toolkit
MultiMeshManager.cpp
Go to the documentation of this file.
1 #include "MultiMeshManager.hpp"
2 #include <cassert>
4 //#include <fmt/ranges.h>
5 #include <functional>
6 #include <wmtk/Mesh.hpp>
13 #include <wmtk/utils/Logger.hpp>
19 
20 namespace wmtk::multimesh {
21 
22 namespace {} // namespace
23 
24 
26 {
27  for (auto& data : m_children) {
28  auto& m = *data.mesh;
29  m.m_multi_mesh_manager.m_parent = nullptr;
30  m.m_multi_mesh_manager.m_child_id = -1;
31  // TODO: delete attributes
32  }
33 
34  m_children.clear();
35 }
36 
38  const Mesh& source_mesh,
39  const Mesh& target_mesh,
40  const wmtk::attribute::Accessor<int64_t>& map_accessor,
41  const Tuple& source_tuple)
42 {
43  assert(source_mesh.is_valid(source_tuple));
44 
45  PrimitiveType source_mesh_primitive_type = source_mesh.top_simplex_type();
46  PrimitiveType target_mesh_primitive_type = target_mesh.top_simplex_type();
47  PrimitiveType min_primitive_type =
48  std::min(source_mesh_primitive_type, target_mesh_primitive_type);
49  Tuple source_mesh_target_tuple = source_tuple;
50  auto [source_mesh_base_tuple, target_mesh_base_tuple] =
51  multimesh::utils::read_tuple_map_attribute(map_accessor, source_tuple);
52 
53  if (source_mesh_base_tuple.is_null() || target_mesh_base_tuple.is_null()) {
54  return Tuple(); // return null tuple
55  }
56 
57  // assert(source_mesh.is_valid(source_mesh_base_tuple));
58  // assert(target_mesh.is_valid(target_mesh_base_tuple));
59 
60 
61  if (source_mesh_base_tuple.m_global_cid != source_mesh_target_tuple.m_global_cid) {
62  // guarantee that the source and target tuples refer to the same simplex
63  assert(source_mesh_primitive_type > target_mesh_primitive_type);
64  const std::vector<Tuple> equivalent_tuples = simplex::top_dimension_cofaces_tuples(
65  source_mesh,
66  simplex::Simplex(source_mesh, target_mesh_primitive_type, source_tuple));
67  for (const Tuple& t : equivalent_tuples) {
68  if (t.m_global_cid == source_mesh_base_tuple.m_global_cid) {
69  // specific for tet->edge
70  if (source_mesh_primitive_type == PrimitiveType::Tetrahedron &&
71  target_mesh_primitive_type == PrimitiveType::Edge) {
72  if (t.m_local_fid == source_mesh_base_tuple.m_local_fid) {
73  source_mesh_target_tuple = t;
74  break;
75  } else {
76  source_mesh_target_tuple =
77  source_mesh.switch_tuple(t, PrimitiveType::Triangle);
78  break;
79  }
80  } else {
81  source_mesh_target_tuple = t;
82  break;
83  }
84  }
85  }
86  }
87 
88  if (source_mesh_primitive_type == PrimitiveType::Tetrahedron &&
89  target_mesh_primitive_type == PrimitiveType::Edge) {
90  if (source_mesh_target_tuple.m_local_fid != source_mesh_base_tuple.m_local_fid) {
91  source_mesh_target_tuple =
92  source_mesh.switch_tuple(source_mesh_target_tuple, PrimitiveType::Triangle);
93  }
94  }
95 
96  assert(
97  source_mesh_base_tuple.m_global_cid ==
98  source_mesh_target_tuple
99  .m_global_cid); // make sure that local tuple operations will find a valid sequence
100 
101  // we want to repeat switches from source_base_tuple -> source_tuple to
102  // target_base _tuple -> return value
103  //
105  source_mesh_base_tuple,
106  source_mesh_target_tuple,
107  source_mesh_primitive_type,
108  target_mesh_base_tuple,
109  target_mesh_primitive_type);
110 }
111 
112 
114  : m_has_child_mesh_in_dimension(dimension, false)
115 {}
116 
122 
123 // attribute directly hashes its "children" components so it overrides "child_hashes"
124 std::map<std::string, const wmtk::utils::Hashable*> MultiMeshManager::child_hashables() const
125 {
126  std::map<std::string, const wmtk::utils::Hashable*> ret;
127  for (const auto& c : m_children) {
128  assert(bool(c.mesh));
129  auto id = c.mesh->absolute_multi_mesh_id();
130  std::string name = fmt::format("child_map_[{}]", fmt::join(id, ","));
131  ret[name] = c.mesh.get();
132  }
133  return ret;
134 }
135 std::map<std::string, std::size_t> MultiMeshManager::child_hashes() const
136 {
137  // default implementation pulls the child attributes (ie the attributes)
138  std::map<std::string, std::size_t> ret = wmtk::utils::MerkleTreeInteriorNode::child_hashes();
139  ret["child_id"] = m_child_id;
140 
141  if (m_parent != nullptr) {
142  auto id = m_parent->absolute_multi_mesh_id();
143  ret["parent_map"] = wmtk::utils::vector_hash(id);
144  } else {
145  ret["parent_map"] = 0;
146  }
147 
148 
149  const std::hash<TypedAttributeHandle<int64_t>> attr_hasher;
150  ret["parent_map_handle"] = attr_hasher(map_to_parent_handle);
151  for (const auto& c : m_children) {
152  assert(bool(c.mesh));
153  auto id = c.mesh->absolute_multi_mesh_id();
154  std::string name = fmt::format("child_map_[{}]", fmt::join(id, ","));
155  ret[name] = attr_hasher(c.map_handle);
156  }
157  return ret;
158 }
159 
161 {
162  return m_parent == nullptr;
163 }
164 
166 {
167  if (is_root()) {
168  throw std::runtime_error("Tried to access the child id of a mesh that is in fact a root");
169  }
170  return m_child_id;
171 }
172 
173 std::vector<int64_t> MultiMeshManager::absolute_id() const
174 {
175  if (is_root()) {
176  return {};
177  } else {
179  id.emplace_back(m_child_id);
180  return id;
181  }
182 }
183 std::vector<int64_t> MultiMeshManager::relative_id(const Mesh& my_mesh, const Mesh& parent) const
184 {
185  assert(is_child(my_mesh, parent));
186  if (&parent == &my_mesh) {
187  return {};
188  } else {
189  assert(!is_root());
190  auto id = m_parent->m_multi_mesh_manager.relative_id(*m_parent, parent);
191  id.emplace_back(m_child_id);
192  return id;
193  }
194 }
195 
196 bool MultiMeshManager::is_child(const Mesh& my_mesh, const Mesh& parent_mesh) const
197 {
198  if (&parent_mesh == &my_mesh) {
199  return true;
200  } else {
201  if (is_root()) {
202  return false;
203  } else {
204  return m_parent->m_multi_mesh_manager.is_child(*m_parent, parent_mesh);
205  }
206  }
207 }
208 
209 
211  Mesh& my_mesh,
212  const std::shared_ptr<Mesh>& child_mesh_ptr,
213  const std::vector<std::array<Tuple, 2>>& child_tuple_my_tuple_map)
214 {
215  assert((&my_mesh.m_multi_mesh_manager) == this);
216  assert(bool(child_mesh_ptr));
217 
218  Mesh& child_mesh = *child_mesh_ptr;
219 
220  const PrimitiveType child_primitive_type = child_mesh.top_simplex_type();
221  const int64_t new_child_id = int64_t(m_children.size());
222 
224 
225  auto child_to_parent_handle = child_mesh.register_attribute_typed<int64_t>(
227  child_primitive_type,
228  wmtk::multimesh::utils::TWO_TUPLE_SIZE,
229  false,
230  wmtk::multimesh::utils::DEFAULT_TUPLES_VALUES);
231 
232  // TODO: make sure that this attribute doesnt already exist
233  auto parent_to_child_handle = my_mesh.register_attribute_typed<int64_t>(
235  child_primitive_type,
236  wmtk::multimesh::utils::TWO_TUPLE_SIZE,
237  false,
238  wmtk::multimesh::utils::DEFAULT_TUPLES_VALUES);
239 
240 
241  auto child_to_parent_accessor = child_mesh.create_accessor(child_to_parent_handle);
242  auto parent_to_child_accessor = my_mesh.create_accessor(parent_to_child_handle);
243 
244 
245  MultiMeshManager& child_manager = child_mesh.m_multi_mesh_manager;
246 
247  // update on child_mesh
248  child_manager.map_to_parent_handle = child_to_parent_handle;
249  child_manager.m_child_id = new_child_id;
250  child_manager.m_parent = &my_mesh;
251 
252  // update myself
253  m_children.emplace_back(ChildData{child_mesh_ptr, parent_to_child_handle});
254 
255  // register maps
256  for (const auto& [child_tuple, my_tuple] : child_tuple_my_tuple_map) {
257  assert(my_mesh.is_valid(my_tuple));
258  assert(child_mesh_ptr->is_valid(child_tuple));
260  parent_to_child_accessor,
261  child_to_parent_accessor,
262  my_tuple,
263  child_tuple);
264  }
265 }
266 
268  Mesh& my_mesh,
269  const std::shared_ptr<Mesh>& child_mesh_ptr)
270 {
271  Mesh& child_mesh = *child_mesh_ptr;
272 
273  MultiMeshManager& child_manager = child_mesh.m_multi_mesh_manager;
274  MultiMeshManager& parent_manager = my_mesh.m_multi_mesh_manager;
275 
276 
277  auto& child_to_parent_handle = child_manager.map_to_parent_handle;
278 
279  const int64_t child_id = child_manager.child_id();
280  ChildData& child_data = parent_manager.m_children[child_id];
281  auto& parent_to_child_handle = child_data.map_handle;
282 
283  assert(child_data.mesh == child_mesh_ptr);
284  assert(child_manager.children()
285  .empty()); // The current implementation does not update the attributes properly for
286  // the case that the child also has children
287 
288  // remove map attribute from parent
289  my_mesh.m_attribute_manager.get<int64_t>(child_mesh.top_simplex_type())
290  .remove_attributes({parent_to_child_handle.base_handle()});
291 
292  // remove map attribute from child
293  child_mesh.m_attribute_manager.get<int64_t>(child_mesh.top_simplex_type())
294  .remove_attributes({child_to_parent_handle.base_handle()});
295 
296  // set child_id to -1 --> make it a root
297  child_manager.m_child_id = -1;
298  // remove parent pointer
299  child_manager.m_parent = nullptr;
300 
301  // remove child_data from parent
302  auto& children = parent_manager.m_children;
303  children.erase(children.begin() + child_id);
304 
305  update_child_handles(my_mesh);
306 }
307 
308 
309 std::vector<wmtk::attribute::TypedAttributeHandle<int64_t>> MultiMeshManager::map_handles() const
310 {
311  std::vector<wmtk::attribute::TypedAttributeHandle<int64_t>> handles;
313  handles.emplace_back(map_to_parent_handle);
314  }
315  for (const auto& cd : m_children) {
316  handles.emplace_back(cd.map_handle);
317  }
318  return handles;
319 }
320 
321 /*
322  * TODO: It is the consumer's responsibility to generate the identity map via a utility function
323 void MultiMeshManager::register_child_mesh(
324  Mesh& my_mesh,
325  std::shared_ptr<Mesh> child_mesh,
326  const std::vector<int64_t>& child_mesh_simplex_id_map)
327 {
328  PrimitiveType map_type = child_mesh->top_simplex_type();
329  std::vector<std::array<Tuple, 2>> child_tuple_my_tuple_map;
330 
331  for (int64_t child_cell_id = 0; child_cell_id < int64_t(child_mesh_simplex_id_map.size());
332  ++child_cell_id) {
333  int64_t parent_cell_id = child_mesh_simplex_id_map[child_cell_id];
334  child_tuple_my_tuple_map.push_back(
335  {child_mesh->tuple_from_id(map_type, child_cell_id),
336  my_mesh.tuple_from_id(map_type, parent_cell_id)});
337  }
338  register_child_mesh(my_mesh, child_mesh, child_tuple_my_tuple_map);
339 }
340 */
341 
342 const Mesh& MultiMeshManager::get_root_mesh(const Mesh& my_mesh) const
343 {
344  if (is_root()) {
345  return my_mesh;
346  } else {
348  }
349 }
351 {
352  if (is_root()) {
353  return my_mesh;
354  } else {
356  }
357 }
358 
360  const Mesh& my_mesh,
361  const std::vector<int64_t>& relative_id) const
362 {
363  assert((&my_mesh.m_multi_mesh_manager) == this);
364 
365  const Mesh* cur_mesh = &my_mesh;
366 
367  for (auto it = relative_id.cbegin(); it != relative_id.cend(); ++it) {
368  // get the select ID from the child map
369  int64_t child_index = *it;
370  const ChildData& cd = cur_mesh->m_multi_mesh_manager.m_children.at(child_index);
371 
372  cur_mesh = cd.mesh.get();
373 
374  // the front id of the current mesh should be the child index from this iteration
375  assert(cur_mesh->m_multi_mesh_manager.m_child_id == child_index);
376  }
377 
378  return *cur_mesh;
379 }
380 Mesh& MultiMeshManager::get_child_mesh(Mesh& my_mesh, const std::vector<int64_t>& relative_id)
381 {
382  return const_cast<Mesh&>(get_child_mesh(const_cast<const Mesh&>(my_mesh), relative_id));
383 }
384 const Mesh& MultiMeshManager::get_mesh(const Mesh& my_mesh, const std::vector<int64_t>& absolute_id)
385  const
386 {
387  const Mesh& root = get_root_mesh(my_mesh);
389 }
390 
391 Mesh& MultiMeshManager::get_mesh(Mesh& my_mesh, const std::vector<int64_t>& absolute_id)
392 {
393  Mesh& root = get_root_mesh(my_mesh);
395 }
396 std::vector<std::shared_ptr<Mesh>> MultiMeshManager::get_child_meshes() const
397 {
398  std::vector<std::shared_ptr<Mesh>> ret;
399  ret.reserve(m_children.size());
400  for (const ChildData& cd : m_children) {
401  ret.emplace_back(cd.mesh);
402  }
403  return ret;
404 }
405 
406 std::vector<simplex::Simplex> MultiMeshManager::map(
407  const Mesh& my_mesh,
408  const Mesh& other_mesh,
409  const simplex::Simplex& my_simplex) const
410 {
411  const auto ret_tups = map_tuples(my_mesh, other_mesh, my_simplex);
413  other_mesh,
414  ret_tups,
415  my_simplex.primitive_type());
416 }
417 std::vector<simplex::Simplex> MultiMeshManager::lub_map(
418  const Mesh& my_mesh,
419  const Mesh& other_mesh,
420  const simplex::Simplex& my_simplex) const
421 {
422  if (&my_mesh == &other_mesh) {
423  return {my_simplex};
424  }
425  const auto ret_tups = lub_map_tuples(my_mesh, other_mesh, my_simplex);
427  other_mesh,
428  ret_tups,
429  my_simplex.primitive_type());
430 }
431 
432 std::pair<const Mesh&, Tuple> MultiMeshManager::map_up_to_tuples(
433  const Mesh& my_mesh,
434  const simplex::Simplex& my_simplex,
435  int64_t depth) const
436 {
437  assert((&my_mesh.m_multi_mesh_manager) == this);
438  const PrimitiveType pt = my_simplex.primitive_type();
439 
440  // get a root tuple by converting the tuple up parent meshes until root is found
441  Tuple cur_tuple = my_simplex.tuple();
442  const Mesh* cur_mesh = &my_mesh;
443  for (int64_t d = 0; d < depth; ++d) {
444  cur_tuple = cur_mesh->m_multi_mesh_manager.map_tuple_to_parent_tuple(*cur_mesh, cur_tuple);
445  cur_mesh = cur_mesh->m_multi_mesh_manager.m_parent;
446  assert(cur_mesh != nullptr);
447  }
448  // assert(cur_mesh->m_multi_mesh_manager
449  // .is_root()); // cur_mesh == nullptr if we just walked past the root node so we stop
450 
451  // bieng lazy about how i set cur_mesh to nullptr above - could simplify the loop to optimize
452  return std::pair<const Mesh&, Tuple>(*cur_mesh, cur_tuple);
453 }
454 
456  const Mesh& my_mesh,
457  const simplex::Simplex& my_simplex,
458  const std::vector<int64_t>& relative_id) const
459 {
460  assert((&my_mesh.m_multi_mesh_manager) == this);
461 
462  const PrimitiveType pt = my_simplex.primitive_type();
463  // note that (cur_mesh, tuples) always match (i.e tuples are tuples from cur_mesh)
464  std::vector<Tuple> tuples;
465  tuples.emplace_back(my_simplex.tuple());
466  const Mesh* cur_mesh = &my_mesh;
467 
468  for (auto it = relative_id.cbegin(); it != relative_id.cend(); ++it) {
469  // get the select ID from the child map
470  int64_t child_index = *it;
471  const ChildData& cd = cur_mesh->m_multi_mesh_manager.m_children.at(child_index);
472 
473  // for every tuple we have try to collect all versions
474  std::vector<Tuple> new_tuples;
475  for (const Tuple& t : tuples) {
476  // get new tuples for every version that exists
477  std::vector<Tuple> n = cur_mesh->m_multi_mesh_manager.map_to_child_tuples(
478  *cur_mesh,
479  cd,
480  simplex::Simplex(*cur_mesh, pt, t));
481  // append to the current set of new tuples
482  new_tuples.insert(new_tuples.end(), n.begin(), n.end());
483  }
484  // update the (mesh,tuples) pair
485  tuples = std::move(new_tuples);
486  cur_mesh = cd.mesh.get();
487 
488  // the front id of the current mesh should be the child index from this iteration
489  assert(cur_mesh->m_multi_mesh_manager.m_child_id == child_index);
490  }
491 
492  // visitor.map(equivalent_tuples, my_simplex.primitive_type());
493 
494  return tuples;
495 }
496 
497 std::vector<Tuple> MultiMeshManager::map_tuples(
498  const Mesh& my_mesh,
499  const Mesh& other_mesh,
500  const simplex::Simplex& my_simplex) const
501 {
502  const auto my_id = absolute_id();
503  const auto other_id = other_mesh.absolute_multi_mesh_id();
504 
505  int64_t depth = my_id.size();
506 
507  auto [root_ref, tuple] = map_up_to_tuples(my_mesh, my_simplex, depth);
508  const simplex::Simplex simplex(root_ref, my_simplex.primitive_type(), tuple);
509 
510  return root_ref.m_multi_mesh_manager.map_down_relative_tuples(root_ref, simplex, other_id);
511 }
512 
514  const Mesh& my_mesh,
515  const Mesh& other_mesh,
516  const simplex::Simplex& my_simplex) const
517 {
518  if (&my_mesh == &other_mesh) {
519  return {my_simplex.tuple()};
520  }
521  const auto my_id = absolute_id();
522  const auto other_id = other_mesh.absolute_multi_mesh_id();
523  const auto lub_id = least_upper_bound_id(my_id, other_id);
524 
525  int64_t depth = my_id.size() - lub_id.size();
526 
527  auto [local_root_ref, tuple] = map_up_to_tuples(my_mesh, my_simplex, depth);
528  assert(other_mesh.m_multi_mesh_manager.is_child(other_mesh, local_root_ref));
529 
530  const simplex::Simplex simplex(local_root_ref, my_simplex.primitive_type(), tuple);
531 
532  auto other_relative_id = relative_id(lub_id, other_id);
533  return local_root_ref.m_multi_mesh_manager.map_down_relative_tuples(
534  local_root_ref,
535  simplex,
536  other_relative_id);
537 }
538 
540  const Mesh& my_mesh,
541  const simplex::Simplex& my_simplex) const
542 {
543  return simplex::Simplex(my_simplex.primitive_type(), map_to_root_tuple(my_mesh, my_simplex));
544 }
545 
547  const
548 {
549  const Tuple t = map_tuple_to_root_tuple(my_mesh, my_simplex.tuple());
550  assert(get_root_mesh(my_mesh).is_valid(t));
551  return t;
552 }
553 Tuple MultiMeshManager::map_tuple_to_root_tuple(const Mesh& my_mesh, const Tuple& my_tuple) const
554 {
555  assert(&my_mesh.m_multi_mesh_manager == this);
556  if (my_mesh.m_multi_mesh_manager.is_root()) {
557  assert(my_mesh.is_valid(my_tuple));
558  return my_tuple;
559  } else {
560  const Tuple ptup = map_tuple_to_parent_tuple(my_mesh, my_tuple);
561  assert(m_parent->is_valid(ptup));
563  }
564 }
565 
566 
568  const Mesh& my_mesh,
569  const simplex::Simplex& my_simplex) const
570 {
571  return simplex::Simplex(
572  my_simplex.primitive_type(),
573  map_tuple_to_parent_tuple(my_mesh, my_simplex.tuple()));
574 }
576  const
577 {
578  return map_tuple_to_parent_tuple(my_mesh, my_simplex.tuple());
579 }
580 
581 Tuple MultiMeshManager::map_tuple_to_parent_tuple(const Mesh& my_mesh, const Tuple& my_tuple) const
582 {
583  assert((&my_mesh.m_multi_mesh_manager) == this);
584  assert(!is_root());
585 
586  const Mesh& parent_mesh = *m_parent;
587 
588  const auto& map_handle = map_to_parent_handle;
589  // assert(!map_handle.is_null());
590 
591  auto map_accessor = my_mesh.create_const_accessor(map_handle);
592  return map_tuple_between_meshes(my_mesh, parent_mesh, map_accessor, my_tuple);
593 }
594 
595 
597  const Mesh& my_mesh,
598  const ChildData& child_data,
599  const simplex::Simplex& my_simplex) const
600 {
601  assert((&my_mesh.m_multi_mesh_manager) == this);
602 
603  const Mesh& child_mesh = *child_data.mesh;
604  if (child_mesh.top_simplex_type() < my_simplex.primitive_type()) {
605  return {};
606  }
607  const auto map_handle = child_data.map_handle;
608  // we will overwrite these tuples inline with the mapped ones while running down the map
609  // functionalities
610 
611  std::vector<Tuple> tuples = simplex::cofaces_single_dimension_tuples(
612  my_mesh,
613  my_simplex,
614  child_mesh.top_simplex_type());
615 
616  /*
617  get all tuples of child mesh top simplex type that contain my_simplex
618  */
619 
620  auto map_accessor = my_mesh.create_const_accessor(map_handle);
621  for (Tuple& tuple : tuples) {
622  tuple = map_tuple_between_meshes(my_mesh, child_mesh, map_accessor, tuple);
623  }
624  tuples.erase(
625  std::remove_if(
626  tuples.begin(),
627  tuples.end(),
628  [](const Tuple& t) -> bool { return t.is_null(); }),
629  tuples.end());
630  tuples =
631  wmtk::simplex::utils::make_unique_tuples(child_mesh, tuples, my_simplex.primitive_type());
632 
633  return tuples;
634 }
635 
637  const Mesh& my_mesh,
638  const Mesh& child_mesh,
639  const simplex::Simplex& my_simplex) const
640 {
641  return map_to_child_tuples(my_mesh, child_mesh.m_multi_mesh_manager.child_id(), my_simplex);
642 }
643 
645  const Mesh& my_mesh,
646  int64_t child_id,
647  const simplex::Simplex& my_simplex) const
648 {
649  // this is just to do a little redirection for simpplifying map_to_child (and potentially for a
650  // visitor pattern)
651  return map_to_child_tuples(my_mesh, m_children.at(child_id), my_simplex);
652 }
653 
654 std::vector<simplex::Simplex> MultiMeshManager::map_to_child(
655  const Mesh& my_mesh,
656  const Mesh& child_mesh,
657  const simplex::Simplex& my_simplex) const
658 {
659  auto tuples = map_to_child_tuples(my_mesh, child_mesh, my_simplex);
660 
662  child_mesh,
663  tuples,
664  my_simplex.primitive_type());
665 }
666 
667 
668 std::vector<std::array<Tuple, 2>> MultiMeshManager::same_simplex_dimension_surjection(
669  const Mesh& parent,
670  const Mesh& child,
671  const std::vector<int64_t>& parent_simplices)
672 {
673  PrimitiveType primitive_type = parent.top_simplex_type();
674 #if !defined(NDEBUG)
675  if (primitive_type != child.top_simplex_type()) {
676  throw std::runtime_error(
677  "Cannot use same_simplex_dimension_bijection on meshes with simplex dimensions");
678  }
679 #endif
680 
681  int64_t size = child.capacity(primitive_type);
682  assert(size == int64_t(parent_simplices.size()));
683  std::vector<std::array<Tuple, 2>> ret;
684  ret.reserve(size);
685 
686  auto parent_flag_accessor = parent.get_const_flag_accessor(primitive_type);
687  auto child_flag_accessor = child.get_const_flag_accessor(primitive_type);
688 
689  for (int64_t index = 0; index < size; ++index) {
690  const Tuple ct = child.tuple_from_id(primitive_type, index);
691  const Tuple pt = parent.tuple_from_id(primitive_type, parent_simplices.at(index));
692  if ((parent_flag_accessor.const_scalar_attribute(pt) & 1) == 0) {
693  continue;
694  }
695  if ((child_flag_accessor.const_scalar_attribute(ct) & 1) == 0) {
696  continue;
697  }
698 
699  ret.emplace_back(std::array<Tuple, 2>{{ct, pt}});
700  }
701  return ret;
702 }
703 
705 {
706  return fmt::format("map_to_child_{}", index);
707 }
708 std::array<wmtk::attribute::Accessor<int64_t>, 2> MultiMeshManager::get_map_accessors(
709  Mesh& my_mesh,
710  ChildData& c)
711 {
712  Mesh& child_mesh = *c.mesh;
713  const auto& child_to_parent_handle = child_mesh.m_multi_mesh_manager.map_to_parent_handle;
714  const auto& parent_to_child_handle = c.map_handle;
715 
716 
717  return std::array<wmtk::attribute::Accessor<int64_t>, 2>{
718  {my_mesh.create_accessor(parent_to_child_handle),
719  child_mesh.create_accessor(child_to_parent_handle)}};
720 }
721 std::array<const wmtk::attribute::Accessor<int64_t>, 2> MultiMeshManager::get_map_const_accessors(
722  const Mesh& my_mesh,
723  const ChildData& c) const
724 {
725  const Mesh& child_mesh = *c.mesh;
726  const auto& child_to_parent_handle = child_mesh.m_multi_mesh_manager.map_to_parent_handle;
727  const auto& parent_to_child_handle = c.map_handle;
728 
729 
730  return std::array<const wmtk::attribute::Accessor<int64_t>, 2>{
731  {my_mesh.create_const_accessor(parent_to_child_handle),
732  child_mesh.create_const_accessor(child_to_parent_handle)}};
733 }
735 {
736  return "map_to_parent";
737 }
738 
739 
740 // remove after bug fix
741 void MultiMeshManager::check_map_valid(const Mesh& my_mesh) const
742 {
743  for (int64_t index = 0; index < int64_t(children().size()); ++index) {
744  const auto& child_data = children()[index];
745  assert(bool(child_data.mesh));
746  assert(child_data.mesh->absolute_multi_mesh_id().front() == index);
747  check_child_map_valid(my_mesh, child_data);
748  }
749 }
750 
751 void MultiMeshManager::check_child_map_valid(const Mesh& my_mesh, const ChildData& child_data) const
752 {
753  const Mesh& child_mesh = *child_data.mesh;
754  const auto parent_to_child_handle = child_data.map_handle;
755  PrimitiveType map_type = child_mesh.top_simplex_type();
756 
757  const std::string c_to_p_name = child_to_parent_map_attribute_name();
758 
759  assert(child_mesh.has_attribute<int64_t>(c_to_p_name, map_type));
760  auto child_to_parent_handle =
761  child_mesh.get_attribute_handle<int64_t>(c_to_p_name, map_type).as<int64_t>();
762  auto child_cell_flag_accessor = child_mesh.get_flag_accessor(map_type);
763 
764  auto all_child_tuples = child_mesh.get_all(map_type);
765 
766  for (const Tuple& child_tuple : all_child_tuples) {
767  logger().debug(
768  "[{} -> {}] Checking child tuple {}",
769  fmt::join(absolute_id(), ","),
770  fmt::join(child_mesh.absolute_multi_mesh_id(), ","),
772  // 1. test if all maps in child_mesh exisits
773  auto [child_tuple_from_child, parent_tuple_from_child] =
775  child_mesh,
776  child_to_parent_handle,
777  child_tuple);
778 
779  // 2. test if tuples in maps are valid (and up_to_date)
780  {
781  logger().debug(
782  "[{} -> {}] Checking asserts from child {} {} (input tuple was {})",
783  fmt::join(absolute_id(), ","),
784  fmt::join(child_mesh.absolute_multi_mesh_id(), ","),
785  wmtk::utils::TupleInspector::as_string(child_tuple_from_child),
786  wmtk::utils::TupleInspector::as_string(child_tuple_from_child),
788  assert(child_mesh.is_valid(child_tuple_from_child));
789  assert(child_mesh.is_valid(child_tuple_from_child));
790  assert(my_mesh.is_valid(parent_tuple_from_child));
791  }
792 
793  // 3. test if map is symmetric
794  {
795  auto [parent_tuple_from_parent, child_tuple_from_parent] =
797  my_mesh,
798  parent_to_child_handle,
799  parent_tuple_from_child);
800  logger().debug(
801  "[{} -> {}] Checking asserts from child {} {}",
802  fmt::join(absolute_id(), ","),
803  fmt::join(child_mesh.absolute_multi_mesh_id(), ","),
804  wmtk::utils::TupleInspector::as_string(parent_tuple_from_parent),
805  wmtk::utils::TupleInspector::as_string(child_tuple_from_parent));
806 
807  assert(
808  (child_tuple_from_child == child_tuple_from_parent &&
809  parent_tuple_from_child == parent_tuple_from_parent));
810  }
811 
812  // 4. test switch_top_simplex operation
813  // for 4, current code support only mapping between triangle meshes
814  if (map_type == PrimitiveType::Triangle &&
816  Tuple cur_child_tuple = child_tuple_from_child;
817  Tuple cur_parent_tuple = parent_tuple_from_child;
818 
819  auto child_to_parent_accessor =
820  child_mesh.create_const_accessor(child_to_parent_handle);
821  for (int i = 0; i < 3; i++) {
822  if (!child_mesh.is_boundary(PrimitiveType::Edge, cur_child_tuple)) {
823  assert(!my_mesh.is_boundary(PrimitiveType::Edge, cur_parent_tuple));
824 
825 #ifndef NDEBUG
826  Tuple child_tuple_opp =
827  child_mesh.switch_tuple(cur_child_tuple, PrimitiveType::Triangle);
828  Tuple parent_tuple_opp =
829  my_mesh.switch_tuple(cur_parent_tuple, PrimitiveType::Triangle);
830  assert(
831  parent_tuple_opp == map_tuple_between_meshes(
832  child_mesh,
833  my_mesh,
834  child_to_parent_accessor,
835  child_tuple_opp));
836 #endif
837  }
838  cur_child_tuple = child_mesh.switch_tuples(
839  cur_child_tuple,
841  cur_parent_tuple = my_mesh.switch_tuples(
842  cur_parent_tuple,
844  }
845  } else if (
846  map_type == PrimitiveType::Edge &&
848  if (!my_mesh.is_boundary(PrimitiveType::Edge, parent_tuple_from_child)) {
849  auto parent_to_child_accessor =
850  my_mesh.create_const_accessor(parent_to_child_handle);
851 #ifndef NDEBUG
852  const Tuple parent_tuple_opp =
853  my_mesh.switch_tuple(parent_tuple_from_child, PrimitiveType::Triangle);
854  assert(
855  child_tuple_from_child == map_tuple_between_meshes(
856  my_mesh,
857  child_mesh,
858  parent_to_child_accessor,
859  parent_tuple_opp));
860 #endif
861  }
862  } else {
863  // TODO: implement other cases
864  continue;
865  }
866  }
867 }
868 
869 
871  const std::vector<int64_t>& a,
872  const std::vector<int64_t>& b)
873 {
874  std::vector<int64_t> ret;
875  size_t size = std::min(a.size(), b.size());
876  for (size_t j = 0; j < size; ++j) {
877  if (a[j] == b[j]) {
878  ret.emplace_back(a[j]);
879  } else {
880  break;
881  }
882  }
883  return ret;
884 }
885 std::vector<int64_t> MultiMeshManager::relative_id(
886  const std::vector<int64_t>& parent,
887  const std::vector<int64_t>& child)
888 {
889  assert(is_child(child, parent));
890  std::vector<int64_t> ret;
891  std::copy(child.begin() + parent.size(), child.end(), std::back_inserter(ret));
892  return ret;
893 }
895  const std::vector<int64_t>& child,
896  const std::vector<int64_t>& parent)
897 {
898  if (parent.size() > child.size()) {
899  return false;
900  }
901  for (size_t j = 0; j < parent.size(); ++j) {
902  if (parent[j] != child[j]) {
903  return false;
904  }
905  }
906  return true;
907 }
908 
909 void MultiMeshManager::serialize(MeshWriter& writer, const Mesh* local_root) const
910 {
911  for (const auto& c : m_children) {
912  c.mesh->serialize(writer, local_root);
913  }
914 }
915 
917 {
918  for (const bool c : m_has_child_mesh_in_dimension) {
919  if (c) {
920  return true;
921  }
922  }
923  return false;
924 }
925 
927  const Mesh& my_mesh,
928  const Mesh& other_mesh,
929  const simplex::Simplex& my_simplex) const
930 {
931  auto& root = my_mesh.get_multi_mesh_root();
932  const simplex::Simplex root_simplex(
933  root,
934  my_simplex.primitive_type(),
935  map_to_root_tuple(my_mesh, my_simplex));
936  return root.m_multi_mesh_manager.can_map_child(root, other_mesh, root_simplex);
937 }
939  const Mesh& my_mesh,
940  const Mesh& other_mesh,
941  const simplex::Simplex& my_simplex) const
942 {
943  if (my_simplex.primitive_type() > other_mesh.top_simplex_type()) {
944  return false;
945  }
946  const auto my_id = absolute_id();
947  const auto other_id = other_mesh.absolute_multi_mesh_id();
948 
949  int64_t depth = my_id.size();
950 
951  auto [root_ref, tuple] = map_up_to_tuples(my_mesh, my_simplex, depth);
952  const simplex::Simplex simplex(root_ref, my_simplex.primitive_type(), tuple);
953 
954  return !root_ref.m_multi_mesh_manager.map_down_relative_tuples(root_ref, simplex, other_id)
955  .empty();
956 }
957 } // namespace wmtk::multimesh
std::vector< int64_t > absolute_multi_mesh_id() const
returns a unique identifier for this mesh within a single multimesh structure
attribute::MeshAttributeHandle get_attribute_handle(const std::string &name, const PrimitiveType ptype) const
Definition: Mesh.hpp:917
int64_t capacity(PrimitiveType type) const
read in the m_capacities return the upper bound for the number of entities of the given dimension
attribute::TypedAttributeHandle< T > register_attribute_typed(const std::string &name, PrimitiveType type, int64_t size, bool replace=false, T default_value=T(0))
const attribute::Accessor< T, Mesh, D > create_const_accessor(const attribute::MeshAttributeHandle &handle) const
bool is_boundary(const simplex::Simplex &tuple) const
check if a simplex lies on a boundary or not
Definition: Mesh.cpp:106
virtual Tuple tuple_from_id(const PrimitiveType type, const int64_t gid) const =0
internal function that returns the tuple of requested type, and has the global index cid
std::vector< Tuple > get_all(PrimitiveType type) const
Generate a vector of Tuples from global vertex/edge/triangle/tetrahedron index.
Definition: Mesh.cpp:18
const attribute::Accessor< char > get_const_flag_accessor(PrimitiveType type) const
Definition: Mesh.cpp:162
multimesh::MultiMeshManager m_multi_mesh_manager
Definition: Mesh.hpp:841
Tuple switch_tuples(const Tuple &tuple, const ContainerType &op_sequence) const
Definition: Mesh.hpp:967
bool has_attribute(const std::string &name, const PrimitiveType ptype) const
Definition: Mesh.hpp:937
virtual bool is_valid(const Tuple &tuple) const
check validity of tuple including its hash
Definition: Mesh.cpp:112
int64_t top_cell_dimension() const
Definition: Mesh.hpp:992
virtual Tuple switch_tuple(const Tuple &tuple, PrimitiveType type) const =0
switch the orientation of the Tuple of the given dimension
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
Mesh & get_multi_mesh_root()
returns a reference to the root of a multimesh tree
PrimitiveType top_simplex_type() const
Definition: Mesh.hpp:996
const attribute::Accessor< char > get_flag_accessor(PrimitiveType type) const
Definition: Mesh.cpp:158
attribute::AttributeManager m_attribute_manager
Definition: Mesh.hpp:839
int64_t m_global_cid
Definition: Tuple.hpp:46
int8_t m_local_fid
Definition: Tuple.hpp:49
std::vector< MeshAttributes< T > > & get()
Implementation details for how the Mesh class implements multiple meshes.
void check_map_valid(const Mesh &my_mesh) const
update all the hashes of the top-simplces of the parent mesh around a vertex hashes of the parent tup...
Tuple map_to_root_tuple(const Mesh &my_mesh, const simplex::Simplex &my_simplex) const
maps a simplex from this mesh to the root mesh
const std::vector< ChildData > & children() const
int64_t child_id() const
Specifies the child id of this mesh if it a child mesh in a mult-mesh tree.
static std::vector< std::array< Tuple, 2 > > same_simplex_dimension_surjection(const Mesh &parent, const Mesh &child, const std::vector< int64_t > &parent_simplices)
bool can_map_child(const Mesh &my_mesh, const Mesh &other_mesh, const simplex::Simplex &my_simplex) const
std::map< std::string, const wmtk::utils::Hashable * > child_hashables() const override
const Mesh & get_root_mesh(const Mesh &my_mesh) const
std::vector< ChildData > m_children
void register_child_mesh(Mesh &my_mesh, const std::shared_ptr< Mesh > &child_mesh, const std::vector< std::array< Tuple, 2 >> &child_tuple_my_tuple_map)
register a another mesh as a child of this mesh.
Mesh & get_mesh(Mesh &m, const std::vector< int64_t > &absolute_id)
static bool is_child(const std::vector< int64_t > &child, const std::vector< int64_t > &parent)
void deregister_child_mesh(Mesh &my_mesh, const std::shared_ptr< Mesh > &child_mesh_ptr)
Deregister a child mesh.
static Tuple map_tuple_between_meshes(const Mesh &source_mesh, const Mesh &target_mesh, const wmtk::attribute::Accessor< int64_t > &source_to_target_map_accessor, const Tuple &source_tuple)
bool is_root() const
Specifies whether this structure is the root of a multi-mesh tree.
std::vector< int64_t > absolute_id() const
static std::vector< int64_t > least_upper_bound_id(const std::vector< int64_t > &a, const std::vector< int64_t > &b)
static std::string parent_to_child_map_attribute_name(int64_t index)
static std::string child_to_parent_map_attribute_name()
std::vector< simplex::Simplex > map(const Mesh &my_mesh, const Mesh &other_mesh, const simplex::Simplex &my_simplex) const
maps a simplex from this mesh to any other mesh
void serialize(MeshWriter &writer, const Mesh *local_root=nullptr) const
std::vector< std::shared_ptr< Mesh > > get_child_meshes() const
std::vector< Tuple > map_down_relative_tuples(const Mesh &my_mesh, const simplex::Simplex &my_simplex, const std::vector< int64_t > &local_id_path) const
std::vector< bool > m_has_child_mesh_in_dimension
TypedAttributeHandle< int64_t > map_to_parent_handle
MultiMeshManager & operator=(const MultiMeshManager &o)
static std::vector< int64_t > relative_id(const std::vector< int64_t > &parent, const std::vector< int64_t > &child)
std::vector< TypedAttributeHandle< int64_t > > map_handles() const
std::map< std::string, std::size_t > child_hashes() const override
std::vector< Tuple > lub_map_tuples(const Mesh &my_mesh, const Mesh &other_mesh, const simplex::Simplex &my_simplex) const
maps a simplex from this mesh to any other mesh using the LUB as the root
void update_child_handles(Mesh &my_mesh)
Clean up child data after deleting attributes.
std::array< wmtk::attribute::Accessor< int64_t >, 2 > get_map_accessors(Mesh &my_mesh, ChildData &c)
Tuple map_tuple_to_root_tuple(const Mesh &my_mesh, const Tuple &my_tuple) const
simplex::Simplex map_to_root(const Mesh &my_mesh, const simplex::Simplex &my_simplex) const
maps a simplex from this mesh to the root mesh
simplex::Simplex map_to_parent(const Mesh &my_mesh, const simplex::Simplex &my_simplex) const
optimized map from a simplex from this mesh to its direct parent
std::array< const wmtk::attribute::Accessor< int64_t >, 2 > get_map_const_accessors(const Mesh &my_mesh, const ChildData &c) const
std::vector< Tuple > map_tuples(const Mesh &my_mesh, const Mesh &other_mesh, const simplex::Simplex &my_simplex) const
maps a simplex from this mesh to any other mesh
Tuple map_to_parent_tuple(const Mesh &my_mesh, const simplex::Simplex &my_simplex) const
optimized map from a simplex from this mesh to its direct parent
void check_child_map_valid(const Mesh &my_mesh, const ChildData &child_data) const
bool can_map(const Mesh &my_mesh, const Mesh &other_mesh, const simplex::Simplex &my_simplex) const
std::vector< Tuple > map_to_child_tuples(const Mesh &my_mesh, const Mesh &child_mesh, const simplex::Simplex &my_simplex) const
Mesh & get_child_mesh(Mesh &m, const std::vector< int64_t > &relative_id)
std::vector< simplex::Simplex > map_to_child(const Mesh &my_mesh, const Mesh &child_mesh, const simplex::Simplex &my_simplex) const
optimized map fromsimplex from this mesh to one of its direct children
std::pair< const Mesh &, Tuple > map_up_to_tuples(const Mesh &my_mesh, const simplex::Simplex &simplex, int64_t depth) const
Tuple map_tuple_to_parent_tuple(const Mesh &my_mesh, const Tuple &my_tuple) const
std::vector< simplex::Simplex > lub_map(const Mesh &my_mesh, const Mesh &other_mesh, const simplex::Simplex &my_simplex) const
maps a simplex from this mesh to any other mesh using the LUB as the root
const Tuple & tuple() const
Definition: Simplex.hpp:53
PrimitiveType primitive_type() const
Definition: Simplex.hpp:51
std::map< std::string, std::size_t > child_hashes() const override
static std::string as_string(const Tuple &t)
std::tuple< Tuple, Tuple > read_tuple_map_attribute(const wmtk::attribute::Accessor< int64_t, MeshType > &accessor, const Tuple &source_tuple)
Tuple transport_tuple(const Tuple &base_source, const Tuple &base_target, PrimitiveType base_primitive_type, const Tuple &source, PrimitiveType primitive_type)
void symmetric_write_tuple_map_attributes(wmtk::attribute::Accessor< int64_t, MeshA > &a_to_b, wmtk::attribute::Accessor< int64_t, MeshB > &b_to_a, const Tuple &a_tuple, const Tuple &b_tuple)
std::tuple< Tuple, Tuple > read_tuple_map_attribute_slow(const Mesh &source_mesh, TypedAttributeHandle< int64_t > map_handle, const Tuple &source_tuple)
std::vector< Simplex > tuple_vector_to_homogeneous_simplex_vector(const Mesh &m, const std::vector< Tuple > &tups, PrimitiveType primitive)
std::vector< Tuple > make_unique_tuples(const Mesh &m, const std::vector< Tuple > &ts, PrimitiveType primitive)
Definition: make_unique.cpp:18
void top_dimension_cofaces_tuples(const PointMesh &mesh, const Simplex &simplex, SimplexCollection &collection)
std::vector< Tuple > cofaces_single_dimension_tuples(const Mesh &mesh, const Simplex &my_simplex, PrimitiveType cofaces_type)
std::size_t vector_hash(const std::vector< size_t > &data)
Definition: vector_hash.cpp:28
spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:58
TypedAttributeHandle< int64_t > map_handle