From 3b16584ab1ce2b5c780bedf42d3599adcdda70d7 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Mon, 25 Sep 2023 15:01:49 -0400 Subject: [PATCH 01/25] minor updates --- src/wmtk/Mesh.cpp | 1 + src/wmtk/Mesh.hpp | 3 +- src/wmtk/MultiMeshManager.cpp | 538 ++++++++++++++++++++-------------- src/wmtk/MultiMeshManager.hpp | 102 ++++--- 4 files changed, 375 insertions(+), 269 deletions(-) diff --git a/src/wmtk/Mesh.cpp b/src/wmtk/Mesh.cpp index a5a6500a12..c8e1ff56d0 100644 --- a/src/wmtk/Mesh.cpp +++ b/src/wmtk/Mesh.cpp @@ -249,6 +249,7 @@ attribute::AttributeScopeHandle Mesh::create_scope() return m_attribute_manager.create_scope(*this); } + template MeshAttributeHandle Mesh::register_attribute(const std::string&, PrimitiveType, long, bool); template MeshAttributeHandle diff --git a/src/wmtk/Mesh.hpp b/src/wmtk/Mesh.hpp index 0b8c6328ca..d5d90ca3ee 100644 --- a/src/wmtk/Mesh.hpp +++ b/src/wmtk/Mesh.hpp @@ -49,7 +49,6 @@ class Mesh : public std::enable_shared_from_this friend class MultiMeshManager; virtual PrimitiveType top_simplex_type() const = 0; - MultiMeshManager multi_mesh_manager; friend class operations::Operation; @@ -337,6 +336,8 @@ class Mesh : public std::enable_shared_from_this private: // members attribute::AttributeManager m_attribute_manager; + MultiMeshManager m_multi_mesh_manager; + // PImpl'd manager of per-thread update stacks // Every time a new access scope is requested the manager creates another level of indirection // for updates diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 34f194ab44..8bafcd0fcc 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -1,274 +1,360 @@ #include "MultiMeshManager.hpp" #include "Mesh.hpp" -#include "Types.hpp" #include "SimplicialComplex.hpp" -namespace wmtk +#include "Types.hpp" +namespace wmtk { + +namespace { + +Vector tuple_to_vector5(const Tuple& t) { - MultiMeshManager::MultiMeshManager() - : m_is_parent_mesh(false) - , m_child_id(-1) - { - } + Vector v; + v(0) = t.m_local_vid; + v(1) = t.m_local_eid; + v(2) = t.m_local_fid; + v(3) = t.m_global_cid; + v(4) = t.m_hash; + return v; +} - MultiMeshManager::~MultiMeshManager() = default; - MultiMeshManager::MultiMeshManager(const MultiMeshManager& o) = default; - MultiMeshManager::MultiMeshManager(MultiMeshManager&& o) = default; - MultiMeshManager& MultiMeshManager::operator=(const MultiMeshManager& o) = default; - MultiMeshManager& MultiMeshManager::operator=(MultiMeshManager&& o) = default; +template +Tuple vector5_to_tuple(const Eigen::MatrixBase& v) +{ + Tuple(v(0), v(1), v(2), v(3), v(4)), +} - bool MultiMeshManager::is_parent_mesh() const - { - return m_is_parent_mesh; - } - long MultiMeshManager::child_id() const - { - return m_child_id; - } +void write_tuple_map_attribute_slow( + Mesh& source_mesh, + MeshAttributeHandle map_handle, + const Tuple& source_tuple, + const Tuple& target_tuple) +{ + auto map_accessor = source_mesh.create_accessor(map_handle); + write_tuple_map_attribute(source_mesh, map_handle, source_tuple, target_tuple); +} - void MultiMeshManager::write_tuple_map_attribute(MeshAttributeHandle map_handle, Mesh& source_mesh, const Tuple& source_tuple, const Tuple& target_tuple) - { - auto map_accessor = source_mesh.create_accessor(map_handle); - auto map = map_accessor.vector_attribute(source_tuple); - - map(0) = source_tuple.m_local_vid; - map(1) = source_tuple.m_local_eid; - map(2) = source_tuple.m_local_fid; - map(3) = source_tuple.m_global_cid; - map(4) = source_tuple.m_hash; - - map(5) = target_tuple.m_local_vid; - map(6) = target_tuple.m_local_eid; - map(7) = target_tuple.m_local_fid; - map(8) = target_tuple.m_global_cid; - map(9) = target_tuple.m_hash; - } - - std::tuple MultiMeshManager::read_tuple_map_attribute(MeshAttributeHandle map_handle, const Mesh& source_mesh, const Tuple& source_tuple) - { - auto map_accessor = source_mesh.create_accessor(map_handle); - auto map = map_accessor.const_vector_attribute(source_tuple); +void write_tuple_map_attribute_slow( + Mesh& source_mesh, + Accessor& map_accessor, + const Tuple& source_tuple, + const Tuple& target_tuple) +{ + auto map = map_accessor.vector_attribute(source_tuple); - return std::make_tuple(Tuple(map(0), map(1), map(2), map(3), map(4)), Tuple(map(5), map(6), map(7), map(8), map(9))); - } + map.head<5>() = tuple_to_vector5(source_tuple); + map.tail<5>() = tuple_to_vector5(target_tuple); +} + +std::tuple read_tuple_map_attribute( + const Mesh& source_mesh, + MeshAttributeHandle map_handle, + const Tuple& source_tuple) +{ + auto map_accessor = source_mesh.create_accessor(map_handle); +} +std::tuple read_tuple_map_attribute_slow( + MeshAttributeHandle map_handle, + const Mesh& source_mesh, + const Tuple& source_tuple) +{ + auto map = map_accessor.const_vector_attribute(source_tuple); - void MultiMeshManager::register_child_mesh(Mesh& parent_mesh, std::shared_ptr child_mesh, const std::vector>& child_mesh_simplex_map) - { - PrimitiveType map_ptype = child_mesh->top_simplex_type(); - long cur_child_id = long(parent_mesh.multi_mesh_manager.child_meshes.size()); + return std::make_tuple(vector5_to_tuple(map.head<5>()), vector5_to_tuple(map.tail<5>())); +} - auto map_to_parent_handle = child_mesh->register_attribute("map_to_parent", map_ptype, 10); - - auto map_to_child_handle = parent_mesh.register_attribute(fmt::format("map_to_child_{}", cur_child_id), map_ptype, 10); - for (long id = 0; id < parent_mesh.capacity(map_ptype); ++id) - { - write_tuple_map_attribute(map_to_child_handle, parent_mesh, parent_mesh.tuple_from_id(map_ptype, id), Tuple()); + +Tuple map_tuple_between_meshes( + const Mesh& source_mesh, + const Mesh& target_mesh, + MeshAttributeHandle source_map_handle, + const Tuple& source_tuple) +{ + PrimitiveType source_mesh_primitive_type = source_mesh.top_simplex_type(); + PrimitiveType target_mesh_primitive_type = target_mesh.top_simplex_type(); + + auto [source_mesh_base_tuple, target_mesh_base_tuple] = + read_tuple_map_attribute(source_map_handle, source_mesh, source_tuple); + + if (source_mesh_base_tuple.is_null() || target_mesh_base_tuple.is_null()) { + return Tuple(); // return null tuple + } + + if (source_mesh_primitive_type == PrimitiveType::Face && + target_mesh_primitive_type == PrimitiveType::Face) { + Tuple cur_tuple = source_tuple; + std::vector record_switch_operations; + while (cur_tuple != source_mesh_base_tuple) { + cur_tuple = source_mesh.switch_tuple(cur_tuple, PrimitiveType::Vertex); + record_switch_operations.push_back(PrimitiveType::Vertex); + if (cur_tuple == source_mesh_base_tuple) { + break; + } + cur_tuple = source_mesh.switch_tuple(cur_tuple, PrimitiveType::Edge); + record_switch_operations.push_back(PrimitiveType::Edge); } - // register maps - for (long id = 0; id < child_mesh->capacity(map_ptype); ++id) - { - write_tuple_map_attribute(map_to_parent_handle, *child_mesh, child_mesh_simplex_map[id][0], child_mesh_simplex_map[id][1]); - write_tuple_map_attribute(map_to_child_handle, parent_mesh, child_mesh_simplex_map[id][1], child_mesh_simplex_map[id][0]); + Tuple ret_tuple = target_mesh_base_tuple; + for (int i = record_switch_operations.size() - 1; i >= 0; --i) { + ret_tuple = target_mesh.switch_tuple(ret_tuple, record_switch_operations[i]); } - - // update on child_mesh - child_mesh->multi_mesh_manager.map_to_parent_handle = map_to_parent_handle; - child_mesh->multi_mesh_manager.m_is_parent_mesh = false; - child_mesh->multi_mesh_manager.m_child_id = long(parent_mesh.multi_mesh_manager.child_meshes.size()); - - // update on parent_mesh - parent_mesh.multi_mesh_manager.child_meshes.push_back(child_mesh); - parent_mesh.multi_mesh_manager.map_to_child_handles.push_back(map_to_child_handle); - parent_mesh.multi_mesh_manager.m_is_parent_mesh = true; - + + return ret_tuple; + } else { + // TODO: implement this for other cases later + // TODO: maybe use a seperate function for each case? + return Tuple(); } +} +} // namespace - void MultiMeshManager::register_child_mesh(Mesh& parent_mesh, std::shared_ptr child_mesh, const std::vector& child_mesh_simplex_id_map) - { - PrimitiveType map_type = child_mesh->top_simplex_type(); - std::vector> child_mesh_simplex_map; - - for (long child_cell_id = 0; child_cell_id < long(child_mesh_simplex_id_map.size()); ++child_cell_id) - { - long parent_cell_id = child_mesh_simplex_id_map[child_cell_id]; - child_mesh_simplex_map.push_back({child_mesh->tuple_from_id(map_type, child_cell_id), parent_mesh.tuple_from_id(map_type, parent_cell_id)}); - } - register_child_mesh(parent_mesh, child_mesh, child_mesh_simplex_map); + +MultiMeshManager::MultiMeshManager() = default; + +MultiMeshManager::~MultiMeshManager() = default; +MultiMeshManager::MultiMeshManager(const MultiMeshManager& o) = default; +MultiMeshManager::MultiMeshManager(MultiMeshManager&& o) = default; +MultiMeshManager& MultiMeshManager::operator=(const MultiMeshManager& o) = default; +MultiMeshManager& MultiMeshManager::operator=(MultiMeshManager&& o) = default; + +bool MultiMeshManager::is_root() const +{ + return m_my_mesh == nullptr; +} + +long MultiMeshManager::child_id() const +{ + return m_child_id; +} + +std::vector MultiMeshManager::absolute_id() const +{ + if (is_root()) { + return {}; + } else { + auto id = m_my_mesh->absolute_id(); + id.emplace_back(m_child_id); + return id; } +} - Tuple MultiMeshManager::map_tuple_between_meshes(const Mesh& source_mesh, const Mesh& target_mesh, MeshAttributeHandle source_map_handle, const Tuple& source_tuple) - { - PrimitiveType source_mesh_ptype = source_mesh.top_simplex_type(); - PrimitiveType target_mesh_ptype = target_mesh.top_simplex_type(); - auto [source_mesh_base_tuple, target_mesh_base_tuple] = read_tuple_map_attribute(source_map_handle, source_mesh, source_tuple); +void MultiMeshManager::register_child_mesh( + Mesh& my_mesh, + const std::shared_ptr& child_mesh_ptr, + const std::vector>& child_mesh_simplex_map) +{ + assert(&my_mesh.m_multi_mesh_manager == this); + assert(bool(child_mesh_ptr)); + + PrimitiveType child_primitive_type = child_mesh->top_simplex_type(); + long new_child_id = long(m_children.size()); + + auto map_to_parent_handle = + child_mesh->register_attribute("map_to_parent", child_primitive_type, 10); + + auto map_to_child_handle = my_mesh.register_attribute( + fmt::format("map_to_child_{}", new_child_id), + child_primitive_type, + 10); + for (long id = 0; id < my_mesh.capacity(child_primitive_type); ++id) { + write_tuple_map_attribute( + map_to_child_handle, + my_mesh, + my_mesh.tuple_from_id(child_primitive_type, id), + Tuple()); + } + // register maps + for (const auto& [my_tuple, child_tuple] : child_mesh_simplex_map) { + // const auto& [my_tuple, child_tuple] = tuple_pair; - if (source_mesh_base_tuple.is_null() || target_mesh_base_tuple.is_null()) - { - return Tuple(); // return null tuple - } + write_tuple_map_attribute(map_to_parent_handle, *child_mesh, my_tuple, child_tuple); + write_tuple_map_attribute(map_to_child_handle, my_mesh, child__tuple, my_tuple); + } - if (source_mesh_ptype == PrimitiveType::Face && target_mesh_ptype == PrimitiveType::Face) - { - Tuple cur_tuple = source_tuple; - std::vector record_switch_operations; - while (cur_tuple != source_mesh_base_tuple) - { - cur_tuple = source_mesh.switch_tuple(cur_tuple, PrimitiveType::Vertex); - record_switch_operations.push_back(PrimitiveType::Vertex); - if (cur_tuple == source_mesh_base_tuple) - { - break; - } - cur_tuple = source_mesh.switch_tuple(cur_tuple, PrimitiveType::Edge); - record_switch_operations.push_back(PrimitiveType::Edge); - } + MultiMeshManager& child_manager = child_mesh->multi_mesh_manager; - Tuple ret_tuple = target_mesh_base_tuple; - for (int i = record_switch_operations.size() - 1; i >= 0; --i) - { - ret_tuple = target_mesh.switch_tuple(ret_tuple, record_switch_operations[i]); - } + // update on child_mesh + child_manager.map_to_parent_handle = map_to_parent_handle; + child_manager.m_child_id = new_child_id; + child_managerm_my_mesh = this; - return ret_tuple; - } - else - { - // TODO: implement this for other cases later - // TODO: maybe use a seperate function for each case? - return Tuple(); - } + // update myself + m_children.emplace_back(child_mesh, map_to_child_handle); +} + +/* + * TODO: It is the consumer's responsibility to generate teh identity map via a utility function +void MultiMeshManager::register_child_mesh( + Mesh& my_mesh, + std::shared_ptr child_mesh, + const std::vector& child_mesh_simplex_id_map) +{ + PrimitiveType map_type = child_mesh->top_simplex_type(); + std::vector> child_mesh_simplex_map; + + for (long child_cell_id = 0; child_cell_id < long(child_mesh_simplex_id_map.size()); + ++child_cell_id) { + long parent_cell_id = child_mesh_simplex_id_map[child_cell_id]; + child_mesh_simplex_map.push_back( + {child_mesh->tuple_from_id(map_type, child_cell_id), + my_mesh.tuple_from_id(map_type, parent_cell_id)}); } + register_child_mesh(my_mesh, child_mesh, child_mesh_simplex_map); +} +*/ - std::vector MultiMeshManager::find_all_simplices_in_child_mesh(const Mesh& parent_mesh, long child_id, const Simplex& simplex_parent) - { - auto child_mesh_ptr = parent_mesh.multi_mesh_manager.child_meshes[child_id]; - auto map_to_child_handle = parent_mesh.multi_mesh_manager.map_to_child_handles[child_id]; - PrimitiveType simplex_ptype = simplex_parent.primitive_type(); - PrimitiveType childmesh_ptype = child_mesh_ptr->top_simplex_type(); - if (simplex_ptype > childmesh_ptype) - { - // Can't find higher-dimensional simplex in child_mesh - return std::vector(); - } +std::vector MultiMeshManager::find_all_simplices_in_child_mesh( + const Mesh& my_mesh, + long child_id, + const Simplex& simplex) +{ + assert(&my_mesh.m_multi_mesh_manager == this); + return find_all_simplices_in_child_mesh(my_mesh, m_children.at(child_id), simplex_parent); +} +std::vector MultiMeshManager::find_all_simplices_in_child_mesh( + const Mesh& my_mesh, + const ChildData& child_data, + const Simplex& simplex_parent) +{ + assert(&my_mesh.m_multi_mesh_manager == this); + const Mesh& child_mesh = *child_data.mesh; + PrimitiveType simplex_primitive_typ = simplex.primitive_type(); + PrimitiveType childmesh_primitive_type = child_mesh.top_simplex_type(); + + if (simplex_primitive_type > childmesh_primitive_type) { + // Can't find higher-dimensional simplex in child_mesh + return std::vector(); + } - // Find all dim(child_mesh) simplex in open_star(simplex_parent)) in parent_mesh - auto top_simplex_in_open_star = SimplicialComplex::open_star(parent_mesh, simplex_parent).get_simplices(childmesh_ptype); - // map tuples to child_mesh and collect all distinct simplices - SimplicialComplex ret_sc(*child_mesh_ptr); - for (auto s : top_simplex_in_open_star) - { - auto child_tuple = map_tuple_between_meshes(parent_mesh, *child_mesh_ptr, map_to_child_handle, s.tuple()); - if (!child_tuple.is_null()) - { - ret_sc.add_simplex(Simplex(simplex_ptype, child_tuple)); - } + const auto& map_to_child_handle = child_data.map_handle; + // Find all dim(child_mesh) simplex in open_star(simplex_parent)) in my_mesh + auto top_simplices_in_open_star = + SimplicialComplex::open_star(my_mesh, simplex).get_simplices(childmesh_primitive_type); + + // map tuples to child_mesh and collect all distinct simplices + SimplicialComplex ret_sc(child_mesh); + for (auto s : top_simplices_in_open_star) { + const Tuple child_tuple = + map_tuple_between_meshes(my_mesh, *child_mesh_ptr, map_to_child_handle, s.tuple()); + if (!child_tuple.is_null()) { + ret_sc.add_simplex(Simplex(simplex_primitive_type, child_tuple)); } - - return ret_sc.get_simplex_vector(); } - bool MultiMeshManager::is_child_mesh_valid(const Mesh& parent_mesh, const Mesh& child_mesh) - { - // TODO: implement this - - return true; + return ret_sc.get_simplex_vector(); +} + +bool MultiMeshManager::is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const +{ + assert(&my_mesh.m_multi_mesh_manager == this); + // TODO: implement this + + return true; +} + +std::vector MultiMeshManager::map_edge_tuple_to_all_children( + const Mesh& my_mesh, + const Tuple& edge_tuple) +{ + assert(&my_mesh.m_multi_mesh_manager == this); + std::vector ret; + for (const auto& child_data : m_children) { + const Mesh& child_mesh = *child_data.mesh; + const auto map_to_child_handle = child_data.map_handle; + Tuple child_tuple = + map_tuple_between_meshes(my_mesh, child_mesh, map_to_child_handle, edge_tuple); + ret.push_back(child_tuple); } + return ret; +} - std::vector MultiMeshManager::map_edge_tuple_to_all_children(const Mesh& parent_mesh, const Tuple& edge_tuple) - { - std::vector ret; - for (auto child_mesh_ptr : parent_mesh.multi_mesh_manager.child_meshes) - { - long child_id = child_mesh_ptr->multi_mesh_manager.child_id(); - auto map_to_child_handle = parent_mesh.multi_mesh_manager.map_to_child_handles[child_id]; - Tuple child_tuple = map_tuple_between_meshes(parent_mesh, *child_mesh_ptr, map_to_child_handle, edge_tuple); - ret.push_back(child_tuple); +bool MultiMeshManager::is_map_valid(const Mesh& my_mesh) const +{ + assert(&my_mesh.m_multi_mesh_manager == this); + for (size_t index = 0; index < m_children.size(); ++index) { + const auto& child_data = m_children[index]; + if (child_data.mesh->mesh_manager.m_child_id != index) { + return false; + } + if (!is_child_map_valid(my_mesh, child_data)) { + return false; } - return ret; } + return true; +} +bool MultiMeshManager::is_child_map_valid(const Mesh& my_mesh, const ChildData& child_data) const +{ + assert(&my_mesh.m_multi_mesh_manager == this); + const Mesh& child_mesh = *child_data.mesh; + const auto parent_to_child_handle = child_data.map_handle; + PrimitiveType map_type = child_mesh.top_simplex_type(); + + auto child_to_parent_handle = child_mesh.m_multi_mesh_manager.map_to_parent_handle; + auto child_cell_flag_accessor = child_mesh.get_flag_accessor(map_type); + + for (const child_tuple : child_mesh.get_simplices(map_type)) { + // 1. test if all maps in child_mesh exisits + auto [child_tuple_from_child, parent_tuple_from_child] = + read_tuple_map_attribute(child_to_parent_handle, child_mesh, child_tuple); - bool MultiMeshManager::is_map_valid(const Mesh& parent_mesh) const - { - for (auto child_mesh_ptr : child_meshes) + // 2. test if tuples in maps are valid (and up_to_date) { - long child_id = child_mesh_ptr->multi_mesh_manager.child_id(); - PrimitiveType map_type = child_mesh_ptr->top_simplex_type(); - - auto parent_to_child_handle = map_to_child_handles[child_id]; - auto child_to_parent_handle = child_mesh_ptr->multi_mesh_manager.map_to_parent_handle; - auto child_cell_flag_accessor = child_mesh_ptr->get_flag_accessor(map_type); - - for (long id = 0; id < child_mesh_ptr->capacity(map_type); ++id) - { - if (child_cell_flag_accessor.scalar_attribute(child_mesh_ptr->tuple_from_id(map_type, id)) == 0) - { - continue; - } + if (!child_mesh.is_valid_slow(child_tuple_from_child)) { + return false; + } + if (!my_mesh.is_valid_slow(parent_tuple_from_child)) { + return false; + } + } - // 1. test if all maps in child_mesh exisits - // 2. test if tuples in maps are valid (and up_to_date) - // 3. test if map is symmetric - // 4. test switch_top_simplex operation + // 3. test if map is symmetric + { + auto [parent_tuple_from_parent, child_tuple_from_parent] = + read_tuple_map_attribute(parent_to_child_handle, my_mesh, parent_tuple); - auto [child_tuple, parent_tuple] = read_tuple_map_attribute(child_to_parent_handle, *child_mesh_ptr, child_mesh_ptr->tuple_from_id(map_type, id)); + if (child_tuple_from_child != child_tuple_from_parent || + parent_tuple_from_child != parent_tuple_from_parent) { + return false; + } + } - if (!child_mesh_ptr->is_valid_slow(child_tuple)) - { - return false; - } - if (!parent_mesh.is_valid_slow(parent_tuple)) - { - return false; - } - - auto [parent_tuple_test, child_tuple_test] = read_tuple_map_attribute(parent_to_child_handle, parent_mesh, parent_tuple); + /* + // 4. test switch_top_simplex operation + // for 4, current code support only mapping between triangle meshes + if (map_type == PrimitiveType::Face && my_mesh.top_simplex_type() == PrimitiveType::Face) { + Tuple cur_child_tuple = child_tuple; + Tuple cur_parent_tuple = parent_tuple; + + for (int i = 0; i < 3; i++) { + if (!child_mesh_ptr->is_boundary(cur_child_tuple)) { + if (my_mesh.is_boundary(cur_parent_tuple)) { + return false; + } - if (child_tuple_test != child_tuple || parent_tuple_test != parent_tuple) - { - return false; - } + Tuple child_tuple_opp = child_mesh.switch_face(cur_child_tuple); + Tuple parent_tuple_opp = my_mesh.switch_face(cur_parent_tuple); - // for 4, current code support only mapping between triangle meshes - if (map_type == PrimitiveType::Face && parent_mesh.top_simplex_type() == PrimitiveType::Face) - { - Tuple cur_child_tuple = child_tuple; - Tuple cur_parent_tuple = parent_tuple; - - for (int i = 0; i < 3; i++) - { - if (!child_mesh_ptr->is_boundary(cur_child_tuple)) - { - if (parent_mesh.is_boundary(cur_parent_tuple)) - { - return false; - } - - Tuple child_tuple_opp = child_mesh_ptr->switch_face(cur_child_tuple); - Tuple parent_tuple_opp = parent_mesh.switch_face(cur_parent_tuple); - - if (parent_tuple_opp != map_tuple_between_meshes(*child_mesh_ptr, parent_mesh, child_to_parent_handle, child_tuple_opp)) - { - return false; - } - - } - cur_child_tuple = child_mesh_ptr->switch_edge(child_mesh_ptr->switch_vertex(cur_child_tuple)); - cur_parent_tuple = parent_mesh.switch_edge(parent_mesh.switch_vertex(cur_parent_tuple)); + if (parent_tuple_opp != map_tuple_between_meshes( + *child_mesh_ptr, + my_mesh, + child_to_parent_handle, + child_tuple_opp)) { + return false; } } - else - { - // TODO: implement other cases - continue; - } - + cur_child_tuple = + child_mesh_ptr->switch_edge(child_mesh_ptr->switch_vertex(cur_child_tuple)); + cur_parent_tuple = my_mesh.switch_edge(my_mesh.switch_vertex(cur_parent_tuple)); } - + } else { + // TODO: implement other cases + continue; } - return true; + */ } + return true; } +} // namespace wmtk diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index 9187819f4d..eab2a5c1e4 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -1,19 +1,17 @@ #pragma once +#include #include +#include "Simplex.hpp" +#include "Tuple.hpp" #include "attribute/AttributeManager.hpp" #include "attribute/AttributeScopeHandle.hpp" #include "attribute/MeshAttributes.hpp" -#include "Simplex.hpp" -#include "Tuple.hpp" -#include -namespace wmtk -{ +namespace wmtk { class Mesh; class MultiMeshManager { - public: - +public: MultiMeshManager(); ~MultiMeshManager(); MultiMeshManager(const MultiMeshManager& o); @@ -25,49 +23,69 @@ class MultiMeshManager // Storage of MultiMesh //========================================================= - bool is_parent_mesh() const; + bool is_root() const; long child_id() const; - // helper function to read/write the map from source_tuple to target_tuple to the attribute - static void write_tuple_map_attribute(MeshAttributeHandle map_handle, Mesh& source_mesh, const Tuple& source_tuple, const Tuple& target_tuple); - static std::tuple read_tuple_map_attribute(MeshAttributeHandle map_handle, const Mesh& source_mesh, const Tuple& source_tuple); + // + std::vector absolute_id() const; - // Child Meshes - std::vector> child_meshes; - - // Only valid if this is_parent_mesh == true - // size of child_meshes.size(), store the map to the base_tuple of the child_meshes (on the top level simplex of each child_mesh) - // a map is a pair of two tuples, from a tuple in parent_mesh to a tuple in child_mesh - // i.e. Dim(map_to_child[i]) == Dim(child_meshes[i]) - std::vector> map_to_child_handles; - - // Only valid if this is is_parent_mesh == false - // store the map to the base_tuple of the parent_mesh - MeshAttributeHandle map_to_parent_handle; - - // register child_meshes and the map from child_meshes to this mesh, child_mesh_simplex - static void register_child_mesh(Mesh&parent_mesh, std::shared_ptr child_mesh, const std::vector>&child_mesh_simplex_map); - static void register_child_mesh(Mesh&parent_mesh, std::shared_ptr child_mesh, const std::vector& child_mesh_simplex_id_map); - - // helper function to check if this mesh is a valid child_mesh of parent_mesh - // i.e. the connectivity of this mesh is a subset of this in parent_mesh - static bool is_child_mesh_valid(const Mesh& parent_mesh, const Mesh& child_mesh); - bool is_map_valid(const Mesh& parent_mesh) const; + // register child_meshes and the map from child_meshes to this mesh, child_mesh_simplex + void register_child_mesh( + Mesh& my_mesh, + const std::shared_ptr& child_mesh, + const std::vector>& child_mesh_simplex_map); - // TODO: make it a free function? static function? - // Map source_tuple from source_mesh to target_mesh - static Tuple map_tuple_between_meshes(const Mesh& source_mesh, const Mesh& target_mesh, MeshAttributeHandle source_map_handle, const Tuple& source_tuple); - static std::vector find_all_simplices_in_child_mesh(const Mesh& parent_mesh, long child_id, const Simplex& simplex_parent); + bool are_maps_valid(const Mesh& my_mesh) const; + + std::vector find_all_simplices_in_child_mesh( + const Mesh& my_mesh, + const Mesh& child_mesh, + const Simplex& simplex_parent); + + std::vector find_all_simplices_in_child_mesh( + const Mesh& my_mesh, + const Mesh& child_mesh, + long child_id, + const Simplex& simplex_parent); // Utility function to map a edge tuple to all its children, used in operations - static std::vector map_edge_tuple_to_all_children(const Mesh& parent_mesh,const Tuple& edge_tuple); + std::vector map_edge_tuple_to_all_children(const Mesh& my_mesh, const Simplex& tuple) + const; + +private: + MeshAttributeHandle std::vector find_all_simplices_in_child_mesh( + const Mesh& my_mesh, + const ChildData& child_data, + const Simplex& simplex) const; + + // helper function to check if this mesh is a valid child_mesh of my_mesh + // i.e. the connectivity of this mesh is a subset of this in my_mesh + bool is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const; + + // checks that the map is consistent + bool is_child_map_valid(const Mesh& my_mesh, const ChildData& child) const; - private: - // flag indicating if this mesh is a parent mesh - bool m_is_parent_mesh; - long m_child_id; +private: + Mesh* m_parent = nullptr; + // only valid if this is teh child of some other mesh + // store the map to the base_tuple of the my_mesh + MeshAttributeHandle map_to_parent_handle; + long m_child_id = -1; + + struct ChildData + { + std::shared_ptr mesh; + // store the map from the manager's mesh to the child mesh (on the top + // level simplex of the mesh) + // encoded by a pair of two tuples, from a tuple in current mesh to a tuple in + // child_mesh + MeshAttributeHandle map_handle; + }; + + // Child Meshes + std::vector m_children; }; -} \ No newline at end of file +} // namespace wmtk From b860c02157707085a8c3a2e661b18927498f5cf9 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Fri, 29 Sep 2023 21:58:22 -0400 Subject: [PATCH 02/25] half-baked updates to multimesh manager --- src/wmtk/MultiMeshManager.cpp | 40 ++++++++++++++++++++++-- src/wmtk/MultiMeshManager.hpp | 57 ++++++++++++++++++++++++++++------- 2 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 8bafcd0fcc..24544ecf0a 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -204,11 +204,45 @@ void MultiMeshManager::register_child_mesh( } */ +std::vector +MultiMeshManager::map(const Mesh& my_mesh, const Mesh& other_mesh, const Simplex& my_simplex) const +{ + assert(&my_mesh.m_multi_mesh_manager == this); + // TODO: construct relative positions + // TODO: construct visitor class that maps up and down + // TODO: visitor runs along meshes traversing the path + throw "not implemented"; -std::vector MultiMeshManager::find_all_simplices_in_child_mesh( + return {}; +} + + +std::vector MultiMeshManager::map_to_parent(const Mesh& my_mesh, const Simplex& my_simplex) + const +{ + assert(&my_mesh.m_multi_mesh_manager == this); + assert(!is_root()); + + const Mesh& parent = *m_parent; + + const auto& map_handle = map_to_parent_handle; + // assert(!map_handle.is_null()); + + map_tuple_between_meshes(my_mesh, parent, map_handle, my_simplex); +} + +// generic mapping function that maps a tuple from "this" mesh to one of its children +std::vector MultiMeshManager::map_to_child( const Mesh& my_mesh, - long child_id, - const Simplex& simplex) + const Mesh& child_mesh, + const Simplex& my_simplex) const +{ + assert(&my_mesh.m_multi_mesh_manager == this); +} + + +std::vector +MultiMeshManager::convert_tuple_to_child(const Mesh& my_mesh, long child_id, const Simplex& simplex) { assert(&my_mesh.m_multi_mesh_manager == this); return find_all_simplices_in_child_mesh(my_mesh, m_children.at(child_id), simplex_parent); diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index eab2a5c1e4..118dcb0170 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -38,24 +38,59 @@ class MultiMeshManager bool are_maps_valid(const Mesh& my_mesh) const; - std::vector find_all_simplices_in_child_mesh( - const Mesh& my_mesh, - const Mesh& child_mesh, - const Simplex& simplex_parent); + //=========== + //=========== + // Map functions + //=========== + //=========== + // Note that when we map a M-tuplefrom a K-complex to a J-complex there are different + // relationships necessary if K == J + // if M == K then this is unique + // if M < K then this is many to many + // if K < J + // if M == K then it is one to many + // if M < K then it is many to many + + //=========== + // Simplex maps + //=========== + // generic mapping function that maps a tuple from "this" mesh to the other mesh + std::vector map(const Mesh& my_mesh, const Mesh& other_mesh, const Simplex& my_simplex) + const; - std::vector find_all_simplices_in_child_mesh( - const Mesh& my_mesh, - const Mesh& child_mesh, - long child_id, - const Simplex& simplex_parent); + + std::vector map_to_parent(const Mesh& my_mesh, const Simplex& my_simplex) const; + + // generic mapping function that maps a tuple from "this" mesh to one of its children + std::vector + map_to_child(const Mesh& my_mesh, const Mesh& child_mesh, const Simplex& my_simplex) const; // Utility function to map a edge tuple to all its children, used in operations std::vector map_edge_tuple_to_all_children(const Mesh& my_mesh, const Simplex& tuple) const; -private: - MeshAttributeHandle std::vector find_all_simplices_in_child_mesh( +protected: // protected to enable unit testing + //=========== + // Tuple maps + //=========== + // generic mapping function that maps a tuple from "this" mesh to the other mesh + Tuple map(const Mesh& my_mesh, const Mesh& other_mesh, const Tuple& my_tuple) const; + + // generic mapping function that maps a tuple from "this" mesh to its parent + Tuple map_to_parent(const Mesh& my_mesh, const Mesh& parent_mesh, const Tuple& my_tuple) const; + + // generic mapping function that maps a tuple from "this" mesh to one of its children + Tuple map_to_child(const Mesh& my_mesh, const Mesh& child_mesh, const Tuple& my_tuple) const; + + // generic mapping function that maps a tuple from "this" mesh to one of its children (by index) + Tuple map_to_child(const Mesh& my_mesh, long child_id, const Tuple& my_tuple) const; + + // wrapper for implementing converting tuple to a child using the internal map data + std::vector + map_to_child(const Mesh& my_mesh, const ChildData& child_data, const Tuple& simplex) const; + + std::vector convert_single_tuple( const Mesh& my_mesh, const ChildData& child_data, const Simplex& simplex) const; From d58d476ff8ff0acf517ef4242f13452f8a41ec94 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Sat, 30 Sep 2023 15:16:14 -0400 Subject: [PATCH 03/25] moving tuple vec to simplex util out of top level cofaces and separating cmakes --- src/wmtk/simplex/CMakeLists.txt | 12 ++-------- src/wmtk/simplex/iterable/CMakeLists.txt | 13 +++++++++++ src/wmtk/simplex/top_level_cofaces.cpp | 23 ++++++++----------- src/wmtk/simplex/utils/CMakeLists.txt | 5 ++++ ...e_vector_to_homogeneous_simplex_vector.cpp | 18 +++++++++++++++ ...e_vector_to_homogeneous_simplex_vector.hpp | 11 +++++++++ 6 files changed, 59 insertions(+), 23 deletions(-) create mode 100644 src/wmtk/simplex/iterable/CMakeLists.txt create mode 100644 src/wmtk/simplex/utils/CMakeLists.txt create mode 100644 src/wmtk/simplex/utils/tuple_vector_to_homogeneous_simplex_vector.cpp create mode 100644 src/wmtk/simplex/utils/tuple_vector_to_homogeneous_simplex_vector.hpp diff --git a/src/wmtk/simplex/CMakeLists.txt b/src/wmtk/simplex/CMakeLists.txt index 2f2e1b9edb..7fc95f6a54 100644 --- a/src/wmtk/simplex/CMakeLists.txt +++ b/src/wmtk/simplex/CMakeLists.txt @@ -22,17 +22,9 @@ set(SRC_FILES simplex_boundary.cpp simplex_boundary_iterable.hpp simplex_boundary_iterable.cpp - iterable/ClosedStarIterable.hpp - iterable/ClosedStarIterable.cpp - iterable/LinkIterable.hpp - iterable/LinkIterable.cpp - iterable/OpenStarIterable.hpp - iterable/OpenStarIterable.cpp - iterable/TopLevelCofacesIterable.hpp - iterable/TopLevelCofacesIterable.cpp - iterable/SimplexBoundaryIterable.hpp - iterable/SimplexBoundaryIterable.cpp internal/SimplexEqualFunctor.hpp internal/SimplexLessFunctor.hpp ) target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) +add_subdirectory(utils) +add_subdirectory(iterable) diff --git a/src/wmtk/simplex/iterable/CMakeLists.txt b/src/wmtk/simplex/iterable/CMakeLists.txt new file mode 100644 index 0000000000..9792dc557b --- /dev/null +++ b/src/wmtk/simplex/iterable/CMakeLists.txt @@ -0,0 +1,13 @@ +set(SRC_FILES + ClosedStarIterable.hpp + ClosedStarIterable.cpp + LinkIterable.hpp + LinkIterable.cpp + OpenStarIterable.hpp + OpenStarIterable.cpp + TopLevelCofacesIterable.hpp + TopLevelCofacesIterable.cpp + SimplexBoundaryIterable.hpp + SimplexBoundaryIterable.cpp +) +target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) diff --git a/src/wmtk/simplex/top_level_cofaces.cpp b/src/wmtk/simplex/top_level_cofaces.cpp index 72d0cde670..bada87411f 100644 --- a/src/wmtk/simplex/top_level_cofaces.cpp +++ b/src/wmtk/simplex/top_level_cofaces.cpp @@ -1,5 +1,6 @@ #include "top_level_cofaces.hpp" #include +#include "utils/tuple_vector_to_homogeneous_simplex_vector.hpp" #include #include @@ -14,16 +15,6 @@ namespace wmtk::simplex { namespace { -std::vector tuple_to_simplices(const std::vector& tups, PrimitiveType primitive) -{ - std::vector r; - r.reserve(tups.size()); - std::transform(tups.begin(), tups.end(), std::back_inserter(r), [primitive](const Tuple& t) { - return Simplex(primitive, t); - }); - return r; -} - std::vector top_level_cofaces_tuples_vertex(const TriMesh& mesh, const Tuple& t) { std::vector collection; @@ -223,7 +214,9 @@ top_level_cofaces(const TriMesh& mesh, const Simplex& simplex, const bool sort_a { SimplexCollection collection( mesh, - tuple_to_simplices(top_level_cofaces_tuples(mesh, simplex), PrimitiveType::Face)); + utils::tuple_vector_to_homogeneous_simplex_vector( + top_level_cofaces_tuples(mesh, simplex), + PrimitiveType::Face)); if (sort_and_clean) { collection.sort_and_clean(); } @@ -236,7 +229,9 @@ top_level_cofaces(const TetMesh& mesh, const Simplex& simplex, const bool sort_a { SimplexCollection collection( mesh, - tuple_to_simplices(top_level_cofaces_tuples(mesh, simplex), PrimitiveType::Tetrahedron)); + utils::tuple_vector_to_homogeneous_simplex_vector( + top_level_cofaces_tuples(mesh, simplex), + PrimitiveType::Tetrahedron)); if (sort_and_clean) { collection.sort_and_clean(); } @@ -249,7 +244,9 @@ top_level_cofaces(const Mesh& mesh, const Simplex& simplex, const bool sort_and_ { SimplexCollection collection( mesh, - tuple_to_simplices(top_level_cofaces_tuples(mesh, simplex), mesh.top_simplex_type())); + utils::tuple_vector_to_homogeneous_simplex_vector( + top_level_cofaces_tuples(mesh, simplex), + mesh.top_simplex_type())); if (sort_and_clean) { collection.sort_and_clean(); } diff --git a/src/wmtk/simplex/utils/CMakeLists.txt b/src/wmtk/simplex/utils/CMakeLists.txt new file mode 100644 index 0000000000..8a5f6ee2b6 --- /dev/null +++ b/src/wmtk/simplex/utils/CMakeLists.txt @@ -0,0 +1,5 @@ +set(SRC_FILES + tuple_vector_to_homogeneous_simplex_vector.hpp + tuple_vector_to_homogeneous_simplex_vector.cpp + ) +target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) diff --git a/src/wmtk/simplex/utils/tuple_vector_to_homogeneous_simplex_vector.cpp b/src/wmtk/simplex/utils/tuple_vector_to_homogeneous_simplex_vector.cpp new file mode 100644 index 0000000000..5e713cf2d4 --- /dev/null +++ b/src/wmtk/simplex/utils/tuple_vector_to_homogeneous_simplex_vector.cpp @@ -0,0 +1,18 @@ + +#include "tuple_vector_to_homogeneous_simplex_vector.hpp" +#include +#include + +namespace wmtk::simplex::utils { +std::vector tuple_vector_to_homogeneous_simplex_vector( + const std::vector& tups, + PrimitiveType primitive) +{ + std::vector r; + r.reserve(tups.size()); + std::transform(tups.begin(), tups.end(), std::back_inserter(r), [primitive](const Tuple& t) { + return Simplex(primitive, t); + }); + return r; +} +} // namespace wmtk::simplex::utils diff --git a/src/wmtk/simplex/utils/tuple_vector_to_homogeneous_simplex_vector.hpp b/src/wmtk/simplex/utils/tuple_vector_to_homogeneous_simplex_vector.hpp new file mode 100644 index 0000000000..ad8b91d7f1 --- /dev/null +++ b/src/wmtk/simplex/utils/tuple_vector_to_homogeneous_simplex_vector.hpp @@ -0,0 +1,11 @@ +#pragma once +#include +#include +#include + + +namespace wmtk::simplex::utils { +std::vector tuple_vector_to_homogeneous_simplex_vector( + const std::vector&, + PrimitiveType primitive); +} From ef407357af298b2be65f49b0f32ff23b99e5f091 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Sun, 1 Oct 2023 00:02:16 -0400 Subject: [PATCH 04/25] more updates to multimesh --- src/wmtk/MultiMeshManager.cpp | 67 +++++++++++++++++++++++++---------- src/wmtk/MultiMeshManager.hpp | 16 +++++++-- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 24544ecf0a..2bcdd4547d 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -1,4 +1,5 @@ #include "MultiMeshManager.hpp" +#include #include "Mesh.hpp" #include "SimplicialComplex.hpp" #include "Types.hpp" @@ -48,11 +49,9 @@ void write_tuple_map_attribute_slow( std::tuple read_tuple_map_attribute( const Mesh& source_mesh, - MeshAttributeHandle map_handle, + const ConstAccessor& accessor, const Tuple& source_tuple) -{ - auto map_accessor = source_mesh.create_accessor(map_handle); -} +{} std::tuple read_tuple_map_attribute_slow( MeshAttributeHandle map_handle, const Mesh& source_mesh, @@ -63,15 +62,18 @@ std::tuple read_tuple_map_attribute_slow( return std::make_tuple(vector5_to_tuple(map.head<5>()), vector5_to_tuple(map.tail<5>())); } +} // namespace -Tuple map_tuple_between_meshes( +Tuple MultiMeshManager::map_tuple_between_meshes( const Mesh& source_mesh, const Mesh& target_mesh, - MeshAttributeHandle source_map_handle, + const ConstAccessor& source_to_target_map_accessor, const Tuple& source_tuple) { PrimitiveType source_mesh_primitive_type = source_mesh.top_simplex_type(); PrimitiveType target_mesh_primitive_type = target_mesh.top_simplex_type(); + PrimitiveType min_primitive_type = + std::min(source_mesh_primitive_type, target_mesh_primitive_type); auto [source_mesh_base_tuple, target_mesh_base_tuple] = read_tuple_map_attribute(source_map_handle, source_mesh, source_tuple); @@ -79,7 +81,12 @@ Tuple map_tuple_between_meshes( if (source_mesh_base_tuple.is_null() || target_mesh_base_tuple.is_null()) { return Tuple(); // return null tuple } + const std::array map_type{ + {source_mesh_primitive_type, target_mesh_primitive_type}}; + + transport_tuple(source_mesh_base_tuple, source_tuple, target_tuple, min_primimtive_type); + /* if (source_mesh_primitive_type == PrimitiveType::Face && target_mesh_primitive_type == PrimitiveType::Face) { Tuple cur_tuple = source_tuple; @@ -100,13 +107,15 @@ Tuple map_tuple_between_meshes( } return ret_tuple; - } else { - // TODO: implement this for other cases later - // TODO: maybe use a seperate function for each case? - return Tuple(); - } + */ +} +else +{ + // TODO: implement this for other cases later + // TODO: maybe use a seperate function for each case? + return Tuple(); +} } -} // namespace MultiMeshManager::MultiMeshManager() = default; @@ -206,33 +215,55 @@ void MultiMeshManager::register_child_mesh( std::vector MultiMeshManager::map(const Mesh& my_mesh, const Mesh& other_mesh, const Simplex& my_simplex) const +{ + const auto ret_tups = map_to_tuples(my_mesh, other_mesh, my_simplex); + return simplex::utils::tuple_vector_to_homogeneous_simplex_vector( + ret_tups, + my_simplex.primitive_type()); +} +std::vector MultiMeshManager::map_to_tuples( + const Mesh& my_mesh, + const Mesh& other_mesh, + const Simplex& my_simplex) const { assert(&my_mesh.m_multi_mesh_manager == this); // TODO: construct relative positions + std::vector equivalent_tuples = simplex::top_level_cofaces(my_simplex); // TODO: construct visitor class that maps up and down + // MultiMeshMapVisitor visitor(my_mesh, other_mesh); // TODO: visitor runs along meshes traversing the path - throw "not implemented"; + + // visitor.map(equivalent_tuples, my_simplex.primitive_type()); return {}; } -std::vector MultiMeshManager::map_to_parent(const Mesh& my_mesh, const Simplex& my_simplex) - const +Simplex MultiMeshManager::map_to_parent(const Mesh& my_mesh, const Simplex& my_simplex) const +{ + return Simplex(my_simplex.primitive_type(), map_to_parent_tuple(my_mesh, my_simplex)); +} + +Tuple MultiMeshManager::map_tuple_to_parent(const Mesh& my_mesh, const Tuple& my_tuple) const { assert(&my_mesh.m_multi_mesh_manager == this); assert(!is_root()); - const Mesh& parent = *m_parent; + const Mesh& parent_mesh = *m_parent; const auto& map_handle = map_to_parent_handle; // assert(!map_handle.is_null()); - map_tuple_between_meshes(my_mesh, parent, map_handle, my_simplex); + map_tuple_between_meshes(my_mesh, parent_mesh, map_handle, my_simplex); } +std::vector MultiMeshManager::map_to_child( + const Mesh& my_mesh, + const Mesh& child_mesh, + const Simplex& my_simplex) const +{} // generic mapping function that maps a tuple from "this" mesh to one of its children -std::vector MultiMeshManager::map_to_child( +std::vector MultiMeshManager::map_to_child_tuples( const Mesh& my_mesh, const Mesh& child_mesh, const Simplex& my_simplex) const diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index 118dcb0170..f3805153a3 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -59,7 +59,8 @@ class MultiMeshManager const; - std::vector map_to_parent(const Mesh& my_mesh, const Simplex& my_simplex) const; + Tuple map_to_parent(const Mesh& my_mesh, const Simplex& my_simplex) const; + Tuple map_to_parent_tuple(const Mesh& my_mesh, const Simplex& my_simplex) const; // generic mapping function that maps a tuple from "this" mesh to one of its children std::vector @@ -75,10 +76,12 @@ class MultiMeshManager // Tuple maps //=========== // generic mapping function that maps a tuple from "this" mesh to the other mesh - Tuple map(const Mesh& my_mesh, const Mesh& other_mesh, const Tuple& my_tuple) const; + std::vector + map_to_tuples(const Mesh& my_mesh, const Mesh& other_mesh, const Tuple& my_tuple) const; // generic mapping function that maps a tuple from "this" mesh to its parent - Tuple map_to_parent(const Mesh& my_mesh, const Mesh& parent_mesh, const Tuple& my_tuple) const; + Tuple map_tuple_to_parent(const Mesh& my_mesh, const Mesh& parent_mesh, const Tuple& my_tuple) + const; // generic mapping function that maps a tuple from "this" mesh to one of its children Tuple map_to_child(const Mesh& my_mesh, const Mesh& child_mesh, const Tuple& my_tuple) const; @@ -102,6 +105,13 @@ class MultiMeshManager // checks that the map is consistent bool is_child_map_valid(const Mesh& my_mesh, const ChildData& child) const; + + static Tuple map_tuple_between_meshes( + const Mesh& source_mesh, + const Mesh& target_mesh, + const ConstAccessor& source_to_target_map_accessor, + const Tuple& source_tuple); + private: Mesh* m_parent = nullptr; // only valid if this is teh child of some other mesh From bc151d5f14dc93a1bb5cfc621dff2f0cee950d3c Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Mon, 2 Oct 2023 13:32:00 -0400 Subject: [PATCH 05/25] adding multimesh utility functions to simplify manager implementation --- src/wmtk/CMakeLists.txt | 1 + src/wmtk/MultiMeshManager.cpp | 70 +++++++------------ src/wmtk/MultiMeshManager.hpp | 41 +++++------ src/wmtk/multimesh/CMakeLists.txt | 1 + src/wmtk/multimesh/utils/CMakeLists.txt | 13 ++++ .../utils/find_local_switch_sequence.cpp | 56 +++++++++++++++ .../utils/find_local_switch_sequence.hpp | 13 ++++ .../multimesh/utils/local_switch_tuple.cpp | 26 +++++++ .../multimesh/utils/local_switch_tuple.hpp | 52 ++++++++++++++ src/wmtk/multimesh/utils/transport_tuple.cpp | 17 +++++ src/wmtk/multimesh/utils/transport_tuple.hpp | 16 +++++ .../utils/tuple_map_attribute_io.cpp | 63 +++++++++++++++++ .../utils/tuple_map_attribute_io.hpp | 27 +++++++ tests/CMakeLists.txt | 2 +- 14 files changed, 331 insertions(+), 67 deletions(-) create mode 100644 src/wmtk/multimesh/CMakeLists.txt create mode 100644 src/wmtk/multimesh/utils/CMakeLists.txt create mode 100644 src/wmtk/multimesh/utils/find_local_switch_sequence.cpp create mode 100644 src/wmtk/multimesh/utils/find_local_switch_sequence.hpp create mode 100644 src/wmtk/multimesh/utils/local_switch_tuple.cpp create mode 100644 src/wmtk/multimesh/utils/local_switch_tuple.hpp create mode 100644 src/wmtk/multimesh/utils/transport_tuple.cpp create mode 100644 src/wmtk/multimesh/utils/transport_tuple.hpp create mode 100644 src/wmtk/multimesh/utils/tuple_map_attribute_io.cpp create mode 100644 src/wmtk/multimesh/utils/tuple_map_attribute_io.hpp diff --git a/src/wmtk/CMakeLists.txt b/src/wmtk/CMakeLists.txt index 86b477eb92..bd155cf7a1 100644 --- a/src/wmtk/CMakeLists.txt +++ b/src/wmtk/CMakeLists.txt @@ -35,4 +35,5 @@ add_subdirectory(simplex) add_subdirectory(operations) add_subdirectory(autogen) add_subdirectory(invariants) +add_subdirectory(multimesh) diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 2bcdd4547d..a3ebe309bf 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -3,6 +3,7 @@ #include "Mesh.hpp" #include "SimplicialComplex.hpp" #include "Types.hpp" +#include "multimesh/utils/transport_tuple.hpp" namespace wmtk { namespace { @@ -26,42 +27,45 @@ Tuple vector5_to_tuple(const Eigen::MatrixBase& v) void write_tuple_map_attribute_slow( - Mesh& source_mesh, - MeshAttributeHandle map_handle, + Accessor& map_accessor, const Tuple& source_tuple, const Tuple& target_tuple) { - auto map_accessor = source_mesh.create_accessor(map_handle); - write_tuple_map_attribute(source_mesh, map_handle, source_tuple, target_tuple); + auto map = map_accessor.vector_attribute(source_tuple); + + map.head<5>() = tuple_to_vector5(source_tuple); + map.tail<5>() = tuple_to_vector5(target_tuple); } void write_tuple_map_attribute_slow( Mesh& source_mesh, - Accessor& map_accessor, + MeshAttributeHandle map_handle, const Tuple& source_tuple, const Tuple& target_tuple) { - auto map = map_accessor.vector_attribute(source_tuple); - - map.head<5>() = tuple_to_vector5(source_tuple); - map.tail<5>() = tuple_to_vector5(target_tuple); + auto map_accessor = source_mesh.create_accessor(map_handle); + write_tuple_map_attribute(map_handle, source_tuple, target_tuple); } std::tuple read_tuple_map_attribute( - const Mesh& source_mesh, const ConstAccessor& accessor, const Tuple& source_tuple) -{} -std::tuple read_tuple_map_attribute_slow( - MeshAttributeHandle map_handle, - const Mesh& source_mesh, - const Tuple& source_tuple) { auto map = map_accessor.const_vector_attribute(source_tuple); return std::make_tuple(vector5_to_tuple(map.head<5>()), vector5_to_tuple(map.tail<5>())); } + +std::tuple read_tuple_map_attribute_slow( + const Mesh& source_mesh, + MeshAttributeHandle map_handle, + const Tuple& source_tuple) +{ + auto acc = source_mesh.get_const_accessor(map_handle); + read_tuple_map_attribute_slow(acc, source_tuple); +} + } // namespace Tuple MultiMeshManager::map_tuple_between_meshes( @@ -84,37 +88,11 @@ Tuple MultiMeshManager::map_tuple_between_meshes( const std::array map_type{ {source_mesh_primitive_type, target_mesh_primitive_type}}; - transport_tuple(source_mesh_base_tuple, source_tuple, target_tuple, min_primimtive_type); - - /* - if (source_mesh_primitive_type == PrimitiveType::Face && - target_mesh_primitive_type == PrimitiveType::Face) { - Tuple cur_tuple = source_tuple; - std::vector record_switch_operations; - while (cur_tuple != source_mesh_base_tuple) { - cur_tuple = source_mesh.switch_tuple(cur_tuple, PrimitiveType::Vertex); - record_switch_operations.push_back(PrimitiveType::Vertex); - if (cur_tuple == source_mesh_base_tuple) { - break; - } - cur_tuple = source_mesh.switch_tuple(cur_tuple, PrimitiveType::Edge); - record_switch_operations.push_back(PrimitiveType::Edge); - } - - Tuple ret_tuple = target_mesh_base_tuple; - for (int i = record_switch_operations.size() - 1; i >= 0; --i) { - ret_tuple = target_mesh.switch_tuple(ret_tuple, record_switch_operations[i]); - } - - return ret_tuple; - */ -} -else -{ - // TODO: implement this for other cases later - // TODO: maybe use a seperate function for each case? - return Tuple(); -} + multimesh::utils::transport_tuple( + source_mesh_base_tuple, + source_tuple, + target_tuple, + min_primimtive_type); } diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index f3805153a3..d7908dbf50 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -71,6 +71,27 @@ class MultiMeshManager std::vector map_edge_tuple_to_all_children(const Mesh& my_mesh, const Simplex& tuple) const; + +private: + Mesh* m_parent = nullptr; + // only valid if this is teh child of some other mesh + // store the map to the base_tuple of the my_mesh + MeshAttributeHandle map_to_parent_handle; + long m_child_id = -1; + + struct ChildData + { + std::shared_ptr mesh; + // store the map from the manager's mesh to the child mesh (on the top + // level simplex of the mesh) + // encoded by a pair of two tuples, from a tuple in current mesh to a tuple in + // child_mesh + MeshAttributeHandle map_handle; + }; + + // Child Meshes + std::vector m_children; + protected: // protected to enable unit testing //=========== // Tuple maps @@ -111,26 +132,6 @@ class MultiMeshManager const Mesh& target_mesh, const ConstAccessor& source_to_target_map_accessor, const Tuple& source_tuple); - -private: - Mesh* m_parent = nullptr; - // only valid if this is teh child of some other mesh - // store the map to the base_tuple of the my_mesh - MeshAttributeHandle map_to_parent_handle; - long m_child_id = -1; - - struct ChildData - { - std::shared_ptr mesh; - // store the map from the manager's mesh to the child mesh (on the top - // level simplex of the mesh) - // encoded by a pair of two tuples, from a tuple in current mesh to a tuple in - // child_mesh - MeshAttributeHandle map_handle; - }; - - // Child Meshes - std::vector m_children; }; } // namespace wmtk diff --git a/src/wmtk/multimesh/CMakeLists.txt b/src/wmtk/multimesh/CMakeLists.txt new file mode 100644 index 0000000000..512d2b1553 --- /dev/null +++ b/src/wmtk/multimesh/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(utils) diff --git a/src/wmtk/multimesh/utils/CMakeLists.txt b/src/wmtk/multimesh/utils/CMakeLists.txt new file mode 100644 index 0000000000..4e611a9b80 --- /dev/null +++ b/src/wmtk/multimesh/utils/CMakeLists.txt @@ -0,0 +1,13 @@ + +set(SRC_FILES + find_local_switch_sequence.cpp + local_switch_tuple.cpp + transport_tuple.cpp + find_local_switch_sequence.hpp + local_switch_tuple.hpp + transport_tuple.hpp + tuple_map_attribute_io.hpp + tuple_map_attribute_io.cpp + ) +target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) + diff --git a/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp b/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp new file mode 100644 index 0000000000..8e27b70965 --- /dev/null +++ b/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp @@ -0,0 +1,56 @@ +#include "find_local_switch_sequence.hpp" +namespace wmtk::multimesh::utils { + + +namespace { + +std::vector find_local_switch_sequence_trimesh( + const Tuple& source, + const Tuple& target) +{ + // TODO: assert that base_source and base_target use the same global CID + + // circulate + Tuple cur_tuple = source; + std::vector switches; + auto try_and_record = [&](PrimitiveType pt) -> bool { + cur_tuple = local_switch_tuple(cur_tuple, pt); + switches.emplace_back(pt); + return cur_tuple == target; + }; + for (long j = 0; j < 3; ++j) { + for (PrimitiveType pt : {PrimtiiveType::Vertex, PrimitiveType::Edge}) { + if (try_and_record(pt)) { + return switches; + } + } + } + throw "switch sequence was unable to find a sequence of switches to match tuples"; + return switches; +} +std::vector find_local_switch_sequence_edgemesh( + const Tuple& source, + const Tuple& target) +{ + if(source != target) { + return std::vector{PrimitiveType::switch_vertex}; + } else { + return std::vector{}; + } + throw "switch sequence was unable to find a sequence of switches to match tuples"; +} +} // namespace + +// Maps the tuple source according to the operation sequence +// std::vector operations where operations satisfies +// base_target = switch_tuples(base_source, operations) +std::vector +find_local_switch_sequence(const Tuple& source, const Tuple& target, PrimitiveType primitive_type) +{ + switch (primitive_type) { + case PrimitiveType::Face: return find_local_switch_sequence_trimesh(source, target); + case PrimitiveType::Edge: return find_local_switch_sequence_edgemesh(source, target); + default: return {}; + } +} +} // namespace wmtk::multimesh::utils diff --git a/src/wmtk/multimesh/utils/find_local_switch_sequence.hpp b/src/wmtk/multimesh/utils/find_local_switch_sequence.hpp new file mode 100644 index 0000000000..451a31854f --- /dev/null +++ b/src/wmtk/multimesh/utils/find_local_switch_sequence.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include +#include + +namespace wmtk::multimesh::utils { + +// Maps the tuple source according to the operation sequence +// std::vector operations where operations satisfies +// base_target = switch_tuples(base_source, operations) +std::vector +find_local_switch_sequence(const Tuple& source, const Tuple& target, PrimitiveType primitive_type); +} // namespace wmtk::multimesh::utils diff --git a/src/wmtk/multimesh/utils/local_switch_tuple.cpp b/src/wmtk/multimesh/utils/local_switch_tuple.cpp new file mode 100644 index 0000000000..4d510af0df --- /dev/null +++ b/src/wmtk/multimesh/utils/local_switch_tuple.cpp @@ -0,0 +1,26 @@ +#include "local_switch_tuple.hpp" +#include +#include +#include + +namespace wmtk::multimesh::utils { + +Tuple local_switch_tuple(const Tuple& source, PrimitiveType primitive_type) +{ + switch (primitive_type) { + case PrimitiveType::Face: return autogen::tri_mesh::local_switch_tuple(source); + case PrimitiveType::Tetrahedron: return autogen::tet_mesh::local_switch_tuple(source); + default: return Tuple(); + } + + Tuple local_switch_tuples( + PrimitiveType mesh_primitive_type, + const Tuple& tuple, + const std::initializer_list& op_sequence) const + { + return local_switch_tuples>( + mesh_primitive_type, + tuple, + op_sequence); + } +} diff --git a/src/wmtk/multimesh/utils/local_switch_tuple.hpp b/src/wmtk/multimesh/utils/local_switch_tuple.hpp new file mode 100644 index 0000000000..2f50265fda --- /dev/null +++ b/src/wmtk/multimesh/utils/local_switch_tuple.hpp @@ -0,0 +1,52 @@ +#pragma once +#include +#include + +namespace wmtk::multimesh::utils { + +// Maps the tuple source according to the operation sequence +// std::vector operations where operations satisfies +// base_target = switch_tuples(base_source, operations) +Tuple local_switch_tuple( + PrimitiveType mesh_primitive_type, + const Tuple& source, + PrimitiveType primitive_type); + + +// Performs a sequence of switch_tuple operations in the order specified in op_sequence. +// in debug mode this will assert a failure, in release this will return a null tuple +#if defined(__cpp_concepts) +template +#else +template +#endif +Tuple local_switch_tuples( + PrimitiveType mesh_primitive_type, + const Tuple& tuple, + const ContainerType& op_sequence) const; +// annoying initializer list prototype to catch switch_tuples(t, {PV,PE}) +Tuple local_switch_tuples( + PrimitiveType mesh_primitive_type, + const Tuple& tuple, + const std::initializer_list& op_sequence) const; + + +#if defined(__cpp_concepts) +template +#else +template +#endif +Tuple local_switch_tuples( + PrimitiveType mesh_primitive_type, + const Tuple& tuple, + const std::initializer_list& op_sequence) const +{ + static_assert(std::is_same_v); + Tuple r = tuple; + for (const PrimitiveType primitive : sequence) { + r = local_switch_tuple(mesh_primitive_type, r, primitive); + } + return r; +} + +} // namespace wmtk::multimesh::utils diff --git a/src/wmtk/multimesh/utils/transport_tuple.cpp b/src/wmtk/multimesh/utils/transport_tuple.cpp new file mode 100644 index 0000000000..1458f9009f --- /dev/null +++ b/src/wmtk/multimesh/utils/transport_tuple.cpp @@ -0,0 +1,17 @@ +#include "transport_tuple.hpp" +#include "find_local_switch_sequence.hpp" + +namespace wmtk::multimesh::utils { + +Tuple transport_tuple( + const Tuple& base_source, + const Tuple& base_target, + PrimitiveType base_primitive_type, + const Tuple& source, + PrimitiveType primitive_type) +{ + std::vector operations = + find_local_switch_sequence(base_source, base_target, base_primitive_type); + return local_switch_tuples(primitive_type, source, operations); +} +} // namespace wmtk::multimesh::utils diff --git a/src/wmtk/multimesh/utils/transport_tuple.hpp b/src/wmtk/multimesh/utils/transport_tuple.hpp new file mode 100644 index 0000000000..6363a4bcea --- /dev/null +++ b/src/wmtk/multimesh/utils/transport_tuple.hpp @@ -0,0 +1,16 @@ +#pragma once +#include +#include + +namespace wmtk::multimesh::utils { + +// Maps the tuple source according to the operation sequence +// std::vector operations where operations satisfies +// base_target = switch_tuples(base_source, operations) +Tuple transport_tuple( + const Tuple& base_source, + const Tuple& base_target, + PrimitiveType base_primitive_type, + const Tuple& source, + PrimitiveType primitive_type); +} // namespace wmtk::multimesh::utils diff --git a/src/wmtk/multimesh/utils/tuple_map_attribute_io.cpp b/src/wmtk/multimesh/utils/tuple_map_attribute_io.cpp new file mode 100644 index 0000000000..b9b8ed375c --- /dev/null +++ b/src/wmtk/multimesh/utils/tuple_map_attribute_io.cpp @@ -0,0 +1,63 @@ +#include "tuple_map_attribute_io.hpp" +#include "Types.hpp" +namespace wmtk::multimesh::utils { +{ + namespace { + Vector tuple_to_vector5(const Tuple& t) + { + Vector v; + v(0) = t.m_local_vid; + v(1) = t.m_local_eid; + v(2) = t.m_local_fid; + v(3) = t.m_global_cid; + v(4) = t.m_hash; + return v; + } + + template + Tuple vector5_to_tuple(const Eigen::MatrixBase& v) + { + Tuple(v(0), v(1), v(2), v(3), v(4)), + } + } // namespace + + void write_tuple_map_attribute( + Accessor & map_accessor, + const Tuple& source_tuple, + const Tuple& target_tuple) + { + auto map = map_accessor.vector_attribute(source_tuple); + + map.head<5>() = tuple_to_vector5(source_tuple); + map.tail<5>() = tuple_to_vector5(target_tuple); + } + + void write_tuple_map_attribute_slow( + Mesh & source_mesh, + MeshAttributeHandle map_handle, + const Tuple& source_tuple, + const Tuple& target_tuple) + { + auto map_accessor = source_mesh.create_accessor(map_handle); + write_tuple_map_attribute(map_handle, source_tuple, target_tuple); + } + + std::tuple read_tuple_map_attribute( + const ConstAccessor& accessor, + const Tuple& source_tuple) + { + auto map = map_accessor.const_vector_attribute(source_tuple); + + return std::make_tuple(vector5_to_tuple(map.head<5>()), vector5_to_tuple(map.tail<5>())); + } + + + std::tuple read_tuple_map_attribute_slow( + const Mesh& source_mesh, + MeshAttributeHandle map_handle, + const Tuple& source_tuple) + { + auto acc = source_mesh.get_const_accessor(map_handle); + read_tuple_map_attribute_slow(acc, source_tuple); + } +} // namespace wmtk::::multimesh:::utils diff --git a/src/wmtk/multimesh/utils/tuple_map_attribute_io.hpp b/src/wmtk/multimesh/utils/tuple_map_attribute_io.hpp new file mode 100644 index 0000000000..5bd6235089 --- /dev/null +++ b/src/wmtk/multimesh/utils/tuple_map_attribute_io.hpp @@ -0,0 +1,27 @@ +#include + +namespace wmtk::multimesh::utils { + + +// utility functions to simplify how we encode 2-Tuple attributes as 10-long attribute +void write_tuple_map_attribute( + Accessor& map_accessor, + const Tuple& source_tuple, + const Tuple& target_tuple); + +std::tuple read_tuple_map_attribute( + const ConstAccessor& accessor, + const Tuple& source_tuple); + +void write_tuple_map_attribute_slow( + Mesh& source_mesh, + MeshAttributeHandle map_handle, + const Tuple& source_tuple, + const Tuple& target_tuple); + + +std::tuple read_tuple_map_attribute_slow( + const Mesh& source_mesh, + MeshAttributeHandle map_handle, + const Tuple& source_tuple); +} // namespace wmtk::multimesh::utils diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 08a53809f1..c882a30aed 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,7 +22,7 @@ set(TEST_SOURCES test_accessor.cpp test_example_meshes.cpp test_3d_operations.cpp - test_multi_mesh.cpp + #test_multi_mesh.cpp tools/DEBUG_PointMesh.hpp tools/DEBUG_TriMesh.hpp tools/DEBUG_TriMesh.cpp From 049713aa1f35f3930b78a50025b6743cb97958e0 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Tue, 3 Oct 2023 10:01:21 -0400 Subject: [PATCH 06/25] warning suppression --- tests/test_3d_operations.cpp | 10 +++++----- tests/tools/TetMesh_examples.hpp | 32 ++++++++++++++++---------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/test_3d_operations.cpp b/tests/test_3d_operations.cpp index a23a711575..858f987cb6 100644 --- a/tests/test_3d_operations.cpp +++ b/tests/test_3d_operations.cpp @@ -35,19 +35,19 @@ TEST_CASE("get_split_simplices_to_delete", "[operations][split][3d]") // debug code std::cout << "vertex: " << std::endl; - for (int i = 0; i < ids_to_delete[0].size(); i++) { + for (size_t i = 0; i < ids_to_delete[0].size(); i++) { std::cout << ids_to_delete[0][i] << std::endl; } std::cout << "edge: " << std::endl; - for (int i = 0; i < ids_to_delete[1].size(); i++) { + for (size_t i = 0; i < ids_to_delete[1].size(); i++) { std::cout << ids_to_delete[1][i] << std::endl; } std::cout << "face: " << std::endl; - for (int i = 0; i < ids_to_delete[2].size(); i++) { + for (size_t i = 0; i < ids_to_delete[2].size(); i++) { std::cout << ids_to_delete[2][i] << std::endl; } std::cout << "tet: " << std::endl; - for (int i = 0; i < ids_to_delete[3].size(); i++) { + for (size_t i = 0; i < ids_to_delete[3].size(); i++) { std::cout << ids_to_delete[3][i] << std::endl; } @@ -351,4 +351,4 @@ TEST_CASE("collapse_edge", "[operation][collapse][3d]") REQUIRE(m.is_connectivity_valid()); REQUIRE(m.valid_primitive_count(PT) == 5); } -} \ No newline at end of file +} diff --git a/tests/tools/TetMesh_examples.hpp b/tests/tools/TetMesh_examples.hpp index dccd69b172..e039048903 100644 --- a/tests/tools/TetMesh_examples.hpp +++ b/tests/tools/TetMesh_examples.hpp @@ -5,9 +5,9 @@ namespace wmtk::tests_3d { // 0 -// / \\ -// / \ \ -// / \ \ +// / \\ . +// / \ \ . +// / \ \ . // / \ \ 3 // 1 --------- 2 // @@ -35,29 +35,29 @@ TetMesh one_ear(); TetMesh two_ears(); // 0 ---------- 4 -// / \\ // \ -// / \ \ // \ -// / \ \ // \ -// / \ \3 \ +// / \\ // \ . +// / \ \ // \ . +// / \ \ // \ . +// / \ \3 \ . // 1 --------- 2/ -------- 5 tuple edge 2-3 // TetMesh three_incident_tets(); // 0 ---------- 4 -// / \\ // \ -// / \ \ // \ -// / \ \ // \ -// / \ \3 \ +// / \\ // \ . +// / \ \ // \ . +// / \ \ // \ . +// / \ \3 \ . // 1 --------- 2/ -------- 5 tuple edge 2-3 -// \ / /\ \ / -// \ / / \\ / -// \ // \\ / -// \ // \ / +// \ / /\ \ / . +// \ / / \\ / . +// \ // \\ / . +// \ // \ / . // 6 -----------7 // TetMesh six_cycle_tets(); -} // namespace wmtk::tests_3d \ No newline at end of file +} // namespace wmtk::tests_3d From 40960fcf9d3d06b814c7b64d04d22ba3f3a951bf Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Tue, 3 Oct 2023 10:53:33 -0400 Subject: [PATCH 07/25] typo and warning supprssion --- src/wmtk/{autogen => }/utils/TupleInspector.hpp | 0 tests/simplicial_complex_tests/3d_mesh_tests.cpp | 12 ++++++------ 2 files changed, 6 insertions(+), 6 deletions(-) rename src/wmtk/{autogen => }/utils/TupleInspector.hpp (100%) diff --git a/src/wmtk/autogen/utils/TupleInspector.hpp b/src/wmtk/utils/TupleInspector.hpp similarity index 100% rename from src/wmtk/autogen/utils/TupleInspector.hpp rename to src/wmtk/utils/TupleInspector.hpp diff --git a/tests/simplicial_complex_tests/3d_mesh_tests.cpp b/tests/simplicial_complex_tests/3d_mesh_tests.cpp index 78e6aa4bb9..a85e17a8dd 100644 --- a/tests/simplicial_complex_tests/3d_mesh_tests.cpp +++ b/tests/simplicial_complex_tests/3d_mesh_tests.cpp @@ -949,9 +949,9 @@ TEST_CASE("closed_star_bunny_tetwild_80", "[simplicial_complex][closed_star][3D] std::vector> sc_v, sc_e, sc_f, sc_t; t = m.tuple_from_id(PV, 4869); sc_v = get_sorted_sc(m, SimplicialComplex::closed_star(m, Simplex(PV, t)).get_simplex_vector()); - for (int i = 0; i < sc_v.size(); i++) { + for (size_t i = 0; i < sc_v.size(); i++) { std::cout << i << ": "; - for (int j = 0; j < sc_v[i].size(); j++) { + for (size_t j = 0; j < sc_v[i].size(); j++) { std::cout << sc_v[i][j] << " "; } std::cout << std::endl; @@ -2876,9 +2876,9 @@ TEST_CASE( sc_f = get_sorted_sc( m, SimplicialComplex::simplex_with_boundary(m, Simplex(PF, t)).get_simplex_vector()); - for (int i = 0; i < sc_f.size(); i++) { + for (size_t i = 0; i < sc_f.size(); i++) { std::cout << i << ": "; - for (int j = 0; j < sc_f[i].size(); j++) { + for (size_t j = 0; j < sc_f[i].size(); j++) { std::cout << sc_f[i][j] << " "; } std::cout << std::endl; @@ -3569,9 +3569,9 @@ TEST_CASE("top_coface_simplex_bunny_tetwild_80", "[simplicial_complex][top_cofac m, SimplicialComplex::top_coface_simplex(m, Simplex(PV, t)).get_simplex_vector()); - for (int i = 0; i < sc_v.size(); i++) { + for (size_t i = 0; i < sc_v.size(); i++) { std::cout << i << ": "; - for (int j = 0; j < sc_v[i].size(); j++) { + for (size_t j = 0; j < sc_v[i].size(); j++) { std::cout << sc_v[i][j] << " "; } std::cout << std::endl; From 50eb9f498a59eeef9a184dcda8fbb8c5ce5ef895 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Tue, 3 Oct 2023 11:20:03 -0400 Subject: [PATCH 08/25] finishing move of TupleInspector from previous commit --- src/wmtk/autogen/CMakeLists.txt | 1 - src/wmtk/autogen/tet_mesh/is_ccw.cpp | 2 +- src/wmtk/autogen/tet_mesh/local_id_table_offset.cpp | 2 +- src/wmtk/autogen/tet_mesh/local_switch_tuple.cpp | 2 +- src/wmtk/autogen/tri_mesh/is_ccw.cpp | 2 +- src/wmtk/autogen/tri_mesh/local_id_table_offset.cpp | 2 +- src/wmtk/autogen/tri_mesh/local_switch_tuple.cpp | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/wmtk/autogen/CMakeLists.txt b/src/wmtk/autogen/CMakeLists.txt index c0364a2250..1161c5d418 100644 --- a/src/wmtk/autogen/CMakeLists.txt +++ b/src/wmtk/autogen/CMakeLists.txt @@ -18,6 +18,5 @@ set(SRC_FILES tri_mesh/local_id_table_offset.cpp tri_mesh/local_id_table_offset.hpp - utils/TupleInspector.hpp ) target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) diff --git a/src/wmtk/autogen/tet_mesh/is_ccw.cpp b/src/wmtk/autogen/tet_mesh/is_ccw.cpp index 1f039bf210..d8b0e93c6d 100644 --- a/src/wmtk/autogen/tet_mesh/is_ccw.cpp +++ b/src/wmtk/autogen/tet_mesh/is_ccw.cpp @@ -1,6 +1,6 @@ #include "is_ccw.hpp" -#include +#include #include "autogenerated_tables.hpp" #include "local_id_table_offset.hpp" diff --git a/src/wmtk/autogen/tet_mesh/local_id_table_offset.cpp b/src/wmtk/autogen/tet_mesh/local_id_table_offset.cpp index 1993eb7243..eb79a36e31 100644 --- a/src/wmtk/autogen/tet_mesh/local_id_table_offset.cpp +++ b/src/wmtk/autogen/tet_mesh/local_id_table_offset.cpp @@ -1,5 +1,5 @@ #include "local_id_table_offset.hpp" -#include +#include #include "autogenerated_tables.hpp" namespace wmtk::autogen::tet_mesh { // computes the offset of a tuple's local ids in the tables diff --git a/src/wmtk/autogen/tet_mesh/local_switch_tuple.cpp b/src/wmtk/autogen/tet_mesh/local_switch_tuple.cpp index 0337d2d782..99bd2ea0cb 100644 --- a/src/wmtk/autogen/tet_mesh/local_switch_tuple.cpp +++ b/src/wmtk/autogen/tet_mesh/local_switch_tuple.cpp @@ -1,6 +1,6 @@ #include "local_switch_tuple.hpp" #include -#include +#include #include "autogenerated_tables.hpp" #include "local_id_table_offset.hpp" diff --git a/src/wmtk/autogen/tri_mesh/is_ccw.cpp b/src/wmtk/autogen/tri_mesh/is_ccw.cpp index 5485c189e6..35b496f9f0 100644 --- a/src/wmtk/autogen/tri_mesh/is_ccw.cpp +++ b/src/wmtk/autogen/tri_mesh/is_ccw.cpp @@ -1,6 +1,6 @@ #include "is_ccw.hpp" -#include +#include #include "autogenerated_tables.hpp" #include "local_id_table_offset.hpp" diff --git a/src/wmtk/autogen/tri_mesh/local_id_table_offset.cpp b/src/wmtk/autogen/tri_mesh/local_id_table_offset.cpp index e99927a060..5aeda960ec 100644 --- a/src/wmtk/autogen/tri_mesh/local_id_table_offset.cpp +++ b/src/wmtk/autogen/tri_mesh/local_id_table_offset.cpp @@ -1,5 +1,5 @@ #include "local_id_table_offset.hpp" -#include +#include #include "autogenerated_tables.hpp" namespace wmtk::autogen::tri_mesh { // computes the offset of a tuple's local ids in the tables diff --git a/src/wmtk/autogen/tri_mesh/local_switch_tuple.cpp b/src/wmtk/autogen/tri_mesh/local_switch_tuple.cpp index 5203878047..e88f9fa533 100644 --- a/src/wmtk/autogen/tri_mesh/local_switch_tuple.cpp +++ b/src/wmtk/autogen/tri_mesh/local_switch_tuple.cpp @@ -1,6 +1,6 @@ #include "local_switch_tuple.hpp" #include -#include +#include #include "autogenerated_tables.hpp" #include "local_id_table_offset.hpp" From c8e13a78d65b28d8f58910f37cf192f47609d11b Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Tue, 3 Oct 2023 11:20:16 -0400 Subject: [PATCH 09/25] fixing a namespace ambiguity in top level cofaces and updates to multimesh things --- src/wmtk/MultiMeshManager.cpp | 118 ++++++----------- src/wmtk/MultiMeshManager.hpp | 27 ++-- src/wmtk/TriMeshOperationExecutor.cpp | 10 ++ src/wmtk/Tuple.hpp | 4 +- .../utils/find_local_switch_sequence.cpp | 9 +- .../multimesh/utils/local_switch_tuple.cpp | 27 ++-- .../multimesh/utils/local_switch_tuple.hpp | 12 +- src/wmtk/multimesh/utils/transport_tuple.cpp | 1 + .../utils/tuple_map_attribute_io.cpp | 121 +++++++++--------- src/wmtk/simplex/top_level_cofaces.cpp | 6 +- src/wmtk/utils/CMakeLists.txt | 1 + src/wmtk/utils/TupleInspector.hpp | 2 +- 12 files changed, 163 insertions(+), 175 deletions(-) diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index a3ebe309bf..9ea68e74d4 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -2,76 +2,15 @@ #include #include "Mesh.hpp" #include "SimplicialComplex.hpp" -#include "Types.hpp" #include "multimesh/utils/transport_tuple.hpp" namespace wmtk { -namespace { - -Vector tuple_to_vector5(const Tuple& t) -{ - Vector v; - v(0) = t.m_local_vid; - v(1) = t.m_local_eid; - v(2) = t.m_local_fid; - v(3) = t.m_global_cid; - v(4) = t.m_hash; - return v; -} - -template -Tuple vector5_to_tuple(const Eigen::MatrixBase& v) -{ - Tuple(v(0), v(1), v(2), v(3), v(4)), -} - - -void write_tuple_map_attribute_slow( - Accessor& map_accessor, - const Tuple& source_tuple, - const Tuple& target_tuple) -{ - auto map = map_accessor.vector_attribute(source_tuple); - - map.head<5>() = tuple_to_vector5(source_tuple); - map.tail<5>() = tuple_to_vector5(target_tuple); -} - -void write_tuple_map_attribute_slow( - Mesh& source_mesh, - MeshAttributeHandle map_handle, - const Tuple& source_tuple, - const Tuple& target_tuple) -{ - auto map_accessor = source_mesh.create_accessor(map_handle); - write_tuple_map_attribute(map_handle, source_tuple, target_tuple); -} - -std::tuple read_tuple_map_attribute( - const ConstAccessor& accessor, - const Tuple& source_tuple) -{ - auto map = map_accessor.const_vector_attribute(source_tuple); - - return std::make_tuple(vector5_to_tuple(map.head<5>()), vector5_to_tuple(map.tail<5>())); -} - - -std::tuple read_tuple_map_attribute_slow( - const Mesh& source_mesh, - MeshAttributeHandle map_handle, - const Tuple& source_tuple) -{ - auto acc = source_mesh.get_const_accessor(map_handle); - read_tuple_map_attribute_slow(acc, source_tuple); -} - -} // namespace +namespace {} // namespace Tuple MultiMeshManager::map_tuple_between_meshes( const Mesh& source_mesh, const Mesh& target_mesh, - const ConstAccessor& source_to_target_map_accessor, + const ConstAccessor& map_accessor, const Tuple& source_tuple) { PrimitiveType source_mesh_primitive_type = source_mesh.top_simplex_type(); @@ -80,19 +19,18 @@ Tuple MultiMeshManager::map_tuple_between_meshes( std::min(source_mesh_primitive_type, target_mesh_primitive_type); auto [source_mesh_base_tuple, target_mesh_base_tuple] = - read_tuple_map_attribute(source_map_handle, source_mesh, source_tuple); + read_tuple_map_attribute(map_accessor, source_mesh, source_tuple); if (source_mesh_base_tuple.is_null() || target_mesh_base_tuple.is_null()) { return Tuple(); // return null tuple } - const std::array map_type{ - {source_mesh_primitive_type, target_mesh_primitive_type}}; multimesh::utils::transport_tuple( source_mesh_base_tuple, source_tuple, + source_mesh_primitive_type, target_tuple, - min_primimtive_type); + primitive_type); } @@ -232,30 +170,56 @@ Tuple MultiMeshManager::map_tuple_to_parent(const Mesh& my_mesh, const Tuple& my const auto& map_handle = map_to_parent_handle; // assert(!map_handle.is_null()); - map_tuple_between_meshes(my_mesh, parent_mesh, map_handle, my_simplex); + auto map_accessor = my_mesh.get_accessor(map_handle); + return map_tuple_between_meshes(my_mesh, parent_mesh, map_accessor, my_simplex); } -std::vector MultiMeshManager::map_to_child( +std::vector MultiMeshManager::map_to_child_tuples( const Mesh& my_mesh, - const Mesh& child_mesh, + const ChildData& child_data, const Simplex& my_simplex) const -{} +{ + assert(&my_mesh.m_multi_mesh_manager == this); + + const Mesh& child_mesh = *child_data.mesh; + const auto map_handle = child_data.map_handle; + // we will rewrite these tuples inline with the mapped ones + std::vector tuples = simplex::top_level_cofaces(my_simplex); + + auto map_accessor = my_mesh.get_accessor(map_handle); + for (Tuple& tuple : tuples) { + tuple = map_tuple_between_meshes(my_mesh, child_mesh, map_accessor, tuple); + } + return tuples; +} -// generic mapping function that maps a tuple from "this" mesh to one of its children std::vector MultiMeshManager::map_to_child_tuples( const Mesh& my_mesh, const Mesh& child_mesh, const Simplex& my_simplex) const { - assert(&my_mesh.m_multi_mesh_manager == this); + return map_to_child_tuples(my_mesh, child_mesh.m_multi_mesh_manager.child_id(), my_simplex); } +std::vector MultiMeshManager::map_to_child_tuples( + const Mesh& my_mesh, + long child_id, + const Simplex& my_simplex) const +{ + // this is just to do a little redirection for simpplifying map_to_child (and potentially for a + // visitor pattern) + return map_to_child_tuples(my_mesh, m_children.at(child_id), my_simplex); +} -std::vector -MultiMeshManager::convert_tuple_to_child(const Mesh& my_mesh, long child_id, const Simplex& simplex) +std::vector MultiMeshManager::map_to_child_tuples( + const Mesh& my_mesh, + const Mesh& child_mesh, + const Simplex& my_simplex) const { - assert(&my_mesh.m_multi_mesh_manager == this); - return find_all_simplices_in_child_mesh(my_mesh, m_children.at(child_id), simplex_parent); + auto tuples = map_to_child_tuples(my_mesh, child_mesh, my_simplex); + return tuple_vector_to_homogeneous_simplex_vector(tuples, my_simplex.primitive_type()); } + + std::vector MultiMeshManager::find_all_simplices_in_child_mesh( const Mesh& my_mesh, const ChildData& child_data, diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index d7908dbf50..1cf7b1030a 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -1,13 +1,14 @@ #pragma once #include #include +#include "Accessor.hpp" #include "Simplex.hpp" #include "Tuple.hpp" -#include "attribute/AttributeManager.hpp" #include "attribute/AttributeScopeHandle.hpp" #include "attribute/MeshAttributes.hpp" namespace wmtk { + class Mesh; class MultiMeshManager { @@ -63,7 +64,12 @@ class MultiMeshManager Tuple map_to_parent_tuple(const Mesh& my_mesh, const Simplex& my_simplex) const; // generic mapping function that maps a tuple from "this" mesh to one of its children - std::vector + std::vector map_to_child_tuples( + const Mesh& my_mesh, + const Mesh& child_mesh, + const Simplex& my_simplex) const; + + std::vector map_to_child(const Mesh& my_mesh, const Mesh& child_mesh, const Simplex& my_simplex) const; @@ -98,27 +104,24 @@ class MultiMeshManager //=========== // generic mapping function that maps a tuple from "this" mesh to the other mesh std::vector - map_to_tuples(const Mesh& my_mesh, const Mesh& other_mesh, const Tuple& my_tuple) const; + map_to_tuples(const Mesh& my_mesh, const Mesh& other_mesh, const Simplex& my_simplex) const; // generic mapping function that maps a tuple from "this" mesh to its parent Tuple map_tuple_to_parent(const Mesh& my_mesh, const Mesh& parent_mesh, const Tuple& my_tuple) const; - // generic mapping function that maps a tuple from "this" mesh to one of its children - Tuple map_to_child(const Mesh& my_mesh, const Mesh& child_mesh, const Tuple& my_tuple) const; - - // generic mapping function that maps a tuple from "this" mesh to one of its children (by index) - Tuple map_to_child(const Mesh& my_mesh, long child_id, const Tuple& my_tuple) const; // wrapper for implementing converting tuple to a child using the internal map data - std::vector - map_to_child(const Mesh& my_mesh, const ChildData& child_data, const Tuple& simplex) const; - - std::vector convert_single_tuple( + std::vector map_to_child_tuples( const Mesh& my_mesh, const ChildData& child_data, const Simplex& simplex) const; + // wrapper for implementing converting tuple to a child using the internal map data + std::vector + map_to_child_tuples(const Mesh& my_mesh, long child_id, const Simplex& simplex) const; + + // helper function to check if this mesh is a valid child_mesh of my_mesh // i.e. the connectivity of this mesh is a subset of this in my_mesh bool is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const; diff --git a/src/wmtk/TriMeshOperationExecutor.cpp b/src/wmtk/TriMeshOperationExecutor.cpp index 38b63c8624..d9875c85fb 100644 --- a/src/wmtk/TriMeshOperationExecutor.cpp +++ b/src/wmtk/TriMeshOperationExecutor.cpp @@ -370,6 +370,7 @@ std::vector> TriMesh::TriMeshOperationExecutor::prepare_operating_tuples_for_child_meshes() const { std::vector> vec_t_child(m_incident_face_datas.size()); + /* for (long i = 0; i < long(m_incident_face_datas.size()); ++i) { vec_t_child[i] = MultiMeshManager::map_edge_tuple_to_all_children( m_mesh, @@ -389,11 +390,14 @@ TriMesh::TriMeshOperationExecutor::prepare_operating_tuples_for_child_meshes() c } } } + */ return vec_t_child; } Tuple TriMesh::TriMeshOperationExecutor::split_edge() { + return split_edge_single_mesh(); + /* if (!m_mesh.multi_mesh_manager.is_parent_mesh()) { return split_edge_single_mesh(); } else { @@ -482,6 +486,7 @@ Tuple TriMesh::TriMeshOperationExecutor::split_edge() } return ret_tuple; } +*/ } Tuple TriMesh::TriMeshOperationExecutor::split_edge_single_mesh() @@ -524,6 +529,7 @@ Tuple TriMesh::TriMeshOperationExecutor::split_edge_single_mesh() void TriMesh::TriMeshOperationExecutor::update_hash_in_map(TriMesh& child_mesh) { + /* long child_id = child_mesh.multi_mesh_manager.child_id(); auto child_hash_accessor = child_mesh.get_cell_hash_accessor(); @@ -559,10 +565,13 @@ void TriMesh::TriMeshOperationExecutor::update_hash_in_map(TriMesh& child_mesh) t_parent_new); } } + */ } Tuple TriMesh::TriMeshOperationExecutor::collapse_edge() { + return collapse_edge_single_mesh(); + /* if (!m_mesh.multi_mesh_manager.is_parent_mesh()) { return collapse_edge_single_mesh(); } else { @@ -597,6 +606,7 @@ Tuple TriMesh::TriMeshOperationExecutor::collapse_edge() return ret_tuple; } + */ } diff --git a/src/wmtk/Tuple.hpp b/src/wmtk/Tuple.hpp index ca5e2aded0..0837f1cf05 100644 --- a/src/wmtk/Tuple.hpp +++ b/src/wmtk/Tuple.hpp @@ -10,7 +10,7 @@ class PointMesh; class EdgeMesh; class TriMesh; class TetMesh; -namespace autogen::utils { +namespace utils { class TupleInspector; } namespace operations { @@ -42,7 +42,7 @@ class Tuple friend class operations::Operation; friend class MultiMeshManager; friend class utils::TupleCellLessThan; - friend class autogen::utils::TupleInspector; + friend class utils::TupleInspector; // friend long Mesh::id(const Tuple& tuple, const PrimitiveType& type) const; // friend Mesh::is_ccw(const Tuple& tuple) const; // friend Mesh::switch_tuple(const Tuple& tuple, const PrimitiveType& type) const; diff --git a/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp b/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp index 8e27b70965..6ad8ae0262 100644 --- a/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp +++ b/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp @@ -1,4 +1,5 @@ #include "find_local_switch_sequence.hpp" +#include "local_switch_tuple.hpp" namespace wmtk::multimesh::utils { @@ -14,12 +15,12 @@ std::vector find_local_switch_sequence_trimesh( Tuple cur_tuple = source; std::vector switches; auto try_and_record = [&](PrimitiveType pt) -> bool { - cur_tuple = local_switch_tuple(cur_tuple, pt); + cur_tuple = local_switch_tuple(PrimitiveType::Face, cur_tuple, pt); switches.emplace_back(pt); return cur_tuple == target; }; for (long j = 0; j < 3; ++j) { - for (PrimitiveType pt : {PrimtiiveType::Vertex, PrimitiveType::Edge}) { + for (PrimitiveType pt : {PrimitiveType::Vertex, PrimitiveType::Edge}) { if (try_and_record(pt)) { return switches; } @@ -32,8 +33,8 @@ std::vector find_local_switch_sequence_edgemesh( const Tuple& source, const Tuple& target) { - if(source != target) { - return std::vector{PrimitiveType::switch_vertex}; + if (source != target) { + return std::vector{PrimitiveType::Vertex}; } else { return std::vector{}; } diff --git a/src/wmtk/multimesh/utils/local_switch_tuple.cpp b/src/wmtk/multimesh/utils/local_switch_tuple.cpp index 4d510af0df..93ca87b6a7 100644 --- a/src/wmtk/multimesh/utils/local_switch_tuple.cpp +++ b/src/wmtk/multimesh/utils/local_switch_tuple.cpp @@ -8,19 +8,22 @@ namespace wmtk::multimesh::utils { Tuple local_switch_tuple(const Tuple& source, PrimitiveType primitive_type) { switch (primitive_type) { - case PrimitiveType::Face: return autogen::tri_mesh::local_switch_tuple(source); - case PrimitiveType::Tetrahedron: return autogen::tet_mesh::local_switch_tuple(source); + case PrimitiveType::Face: return autogen::tri_mesh::local_switch_tuple(source, primitive_type); + case PrimitiveType::Tetrahedron: return autogen::tet_mesh::local_switch_tuple(source, primitive_type); + case PrimitiveType::Vertex: + case PrimitiveType::Edge: default: return Tuple(); } +} - Tuple local_switch_tuples( - PrimitiveType mesh_primitive_type, - const Tuple& tuple, - const std::initializer_list& op_sequence) const - { - return local_switch_tuples>( - mesh_primitive_type, - tuple, - op_sequence); - } +Tuple local_switch_tuples( + PrimitiveType mesh_primitive_type, + const Tuple& tuple, + const std::initializer_list& op_sequence) +{ + return local_switch_tuples>( + mesh_primitive_type, + tuple, + op_sequence); } +} // namespace wmtk::multimesh::utils diff --git a/src/wmtk/multimesh/utils/local_switch_tuple.hpp b/src/wmtk/multimesh/utils/local_switch_tuple.hpp index 2f50265fda..f0baf93649 100644 --- a/src/wmtk/multimesh/utils/local_switch_tuple.hpp +++ b/src/wmtk/multimesh/utils/local_switch_tuple.hpp @@ -13,7 +13,7 @@ Tuple local_switch_tuple( PrimitiveType primitive_type); -// Performs a sequence of switch_tuple operations in the order specified in op_sequence. +// Performs a sequence of switch_tuple operations in the order specified in sequence. // in debug mode this will assert a failure, in release this will return a null tuple #if defined(__cpp_concepts) template @@ -23,14 +23,18 @@ template Tuple local_switch_tuples( PrimitiveType mesh_primitive_type, const Tuple& tuple, - const ContainerType& op_sequence) const; + const ContainerType& sequence) ; // annoying initializer list prototype to catch switch_tuples(t, {PV,PE}) Tuple local_switch_tuples( PrimitiveType mesh_primitive_type, const Tuple& tuple, - const std::initializer_list& op_sequence) const; + const std::initializer_list& sequence) ; + + + +// IMPLEMENTATION of above declaration #if defined(__cpp_concepts) template #else @@ -39,7 +43,7 @@ template Tuple local_switch_tuples( PrimitiveType mesh_primitive_type, const Tuple& tuple, - const std::initializer_list& op_sequence) const + const std::initializer_list& sequence) { static_assert(std::is_same_v); Tuple r = tuple; diff --git a/src/wmtk/multimesh/utils/transport_tuple.cpp b/src/wmtk/multimesh/utils/transport_tuple.cpp index 1458f9009f..358d99564f 100644 --- a/src/wmtk/multimesh/utils/transport_tuple.cpp +++ b/src/wmtk/multimesh/utils/transport_tuple.cpp @@ -1,5 +1,6 @@ #include "transport_tuple.hpp" #include "find_local_switch_sequence.hpp" +#include "local_switch_tuple.hpp" namespace wmtk::multimesh::utils { diff --git a/src/wmtk/multimesh/utils/tuple_map_attribute_io.cpp b/src/wmtk/multimesh/utils/tuple_map_attribute_io.cpp index b9b8ed375c..5cf22880d7 100644 --- a/src/wmtk/multimesh/utils/tuple_map_attribute_io.cpp +++ b/src/wmtk/multimesh/utils/tuple_map_attribute_io.cpp @@ -1,63 +1,64 @@ #include "tuple_map_attribute_io.hpp" -#include "Types.hpp" +#include +#include +#include namespace wmtk::multimesh::utils { +namespace { +Vector tuple_to_vector5(const Tuple& t) { - namespace { - Vector tuple_to_vector5(const Tuple& t) - { - Vector v; - v(0) = t.m_local_vid; - v(1) = t.m_local_eid; - v(2) = t.m_local_fid; - v(3) = t.m_global_cid; - v(4) = t.m_hash; - return v; - } - - template - Tuple vector5_to_tuple(const Eigen::MatrixBase& v) - { - Tuple(v(0), v(1), v(2), v(3), v(4)), - } - } // namespace - - void write_tuple_map_attribute( - Accessor & map_accessor, - const Tuple& source_tuple, - const Tuple& target_tuple) - { - auto map = map_accessor.vector_attribute(source_tuple); - - map.head<5>() = tuple_to_vector5(source_tuple); - map.tail<5>() = tuple_to_vector5(target_tuple); - } - - void write_tuple_map_attribute_slow( - Mesh & source_mesh, - MeshAttributeHandle map_handle, - const Tuple& source_tuple, - const Tuple& target_tuple) - { - auto map_accessor = source_mesh.create_accessor(map_handle); - write_tuple_map_attribute(map_handle, source_tuple, target_tuple); - } - - std::tuple read_tuple_map_attribute( - const ConstAccessor& accessor, - const Tuple& source_tuple) - { - auto map = map_accessor.const_vector_attribute(source_tuple); - - return std::make_tuple(vector5_to_tuple(map.head<5>()), vector5_to_tuple(map.tail<5>())); - } - - - std::tuple read_tuple_map_attribute_slow( - const Mesh& source_mesh, - MeshAttributeHandle map_handle, - const Tuple& source_tuple) - { - auto acc = source_mesh.get_const_accessor(map_handle); - read_tuple_map_attribute_slow(acc, source_tuple); - } -} // namespace wmtk::::multimesh:::utils + Vector v; + v(0) = wmtk::utils::TupleInspector::local_vid(t); + v(1) = wmtk::utils::TupleInspector::local_eid(t); + v(2) = wmtk::utils::TupleInspector::local_fid(t); + v(3) = wmtk::utils::TupleInspector::global_cid(t); + v(4) = wmtk::utils::TupleInspector::hash(t); + return v; +} + +template +Tuple vector5_to_tuple(const Eigen::MatrixBase& v) +{ + return Tuple(v(0), v(1), v(2), v(3), v(4)); +} +} // namespace + +void write_tuple_map_attribute( + Accessor& map_accessor, + const Tuple& source_tuple, + const Tuple& target_tuple) +{ + auto map = map_accessor.vector_attribute(source_tuple); + + map.head<5>() = tuple_to_vector5(source_tuple); + map.tail<5>() = tuple_to_vector5(target_tuple); +} + +void write_tuple_map_attribute_slow( + Mesh& source_mesh, + MeshAttributeHandle map_handle, + const Tuple& source_tuple, + const Tuple& target_tuple) +{ + auto map_accessor = source_mesh.create_accessor(map_handle); + write_tuple_map_attribute(map_accessor, source_tuple, target_tuple); +} + +std::tuple read_tuple_map_attribute( + const ConstAccessor& map_accessor, + const Tuple& source_tuple) +{ + auto map = map_accessor.const_vector_attribute(source_tuple); + + return std::make_tuple(vector5_to_tuple(map.head<5>()), vector5_to_tuple(map.tail<5>())); +} + + +std::tuple read_tuple_map_attribute_slow( + const Mesh& source_mesh, + MeshAttributeHandle map_handle, + const Tuple& source_tuple) +{ + auto acc = source_mesh.create_const_accessor(map_handle); + return read_tuple_map_attribute(acc, source_tuple); +} +} // namespace wmtk::multimesh::utils diff --git a/src/wmtk/simplex/top_level_cofaces.cpp b/src/wmtk/simplex/top_level_cofaces.cpp index bada87411f..ba12b02e35 100644 --- a/src/wmtk/simplex/top_level_cofaces.cpp +++ b/src/wmtk/simplex/top_level_cofaces.cpp @@ -19,7 +19,7 @@ std::vector top_level_cofaces_tuples_vertex(const TriMesh& mesh, const Tu { std::vector collection; - std::set touched_cells; + std::set touched_cells; std::queue q; q.push(t); while (!q.empty()) { @@ -63,7 +63,7 @@ std::vector top_level_cofaces_tuples_face(const TriMesh& mesh, const Tupl std::vector top_level_cofaces_tuples_vertex(const TetMesh& mesh, const Tuple& t) { std::vector collection; - std::set touched_cells; + std::set touched_cells; std::queue q; q.push(t); while (!q.empty()) { @@ -99,7 +99,7 @@ std::vector top_level_cofaces_tuples_vertex(const TetMesh& mesh, const Tu std::vector top_level_cofaces_tuples_edge(const TetMesh& mesh, const Tuple& t) { std::vector collection; - std::set touched_cells; + std::set touched_cells; std::queue q; q.push(t); while (!q.empty()) { diff --git a/src/wmtk/utils/CMakeLists.txt b/src/wmtk/utils/CMakeLists.txt index 3b06117a0c..5242c768ce 100644 --- a/src/wmtk/utils/CMakeLists.txt +++ b/src/wmtk/utils/CMakeLists.txt @@ -11,5 +11,6 @@ set(SRC_FILES Rational.hpp mesh_utils.hpp mesh_utils.cpp + TupleInspector.hpp ) target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) diff --git a/src/wmtk/utils/TupleInspector.hpp b/src/wmtk/utils/TupleInspector.hpp index 24fdd5cb7a..de9e0f1412 100644 --- a/src/wmtk/utils/TupleInspector.hpp +++ b/src/wmtk/utils/TupleInspector.hpp @@ -2,7 +2,7 @@ #include -namespace wmtk::autogen::utils { +namespace wmtk::utils { // NOTE: this is just for helping with autogen accessing tuple intenrals. DO NOT USE ELSEWHERE struct TupleInspector { From 46b98af5c22a51fcbd4a8eb79bd14ecdd35fd895 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Tue, 3 Oct 2023 12:41:04 -0400 Subject: [PATCH 10/25] fixing reorder warning in simplexcollectoin --- src/wmtk/simplex/SimplexCollection.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wmtk/simplex/SimplexCollection.hpp b/src/wmtk/simplex/SimplexCollection.hpp index f98073a2eb..469ce1e739 100644 --- a/src/wmtk/simplex/SimplexCollection.hpp +++ b/src/wmtk/simplex/SimplexCollection.hpp @@ -12,9 +12,9 @@ class SimplexCollection public: SimplexCollection(const Mesh& mesh, std::vector&& simplices = {}) : m_mesh{mesh} + , m_simplices(std::move(simplices)) , m_simplex_is_less(mesh) , m_simplex_is_equal(mesh) - , m_simplices(std::move(simplices)) {} /** @@ -65,12 +65,12 @@ class SimplexCollection const SimplexCollection& collection_a, const SimplexCollection& collection_b); -protected: - internal::SimplexLessFunctor m_simplex_is_less; - internal::SimplexEqualFunctor m_simplex_is_equal; protected: const Mesh& m_mesh; std::vector m_simplices; +protected: + internal::SimplexLessFunctor m_simplex_is_less; + internal::SimplexEqualFunctor m_simplex_is_equal; }; } // namespace wmtk::simplex From c218a3654dedeeacedd1387c01331c4a06922c62 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Tue, 3 Oct 2023 15:33:35 -0400 Subject: [PATCH 11/25] build of multimesh works, need to unit test the multimesh utils --- src/wmtk/MultiMeshManager.cpp | 172 +++++++++--------- src/wmtk/MultiMeshManager.hpp | 18 +- .../utils/find_local_switch_sequence.cpp | 2 + .../multimesh/utils/local_switch_tuple.cpp | 10 +- .../multimesh/utils/local_switch_tuple.hpp | 9 +- 5 files changed, 102 insertions(+), 109 deletions(-) diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 9ea68e74d4..0b224878c2 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -1,8 +1,10 @@ #include "MultiMeshManager.hpp" +#include #include #include "Mesh.hpp" #include "SimplicialComplex.hpp" #include "multimesh/utils/transport_tuple.hpp" +#include "multimesh/utils/tuple_map_attribute_io.hpp" namespace wmtk { namespace {} // namespace @@ -19,18 +21,21 @@ Tuple MultiMeshManager::map_tuple_between_meshes( std::min(source_mesh_primitive_type, target_mesh_primitive_type); auto [source_mesh_base_tuple, target_mesh_base_tuple] = - read_tuple_map_attribute(map_accessor, source_mesh, source_tuple); + multimesh::utils::read_tuple_map_attribute(map_accessor, source_tuple); if (source_mesh_base_tuple.is_null() || target_mesh_base_tuple.is_null()) { return Tuple(); // return null tuple } - multimesh::utils::transport_tuple( + // we want to repeat switches from source_base_tuple -> source_tuple to + // target_base _tuple -> return value + // + return multimesh::utils::transport_tuple( source_mesh_base_tuple, source_tuple, source_mesh_primitive_type, - target_tuple, - primitive_type); + target_mesh_base_tuple, + target_mesh_primitive_type); } @@ -44,7 +49,7 @@ MultiMeshManager& MultiMeshManager::operator=(MultiMeshManager&& o) = default; bool MultiMeshManager::is_root() const { - return m_my_mesh == nullptr; + return m_parent == nullptr; } long MultiMeshManager::child_id() const @@ -57,7 +62,7 @@ std::vector MultiMeshManager::absolute_id() const if (is_root()) { return {}; } else { - auto id = m_my_mesh->absolute_id(); + auto id = m_parent->m_multi_mesh_manager.absolute_id(); id.emplace_back(m_child_id); return id; } @@ -72,40 +77,49 @@ void MultiMeshManager::register_child_mesh( assert(&my_mesh.m_multi_mesh_manager == this); assert(bool(child_mesh_ptr)); - PrimitiveType child_primitive_type = child_mesh->top_simplex_type(); + Mesh& child_mesh = *child_mesh_ptr; + + PrimitiveType child_primitive_type = child_mesh.top_simplex_type(); long new_child_id = long(m_children.size()); - auto map_to_parent_handle = - child_mesh->register_attribute("map_to_parent", child_primitive_type, 10); + auto child_to_parent_handle = + child_mesh.register_attribute("map_to_parent", child_primitive_type, 10); - auto map_to_child_handle = my_mesh.register_attribute( + // TODO: make sure that this attribute doesnt already exist + auto parent_to_child_handle = my_mesh.register_attribute( fmt::format("map_to_child_{}", new_child_id), child_primitive_type, 10); + + + auto child_to_parent_accessor = child_mesh.create_accessor(child_to_parent_handle); + auto parent_to_child_accessor = my_mesh.create_accessor(parent_to_child_handle); + + // default initialize the parent to child map which can have entries missing for (long id = 0; id < my_mesh.capacity(child_primitive_type); ++id) { - write_tuple_map_attribute( - map_to_child_handle, - my_mesh, - my_mesh.tuple_from_id(child_primitive_type, id), - Tuple()); + multimesh::utils::write_tuple_map_attribute(parent_to_child_accessor, Tuple(), Tuple()); } // register maps for (const auto& [my_tuple, child_tuple] : child_mesh_simplex_map) { - // const auto& [my_tuple, child_tuple] = tuple_pair; - - write_tuple_map_attribute(map_to_parent_handle, *child_mesh, my_tuple, child_tuple); - write_tuple_map_attribute(map_to_child_handle, my_mesh, child__tuple, my_tuple); + multimesh::utils::write_tuple_map_attribute( + child_to_parent_accessor, + my_tuple, + child_tuple); + multimesh::utils::write_tuple_map_attribute( + parent_to_child_accessor, + child_tuple, + my_tuple); } - MultiMeshManager& child_manager = child_mesh->multi_mesh_manager; + MultiMeshManager& child_manager = child_mesh.m_multi_mesh_manager; // update on child_mesh - child_manager.map_to_parent_handle = map_to_parent_handle; + child_manager.map_to_parent_handle = child_to_parent_handle; child_manager.m_child_id = new_child_id; - child_managerm_my_mesh = this; + child_manager.m_parent = &my_mesh; // update myself - m_children.emplace_back(child_mesh, map_to_child_handle); + m_children.emplace_back(ChildData{child_mesh_ptr, parent_to_child_handle}); } /* @@ -144,7 +158,7 @@ std::vector MultiMeshManager::map_to_tuples( { assert(&my_mesh.m_multi_mesh_manager == this); // TODO: construct relative positions - std::vector equivalent_tuples = simplex::top_level_cofaces(my_simplex); + std::vector equivalent_tuples = simplex::top_level_cofaces_tuples(my_mesh, my_simplex); // TODO: construct visitor class that maps up and down // MultiMeshMapVisitor visitor(my_mesh, other_mesh); // TODO: visitor runs along meshes traversing the path @@ -157,10 +171,12 @@ std::vector MultiMeshManager::map_to_tuples( Simplex MultiMeshManager::map_to_parent(const Mesh& my_mesh, const Simplex& my_simplex) const { - return Simplex(my_simplex.primitive_type(), map_to_parent_tuple(my_mesh, my_simplex)); + return Simplex( + my_simplex.primitive_type(), + map_tuple_to_parent_tuple(my_mesh, my_simplex.tuple())); } -Tuple MultiMeshManager::map_tuple_to_parent(const Mesh& my_mesh, const Tuple& my_tuple) const +Tuple MultiMeshManager::map_tuple_to_parent_tuple(const Mesh& my_mesh, const Tuple& my_tuple) const { assert(&my_mesh.m_multi_mesh_manager == this); assert(!is_root()); @@ -170,8 +186,8 @@ Tuple MultiMeshManager::map_tuple_to_parent(const Mesh& my_mesh, const Tuple& my const auto& map_handle = map_to_parent_handle; // assert(!map_handle.is_null()); - auto map_accessor = my_mesh.get_accessor(map_handle); - return map_tuple_between_meshes(my_mesh, parent_mesh, map_accessor, my_simplex); + auto map_accessor = my_mesh.create_accessor(map_handle); + return map_tuple_between_meshes(my_mesh, parent_mesh, map_accessor, my_tuple); } std::vector MultiMeshManager::map_to_child_tuples( const Mesh& my_mesh, @@ -183,12 +199,18 @@ std::vector MultiMeshManager::map_to_child_tuples( const Mesh& child_mesh = *child_data.mesh; const auto map_handle = child_data.map_handle; // we will rewrite these tuples inline with the mapped ones - std::vector tuples = simplex::top_level_cofaces(my_simplex); + std::vector tuples = simplex::top_level_cofaces_tuples(my_mesh, my_simplex); - auto map_accessor = my_mesh.get_accessor(map_handle); + auto map_accessor = my_mesh.create_accessor(map_handle); for (Tuple& tuple : tuples) { tuple = map_tuple_between_meshes(my_mesh, child_mesh, map_accessor, tuple); } + tuples.erase( + std::remove_if( + tuples.begin(), + tuples.end(), + [](const Tuple& t) -> bool { return t.is_null(); }), + tuples.end()); return tuples; } @@ -210,74 +232,43 @@ std::vector MultiMeshManager::map_to_child_tuples( return map_to_child_tuples(my_mesh, m_children.at(child_id), my_simplex); } -std::vector MultiMeshManager::map_to_child_tuples( +std::vector MultiMeshManager::map_to_child( const Mesh& my_mesh, const Mesh& child_mesh, const Simplex& my_simplex) const { auto tuples = map_to_child_tuples(my_mesh, child_mesh, my_simplex); - return tuple_vector_to_homogeneous_simplex_vector(tuples, my_simplex.primitive_type()); -} - - -std::vector MultiMeshManager::find_all_simplices_in_child_mesh( - const Mesh& my_mesh, - const ChildData& child_data, - const Simplex& simplex_parent) -{ - assert(&my_mesh.m_multi_mesh_manager == this); - const Mesh& child_mesh = *child_data.mesh; - PrimitiveType simplex_primitive_typ = simplex.primitive_type(); - PrimitiveType childmesh_primitive_type = child_mesh.top_simplex_type(); - - if (simplex_primitive_type > childmesh_primitive_type) { - // Can't find higher-dimensional simplex in child_mesh - return std::vector(); - } - - - const auto& map_to_child_handle = child_data.map_handle; - // Find all dim(child_mesh) simplex in open_star(simplex_parent)) in my_mesh - auto top_simplices_in_open_star = - SimplicialComplex::open_star(my_mesh, simplex).get_simplices(childmesh_primitive_type); - - // map tuples to child_mesh and collect all distinct simplices - SimplicialComplex ret_sc(child_mesh); - for (auto s : top_simplices_in_open_star) { - const Tuple child_tuple = - map_tuple_between_meshes(my_mesh, *child_mesh_ptr, map_to_child_handle, s.tuple()); - if (!child_tuple.is_null()) { - ret_sc.add_simplex(Simplex(simplex_primitive_type, child_tuple)); - } - } - - return ret_sc.get_simplex_vector(); + return simplex::utils::tuple_vector_to_homogeneous_simplex_vector( + tuples, + my_simplex.primitive_type()); } -bool MultiMeshManager::is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const -{ - assert(&my_mesh.m_multi_mesh_manager == this); - // TODO: implement this - return true; -} - -std::vector MultiMeshManager::map_edge_tuple_to_all_children( - const Mesh& my_mesh, - const Tuple& edge_tuple) -{ - assert(&my_mesh.m_multi_mesh_manager == this); - std::vector ret; - for (const auto& child_data : m_children) { - const Mesh& child_mesh = *child_data.mesh; - const auto map_to_child_handle = child_data.map_handle; - Tuple child_tuple = - map_tuple_between_meshes(my_mesh, child_mesh, map_to_child_handle, edge_tuple); - ret.push_back(child_tuple); - } - return ret; -} +// bool MultiMeshManager::is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const +//{ +// assert(&my_mesh.m_multi_mesh_manager == this); +// // TODO: implement this +// +// return true; +//} +// +// std::vector MultiMeshManager::map_edge_tuple_to_all_children( +// const Mesh& my_mesh, +// const Tuple& edge_tuple) +//{ +// assert(&my_mesh.m_multi_mesh_manager == this); +// std::vector ret; +// for (const auto& child_data : m_children) { +// const Mesh& child_mesh = *child_data.mesh; +// const auto map_to_child_handle = child_data.map_handle; +// Tuple child_tuple = +// map_tuple_between_meshes(my_mesh, child_mesh, map_to_child_handle, edge_tuple); +// ret.push_back(child_tuple); +// } +// return ret; +//} +/* bool MultiMeshManager::is_map_valid(const Mesh& my_mesh) const { assert(&my_mesh.m_multi_mesh_manager == this); @@ -328,7 +319,6 @@ bool MultiMeshManager::is_child_map_valid(const Mesh& my_mesh, const ChildData& } } - /* // 4. test switch_top_simplex operation // for 4, current code support only mapping between triangle meshes if (map_type == PrimitiveType::Face && my_mesh.top_simplex_type() == PrimitiveType::Face) { @@ -360,8 +350,8 @@ bool MultiMeshManager::is_child_map_valid(const Mesh& my_mesh, const ChildData& // TODO: implement other cases continue; } - */ } return true; } +*/ } // namespace wmtk diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index 1cf7b1030a..d439ba2d26 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -60,7 +60,7 @@ class MultiMeshManager const; - Tuple map_to_parent(const Mesh& my_mesh, const Simplex& my_simplex) const; + Simplex map_to_parent(const Mesh& my_mesh, const Simplex& my_simplex) const; Tuple map_to_parent_tuple(const Mesh& my_mesh, const Simplex& my_simplex) const; // generic mapping function that maps a tuple from "this" mesh to one of its children @@ -106,9 +106,9 @@ class MultiMeshManager std::vector map_to_tuples(const Mesh& my_mesh, const Mesh& other_mesh, const Simplex& my_simplex) const; - // generic mapping function that maps a tuple from "this" mesh to its parent - Tuple map_tuple_to_parent(const Mesh& my_mesh, const Mesh& parent_mesh, const Tuple& my_tuple) - const; + // generic mapping function that maps a tuple from "this" mesh to its parent. We don't actually + // need the simplex parent of the tuple being mapped up so we can throw away the simplex-nes + Tuple map_tuple_to_parent_tuple(const Mesh& my_mesh, const Tuple& my_tuple) const; // wrapper for implementing converting tuple to a child using the internal map data @@ -122,12 +122,12 @@ class MultiMeshManager map_to_child_tuples(const Mesh& my_mesh, long child_id, const Simplex& simplex) const; - // helper function to check if this mesh is a valid child_mesh of my_mesh - // i.e. the connectivity of this mesh is a subset of this in my_mesh - bool is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const; + //// helper function to check if this mesh is a valid child_mesh of my_mesh + //// i.e. the connectivity of this mesh is a subset of this in my_mesh + // bool is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const; - // checks that the map is consistent - bool is_child_map_valid(const Mesh& my_mesh, const ChildData& child) const; + //// checks that the map is consistent + // bool is_child_map_valid(const Mesh& my_mesh, const ChildData& child) const; static Tuple map_tuple_between_meshes( diff --git a/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp b/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp index 6ad8ae0262..393c50dc9a 100644 --- a/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp +++ b/src/wmtk/multimesh/utils/find_local_switch_sequence.cpp @@ -51,6 +51,8 @@ find_local_switch_sequence(const Tuple& source, const Tuple& target, PrimitiveTy switch (primitive_type) { case PrimitiveType::Face: return find_local_switch_sequence_trimesh(source, target); case PrimitiveType::Edge: return find_local_switch_sequence_edgemesh(source, target); + case PrimitiveType::Vertex: return {}; + case PrimitiveType::Tetrahedron: default: return {}; } } diff --git a/src/wmtk/multimesh/utils/local_switch_tuple.cpp b/src/wmtk/multimesh/utils/local_switch_tuple.cpp index 93ca87b6a7..757cf0ac19 100644 --- a/src/wmtk/multimesh/utils/local_switch_tuple.cpp +++ b/src/wmtk/multimesh/utils/local_switch_tuple.cpp @@ -5,11 +5,15 @@ namespace wmtk::multimesh::utils { -Tuple local_switch_tuple(const Tuple& source, PrimitiveType primitive_type) +Tuple local_switch_tuple( + PrimitiveType mesh_primitive_type, + const Tuple& source, + PrimitiveType primitive_type) { - switch (primitive_type) { + switch (mesh_primitive_type) { case PrimitiveType::Face: return autogen::tri_mesh::local_switch_tuple(source, primitive_type); - case PrimitiveType::Tetrahedron: return autogen::tet_mesh::local_switch_tuple(source, primitive_type); + case PrimitiveType::Tetrahedron: + return autogen::tet_mesh::local_switch_tuple(source, primitive_type); case PrimitiveType::Vertex: case PrimitiveType::Edge: default: return Tuple(); diff --git a/src/wmtk/multimesh/utils/local_switch_tuple.hpp b/src/wmtk/multimesh/utils/local_switch_tuple.hpp index f0baf93649..02fc3e0ea7 100644 --- a/src/wmtk/multimesh/utils/local_switch_tuple.hpp +++ b/src/wmtk/multimesh/utils/local_switch_tuple.hpp @@ -23,15 +23,12 @@ template Tuple local_switch_tuples( PrimitiveType mesh_primitive_type, const Tuple& tuple, - const ContainerType& sequence) ; + const ContainerType& sequence); // annoying initializer list prototype to catch switch_tuples(t, {PV,PE}) Tuple local_switch_tuples( PrimitiveType mesh_primitive_type, const Tuple& tuple, - const std::initializer_list& sequence) ; - - - + const std::initializer_list& sequence); // IMPLEMENTATION of above declaration @@ -43,7 +40,7 @@ template Tuple local_switch_tuples( PrimitiveType mesh_primitive_type, const Tuple& tuple, - const std::initializer_list& sequence) + const ContainerType& sequence) { static_assert(std::is_same_v); Tuple r = tuple; From a5c211c42c1d05261c8b4682d209939636e161c8 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Wed, 4 Oct 2023 00:15:47 -0400 Subject: [PATCH 12/25] generating interface for multimesh in Mesh --- src/wmtk/Mesh.cpp | 40 +++++++++++++++++++++++++++++++++++ src/wmtk/Mesh.hpp | 25 ++++++++++++++++++++++ src/wmtk/MultiMeshManager.cpp | 3 ++- src/wmtk/MultiMeshManager.hpp | 14 ++++++------ 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/src/wmtk/Mesh.cpp b/src/wmtk/Mesh.cpp index c8e1ff56d0..ff5aa1a95d 100644 --- a/src/wmtk/Mesh.cpp +++ b/src/wmtk/Mesh.cpp @@ -270,4 +270,44 @@ Tuple Mesh::switch_tuples_unsafe( return switch_tuples_unsafe>(tuple, op_sequence); } + +std::vector Mesh::absolute_multi_mesh_id() const +{ + m_multi_mesh_manager.absolute_id(); +} +void Mesh::register_child_mesh( + const std::shared_ptr& child_mesh, + const std::vector>& map_tuples) +{ + m_multi_mesh_manager.register_child_mesh(child_mesh, map_tuples); +} + + +std::vector Mesh::map(const Mesh& other_mesh, const Simplex& my_simplex) const +{ + return m_multi_mesh_manager.map(*this, other_mesh, my_simplex); +} +Simplex Mesh::map_to_parent(const Simplex& my_simplex) const +{ + return m_multi_mesh_manager.map_to_parent(*this, my_simplex); +} +std::vector Mesh::map_to_child(const Mesh& child_mesh, const Simplex& my_simplex) const +{ + return m_multi_mesh_manager.map_to_child(*this, child_mesh, my_simplex); +} + +std::vector Mesh::map_tuples(const Mesh& other_mesh, const Simplex& my_simplex) const +{ + return m_multi_mesh_manager.map_tuples(*this, other_mesh, my_simplex); +} +Tuple Mesh::map_to_parent_tuple(const Simplex& my_simplex) const +{ + return m_multi_mesh_manager.map_to_parent_tuple(*this, my_simplex); +} +std::vector Mesh::map_to_child_tuples(const Mesh& child_mesh, const Simplex& my_simplex) + const +{ + return m_multi_mesh_manager.map_to_child_tuples(*this, child_mesh, my_simplex); +} + } // namespace wmtk diff --git a/src/wmtk/Mesh.hpp b/src/wmtk/Mesh.hpp index d5d90ca3ee..978287c119 100644 --- a/src/wmtk/Mesh.hpp +++ b/src/wmtk/Mesh.hpp @@ -312,6 +312,31 @@ class Mesh : public std::enable_shared_from_this bool simplex_is_less(const Simplex& s0, const Simplex& s1) const; + + //============================ + // MultiMesh interface + //============================ + std::vector absolute_multi_mesh_id() const; + void register_child_mesh( + const std::shared_ptr& child_mesh, + const std::vector>& map_tuples); + + // a generic map interface between pairs of mesh in a single multi-mesh structure + std::vector map(const Mesh& other_mesh, const Simplex& my_simplex) const; + // map to just the parent + Simplex map_to_parent(const Simplex& my_simplex) const; + // map to just a child + std::vector map_to_child(const Mesh& child_mesh, const Simplex& my_simplex) const; + + // a generic map interface between pairs of mesh in a single multi-mesh structure but returns + // tuples Each tuple partial encodes a Simplex, whose dimension is the same as my_simplex + std::vector map_tuples(const Mesh& other_mesh, const Simplex& my_simplex) const; + // map to just the parent + Tuple map_to_parent_tuple(const Simplex& my_simplex) const; + // map to just a child + std::vector map_to_child_tuples(const Mesh& child_mesh, const Simplex& my_simplex) const; + + protected: /** * @brief return the global id of the Tuple of the given dimension diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 0b224878c2..4074817284 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -151,11 +151,12 @@ MultiMeshManager::map(const Mesh& my_mesh, const Mesh& other_mesh, const Simplex ret_tups, my_simplex.primitive_type()); } -std::vector MultiMeshManager::map_to_tuples( +std::vector MultiMeshManager::map_tuples( const Mesh& my_mesh, const Mesh& other_mesh, const Simplex& my_simplex) const { + throw "Not implemented"; assert(&my_mesh.m_multi_mesh_manager == this); // TODO: construct relative positions std::vector equivalent_tuples = simplex::top_level_cofaces_tuples(my_mesh, my_simplex); diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index d439ba2d26..0350aa064d 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -37,7 +37,7 @@ class MultiMeshManager const std::vector>& child_mesh_simplex_map); - bool are_maps_valid(const Mesh& my_mesh) const; + // bool are_maps_valid(const Mesh& my_mesh) const; //=========== //=========== @@ -58,20 +58,23 @@ class MultiMeshManager // generic mapping function that maps a tuple from "this" mesh to the other mesh std::vector map(const Mesh& my_mesh, const Mesh& other_mesh, const Simplex& my_simplex) const; + // generic mapping function that maps a tuple from "this" mesh to the other mesh + std::vector + map_tuples(const Mesh& my_mesh, const Mesh& other_mesh, const Simplex& my_simplex) const; Simplex map_to_parent(const Mesh& my_mesh, const Simplex& my_simplex) const; Tuple map_to_parent_tuple(const Mesh& my_mesh, const Simplex& my_simplex) const; + // generic mapping function that maps a tuple from "this" mesh to one of its children + std::vector + map_to_child(const Mesh& my_mesh, const Mesh& child_mesh, const Simplex& my_simplex) const; std::vector map_to_child_tuples( const Mesh& my_mesh, const Mesh& child_mesh, const Simplex& my_simplex) const; - std::vector - map_to_child(const Mesh& my_mesh, const Mesh& child_mesh, const Simplex& my_simplex) const; - // Utility function to map a edge tuple to all its children, used in operations std::vector map_edge_tuple_to_all_children(const Mesh& my_mesh, const Simplex& tuple) @@ -102,9 +105,6 @@ class MultiMeshManager //=========== // Tuple maps //=========== - // generic mapping function that maps a tuple from "this" mesh to the other mesh - std::vector - map_to_tuples(const Mesh& my_mesh, const Mesh& other_mesh, const Simplex& my_simplex) const; // generic mapping function that maps a tuple from "this" mesh to its parent. We don't actually // need the simplex parent of the tuple being mapped up so we can throw away the simplex-nes From fcd749ac3e77dcddfed527026e77bd530c1175f6 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Wed, 4 Oct 2023 00:16:19 -0400 Subject: [PATCH 13/25] working on rejuvenating multimesh unit tests --- tests/CMakeLists.txt | 2 +- tests/test_multi_mesh.cpp | 138 ++++++++++++++++++++++++---------- tests/tools/DEBUG_TriMesh.hpp | 1 + 3 files changed, 100 insertions(+), 41 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c882a30aed..08a53809f1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,7 +22,7 @@ set(TEST_SOURCES test_accessor.cpp test_example_meshes.cpp test_3d_operations.cpp - #test_multi_mesh.cpp + test_multi_mesh.cpp tools/DEBUG_PointMesh.hpp tools/DEBUG_TriMesh.hpp tools/DEBUG_TriMesh.cpp diff --git a/tests/test_multi_mesh.cpp b/tests/test_multi_mesh.cpp index 922152f4d6..d84a67c779 100644 --- a/tests/test_multi_mesh.cpp +++ b/tests/test_multi_mesh.cpp @@ -16,27 +16,33 @@ constexpr PrimitiveType PV = PrimitiveType::Vertex; constexpr PrimitiveType PE = PrimitiveType::Edge; constexpr PrimitiveType PF = PrimitiveType::Face; -TEST_CASE("test_register_child_mesh","[multimesh][2D]") +TEST_CASE("test_register_child_mesh", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); std::shared_ptr child0_ptr = std::make_shared(single_triangle()); std::vector child0_map = {0}; std::shared_ptr child1_ptr = std::make_shared(one_ear()); - std::vector child1_map = {0,1}; + std::vector child1_map = {0, 1}; - MultiMeshManager::register_child_mesh(parent, child0_ptr, child0_map); - MultiMeshManager::register_child_mesh(parent, child1_ptr, child1_map); + parent.register_child_mesh(child0_ptr, child0_map); + parent.register_child_mesh(child1_ptr, child1_map); - auto p_mul_manager = parent.multi_mesh_manager; + const auto& p_mul_manager = parent.multi_mesh_manager(); REQUIRE(p_mul_manager.child_meshes.size() == 2); REQUIRE(p_mul_manager.child_meshes[0] == child0_ptr); REQUIRE(p_mul_manager.child_meshes[1] == child1_ptr); - auto [tuple1, tuple2] = MultiMeshManager::read_tuple_map_attribute(p_mul_manager.map_to_child_handles[0], parent, parent.tuple_from_id(PF,0)); - REQUIRE(tuple1 == parent.tuple_from_id(PF,0)); - REQUIRE(tuple2 == child0_ptr->tuple_from_id(PF,0)); - - auto [tuple3, tuple4] = MultiMeshManager::read_tuple_map_attribute(p_mul_manager.map_to_child_handles[0], parent, parent.tuple_from_id(PF,1)); + auto [tuple1, tuple2] = multimesh::utils::read_tuple_map_attribute_slow( + p_mul_manager.map_to_child_handles[0], + parent, + parent.tuple_from_id(PF, 0)); + REQUIRE(tuple1 == parent.tuple_from_id(PF, 0)); + REQUIRE(tuple2 == child0_ptr->tuple_from_id(PF, 0)); + + auto [tuple3, tuple4] = multimesh::utils::read_tuple_map_attribute_slow( + p_mul_manager.map_to_child_handles[0], + parent, + parent.tuple_from_id(PF, 1)); REQUIRE(!tuple3.is_null()); REQUIRE(tuple4.is_null()); @@ -46,55 +52,108 @@ TEST_CASE("test_register_child_mesh","[multimesh][2D]") REQUIRE(c2_mul_manager.is_parent_mesh() == false); REQUIRE(c2_mul_manager.child_id() == 1); - auto [tuple5, tuple6] = MultiMeshManager::read_tuple_map_attribute(c2_mul_manager.map_to_parent_handle, *child1_ptr, child1_ptr->tuple_from_id(PF,1)); + auto [tuple5, tuple6] = multimesh::utils::read_tuple_map_attribute_slow( + c2_mul_manager.map_to_parent_handle, + *child1_ptr, + child1_ptr->tuple_from_id(PF, 1)); - REQUIRE(tuple5 == child1_ptr->tuple_from_id(PF,1)); - REQUIRE(tuple6 == parent.tuple_from_id(PF,1)); + REQUIRE(tuple5 == child1_ptr->tuple_from_id(PF, 1)); + REQUIRE(tuple6 == parent.tuple_from_id(PF, 1)); REQUIRE(p_mul_manager.is_map_valid(parent) == true); } -TEST_CASE("test_multi_mesh_navigation","[multimesh][2D]") +TEST_CASE("test_multi_mesh_navigation", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); std::shared_ptr child0_ptr = std::make_shared(single_triangle()); std::vector child0_map = {0}; std::shared_ptr child1_ptr = std::make_shared(one_ear()); - std::vector child1_map = {0,1}; - std::shared_ptr child2_ptr = std::make_shared(two_neighbors_cut_on_edge01()); - std::vector child2_map = {0,1,2}; + std::vector child1_map = {0, 1}; + std::shared_ptr child2_ptr = + std::make_shared(two_neighbors_cut_on_edge01()); + std::vector child2_map = {0, 1, 2}; MultiMeshManager::register_child_mesh(parent, child0_ptr, child0_map); MultiMeshManager::register_child_mesh(parent, child1_ptr, child1_map); MultiMeshManager::register_child_mesh(parent, child2_ptr, child2_map); Tuple edge = parent.edge_tuple_between_v1_v2(1, 0, 0); - Tuple edge_child0 = MultiMeshManager::map_tuple_between_meshes(parent, *child0_ptr, parent.multi_mesh_manager.map_to_child_handles[0], edge); - Tuple edge_child1 = MultiMeshManager::map_tuple_between_meshes(parent, *child1_ptr, parent.multi_mesh_manager.map_to_child_handles[1], edge); - Tuple edge_child2 = MultiMeshManager::map_tuple_between_meshes(parent, *child2_ptr, parent.multi_mesh_manager.map_to_child_handles[2], edge); + Tuple edge_child0 = MultiMeshManager::map_tuple_between_meshes( + parent, + *child0_ptr, + parent.multi_mesh_manager.map_to_child_handles[0], + edge); + Tuple edge_child1 = MultiMeshManager::map_tuple_between_meshes( + parent, + *child1_ptr, + parent.multi_mesh_manager.map_to_child_handles[1], + edge); + Tuple edge_child2 = MultiMeshManager::map_tuple_between_meshes( + parent, + *child2_ptr, + parent.multi_mesh_manager.map_to_child_handles[2], + edge); CHECK(edge_child0 == child0_ptr->edge_tuple_between_v1_v2(1, 0, 0)); CHECK(edge_child1 == child1_ptr->edge_tuple_between_v1_v2(1, 0, 0)); CHECK(edge_child2 == child2_ptr->edge_tuple_between_v1_v2(1, 0, 0)); - CHECK(child0_ptr->switch_vertex(edge_child0) == MultiMeshManager::map_tuple_between_meshes(parent, *child0_ptr, parent.multi_mesh_manager.map_to_child_handles[0], parent.switch_vertex(edge))); - CHECK(child1_ptr->switch_vertex(edge_child1) == MultiMeshManager::map_tuple_between_meshes(parent, *child1_ptr, parent.multi_mesh_manager.map_to_child_handles[1], parent.switch_vertex(edge))); - CHECK(child2_ptr->switch_vertex(edge_child2) == MultiMeshManager::map_tuple_between_meshes(parent, *child2_ptr, parent.multi_mesh_manager.map_to_child_handles[2], parent.switch_vertex(edge))); - - CHECK(child0_ptr->switch_edge(edge_child0) == MultiMeshManager::map_tuple_between_meshes(parent, *child0_ptr, parent.multi_mesh_manager.map_to_child_handles[0], parent.switch_edge(edge))); - CHECK(child1_ptr->switch_edge(edge_child1) == MultiMeshManager::map_tuple_between_meshes(parent, *child1_ptr, parent.multi_mesh_manager.map_to_child_handles[1], parent.switch_edge(edge))); - CHECK(child2_ptr->switch_edge(edge_child2) == MultiMeshManager::map_tuple_between_meshes(parent, *child2_ptr, parent.multi_mesh_manager.map_to_child_handles[2], parent.switch_edge(edge))); + CHECK( + child0_ptr->switch_vertex(edge_child0) == + MultiMeshManager::map_tuple_between_meshes( + parent, + *child0_ptr, + parent.multi_mesh_manager.map_to_child_handles[0], + parent.switch_vertex(edge))); + CHECK( + child1_ptr->switch_vertex(edge_child1) == + MultiMeshManager::map_tuple_between_meshes( + parent, + *child1_ptr, + parent.multi_mesh_manager.map_to_child_handles[1], + parent.switch_vertex(edge))); + CHECK( + child2_ptr->switch_vertex(edge_child2) == + MultiMeshManager::map_tuple_between_meshes( + parent, + *child2_ptr, + parent.multi_mesh_manager.map_to_child_handles[2], + parent.switch_vertex(edge))); + + CHECK( + child0_ptr->switch_edge(edge_child0) == + MultiMeshManager::map_tuple_between_meshes( + parent, + *child0_ptr, + parent.multi_mesh_manager.map_to_child_handles[0], + parent.switch_edge(edge))); + CHECK( + child1_ptr->switch_edge(edge_child1) == + MultiMeshManager::map_tuple_between_meshes( + parent, + *child1_ptr, + parent.multi_mesh_manager.map_to_child_handles[1], + parent.switch_edge(edge))); + CHECK( + child2_ptr->switch_edge(edge_child2) == + MultiMeshManager::map_tuple_between_meshes( + parent, + *child2_ptr, + parent.multi_mesh_manager.map_to_child_handles[2], + parent.switch_edge(edge))); } -TEST_CASE("test_split_multi_mesh","[multimesh][2D]") +TEST_CASE("test_split_multi_mesh", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); std::shared_ptr child0_ptr = std::make_shared(single_triangle()); std::vector child0_map = {0}; std::shared_ptr child1_ptr = std::make_shared(one_ear()); - std::vector child1_map = {0,1}; - std::shared_ptr child2_ptr = std::make_shared(two_neighbors_cut_on_edge01()); - std::vector child2_map = {0,1,2}; + std::vector child1_map = {0, 1}; + std::shared_ptr child2_ptr = + std::make_shared(two_neighbors_cut_on_edge01()); + std::vector child2_map = {0, 1, 2}; MultiMeshManager::register_child_mesh(parent, child0_ptr, child0_map); MultiMeshManager::register_child_mesh(parent, child1_ptr, child1_map); @@ -138,7 +197,7 @@ TEST_CASE("test_split_multi_mesh","[multimesh][2D]") REQUIRE(child0_ptr->is_connectivity_valid()); REQUIRE(child1_ptr->is_connectivity_valid()); REQUIRE(child2_ptr->is_connectivity_valid()); - REQUIRE(parent.multi_mesh_manager.is_map_valid(parent) == true); + REQUIRE(parent.multi_mesh_manager.is_map_valid(parent) == true); CHECK(parent.fv_from_fid(2) == Eigen::Matrix(0, 2, 4)); CHECK(parent.fv_from_fid(3) == Eigen::Matrix(5, 1, 2)); @@ -147,7 +206,7 @@ TEST_CASE("test_split_multi_mesh","[multimesh][2D]") CHECK(parent.fv_from_fid(8) == Eigen::Matrix(6, 5, 2)); CHECK(parent.fv_from_fid(9) == Eigen::Matrix(3, 6, 0)); CHECK(parent.fv_from_fid(10) == Eigen::Matrix(3, 5, 6)); - + CHECK(child0_ptr->fv_from_fid(1) == Eigen::Matrix(3, 1, 2)); CHECK(child0_ptr->fv_from_fid(3) == Eigen::Matrix(0, 4, 2)); CHECK(child0_ptr->fv_from_fid(4) == Eigen::Matrix(4, 3, 2)); @@ -168,15 +227,16 @@ TEST_CASE("test_split_multi_mesh","[multimesh][2D]") CHECK(child2_ptr->fv_from_fid(10) == Eigen::Matrix(3, 8, 10)); } -TEST_CASE("test_collapse_multi_mesh","[multimesh][2D]") +TEST_CASE("test_collapse_multi_mesh", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); std::shared_ptr child0_ptr = std::make_shared(two_neighbors()); - std::vector child0_map = {0,1,2}; + std::vector child0_map = {0, 1, 2}; std::shared_ptr child1_ptr = std::make_shared(one_ear()); - std::vector child1_map = {0,1}; - std::shared_ptr child2_ptr = std::make_shared(two_neighbors_cut_on_edge01()); - std::vector child2_map = {0,1,2}; + std::vector child1_map = {0, 1}; + std::shared_ptr child2_ptr = + std::make_shared(two_neighbors_cut_on_edge01()); + std::vector child2_map = {0, 1, 2}; MultiMeshManager::register_child_mesh(parent, child0_ptr, child0_map); MultiMeshManager::register_child_mesh(parent, child1_ptr, child1_map); @@ -201,7 +261,5 @@ TEST_CASE("test_collapse_multi_mesh","[multimesh][2D]") CHECK(child1_ptr->fv_from_fid(1) == Eigen::Matrix(3, 2, 0)); CHECK(child2_ptr->fv_from_fid(1) == Eigen::Matrix(3, 5, 6)); CHECK(child2_ptr->fv_from_fid(2) == Eigen::Matrix(0, 2, 4)); - } - diff --git a/tests/tools/DEBUG_TriMesh.hpp b/tests/tools/DEBUG_TriMesh.hpp index e7b1bd63cb..e493a94fe9 100644 --- a/tests/tools/DEBUG_TriMesh.hpp +++ b/tests/tools/DEBUG_TriMesh.hpp @@ -17,6 +17,7 @@ class DEBUG_TriMesh : public TriMesh // uses spdlog to print out a variety of information about the mesh void print_state() const; + MultiMeshManager& multi_mesh_manager() { return m_multi_mesh_manager; } void print_vf() const; Eigen::Matrix fv_from_fid(const long fid) const; From 6969c8e2c317c36cadd41fa3b2a90a21c2879c35 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Wed, 4 Oct 2023 12:01:30 -0400 Subject: [PATCH 14/25] merge --- src/wmtk/Mesh.cpp | 2 +- src/wmtk/Mesh.hpp | 3 +- src/wmtk/autogen/CMakeLists.txt | 5 + src/wmtk/autogen/is_ccw.cpp | 30 ++ src/wmtk/autogen/is_ccw.hpp | 14 + src/wmtk/autogen/local_switch_tuple.cpp | 15 + src/wmtk/autogen/local_switch_tuple.hpp | 9 + src/wmtk/autogen/tet_mesh/is_ccw.cpp | 3 + src/wmtk/autogen/tet_mesh/is_ccw.hpp | 4 +- .../tet_mesh/local_id_table_offset.cpp | 21 +- .../tet_mesh/local_id_table_offset.hpp | 4 + .../autogen/tet_mesh/local_switch_tuple.hpp | 1 + src/wmtk/autogen/tri_mesh/is_ccw.cpp | 2 + .../tri_mesh/local_id_table_offset.cpp | 10 + .../tri_mesh/local_id_table_offset.hpp | 4 + .../autogen/tri_mesh/local_switch_tuple.hpp | 1 + tests/CMakeLists.txt | 3 +- tests/test_autogen.cpp | 271 ++++++++++++++++++ 18 files changed, 396 insertions(+), 6 deletions(-) create mode 100644 src/wmtk/autogen/is_ccw.cpp create mode 100644 src/wmtk/autogen/is_ccw.hpp create mode 100644 src/wmtk/autogen/local_switch_tuple.cpp create mode 100644 src/wmtk/autogen/local_switch_tuple.hpp create mode 100644 tests/test_autogen.cpp diff --git a/src/wmtk/Mesh.cpp b/src/wmtk/Mesh.cpp index ff5aa1a95d..d72798f6d7 100644 --- a/src/wmtk/Mesh.cpp +++ b/src/wmtk/Mesh.cpp @@ -273,7 +273,7 @@ Tuple Mesh::switch_tuples_unsafe( std::vector Mesh::absolute_multi_mesh_id() const { - m_multi_mesh_manager.absolute_id(); + return m_multi_mesh_manager.absolute_id(); } void Mesh::register_child_mesh( const std::shared_ptr& child_mesh, diff --git a/src/wmtk/Mesh.hpp b/src/wmtk/Mesh.hpp index 978287c119..5220b3ef3b 100644 --- a/src/wmtk/Mesh.hpp +++ b/src/wmtk/Mesh.hpp @@ -358,11 +358,12 @@ class Mesh : public std::enable_shared_from_this // std::shared_ptr request_accesor_cache(); //[[nodiscard]] AccessorScopeHandle push_accesor_scope(); -private: // members +protected: // THese are protected so unit tests can access - do not use manually in other derived classes? attribute::AttributeManager m_attribute_manager; MultiMeshManager m_multi_mesh_manager; +private: // PImpl'd manager of per-thread update stacks // Every time a new access scope is requested the manager creates another level of indirection // for updates diff --git a/src/wmtk/autogen/CMakeLists.txt b/src/wmtk/autogen/CMakeLists.txt index 1161c5d418..5f184c75e4 100644 --- a/src/wmtk/autogen/CMakeLists.txt +++ b/src/wmtk/autogen/CMakeLists.txt @@ -18,5 +18,10 @@ set(SRC_FILES tri_mesh/local_id_table_offset.cpp tri_mesh/local_id_table_offset.hpp + is_ccw.hpp + is_ccw.cpp + local_switch_tuple.hpp + local_switch_tuple.cpp + ) target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) diff --git a/src/wmtk/autogen/is_ccw.cpp b/src/wmtk/autogen/is_ccw.cpp new file mode 100644 index 0000000000..67f0a164c9 --- /dev/null +++ b/src/wmtk/autogen/is_ccw.cpp @@ -0,0 +1,30 @@ +#include "is_ccw.hpp" +#include +#include +#include +namespace wmtk::autogen { +bool is_ccw(PrimitiveType pt, const Tuple& t) +{ + switch (pt) { + case PrimitiveType::Face: return tri_mesh::is_ccw(t); + case PrimitiveType::Tetrahedron: return tet_mesh::is_ccw(t); + case PrimitiveType::Vertex: + case PrimitiveType::Edge: + default: throw "notimplemented"; + } + return false; +} + +// validates whether the tuple local ids are valid for computing ccw'ness +bool tuple_is_valid_for_ccw(PrimitiveType pt, const Tuple& t) +{ + switch (pt) { + case PrimitiveType::Face: return tri_mesh::tuple_is_valid_for_ccw(t); + case PrimitiveType::Tetrahedron: return tet_mesh::tuple_is_valid_for_ccw(t); + case PrimitiveType::Vertex: + case PrimitiveType::Edge: + default: throw "notimplemented"; + } + return false; +} +} // namespace wmtk::autogen diff --git a/src/wmtk/autogen/is_ccw.hpp b/src/wmtk/autogen/is_ccw.hpp new file mode 100644 index 0000000000..100606f21d --- /dev/null +++ b/src/wmtk/autogen/is_ccw.hpp @@ -0,0 +1,14 @@ +#pragma once +#include + +namespace wmtk { +class Tuple; +} + +// NOTE: this header primarily exists to simplify unit testing, not really for use +namespace wmtk::autogen { +bool is_ccw(PrimitiveType ptype, const Tuple& t); + +// validates whether the tuple local ids are valid for computing ccw'ness +bool tuple_is_valid_for_ccw(PrimitiveType ptype, const Tuple& t); +} // namespace wmtk::autogen diff --git a/src/wmtk/autogen/local_switch_tuple.cpp b/src/wmtk/autogen/local_switch_tuple.cpp new file mode 100644 index 0000000000..ae0745bbe2 --- /dev/null +++ b/src/wmtk/autogen/local_switch_tuple.cpp @@ -0,0 +1,15 @@ +#include "local_switch_tuple.hpp" +#include +#include +namespace wmtk::autogen { +Tuple local_switch_tuple(PrimitiveType mesh_type, const Tuple& t, PrimitiveType pt) +{ + switch (mesh_type) { + case PrimitiveType::Face: return tri_mesh::local_switch_tuple(t, pt); + case PrimitiveType::Tetrahedron: return tet_mesh::local_switch_tuple(t, pt); + case PrimitiveType::Vertex: + case PrimitiveType::Edge: throw "notimplemented"; + } + return Tuple(); +} +} // namespace wmtk::autogen diff --git a/src/wmtk/autogen/local_switch_tuple.hpp b/src/wmtk/autogen/local_switch_tuple.hpp new file mode 100644 index 0000000000..87c2472783 --- /dev/null +++ b/src/wmtk/autogen/local_switch_tuple.hpp @@ -0,0 +1,9 @@ + +#pragma once +#include +#include + +// NOTE: this header primarily exists to simplify unit testing, not really for use +namespace wmtk::autogen { +Tuple local_switch_tuple(PrimitiveType mesh_type, const Tuple& t, PrimitiveType pt); +} diff --git a/src/wmtk/autogen/tet_mesh/is_ccw.cpp b/src/wmtk/autogen/tet_mesh/is_ccw.cpp index d8b0e93c6d..5dbe7bae30 100644 --- a/src/wmtk/autogen/tet_mesh/is_ccw.cpp +++ b/src/wmtk/autogen/tet_mesh/is_ccw.cpp @@ -1,12 +1,15 @@ #include "is_ccw.hpp" #include +#include +#include #include "autogenerated_tables.hpp" #include "local_id_table_offset.hpp" namespace wmtk::autogen::tet_mesh { bool is_ccw(const Tuple& tuple) { + assert(tuple_is_valid_for_ccw(tuple)); using namespace utils; const long offset = local_id_table_offset(tuple); return auto_3d_table_ccw[offset] == 1; diff --git a/src/wmtk/autogen/tet_mesh/is_ccw.hpp b/src/wmtk/autogen/tet_mesh/is_ccw.hpp index 0018b7390b..84b8ca1ac5 100644 --- a/src/wmtk/autogen/tet_mesh/is_ccw.hpp +++ b/src/wmtk/autogen/tet_mesh/is_ccw.hpp @@ -1,5 +1,7 @@ #pragma once -#include +namespace wmtk { +class Tuple; +} namespace wmtk::autogen::tet_mesh { bool is_ccw(const Tuple& t); diff --git a/src/wmtk/autogen/tet_mesh/local_id_table_offset.cpp b/src/wmtk/autogen/tet_mesh/local_id_table_offset.cpp index eb79a36e31..ddadfb1c35 100644 --- a/src/wmtk/autogen/tet_mesh/local_id_table_offset.cpp +++ b/src/wmtk/autogen/tet_mesh/local_id_table_offset.cpp @@ -6,8 +6,25 @@ namespace wmtk::autogen::tet_mesh { long local_id_table_offset(const Tuple& tuple) { using namespace utils; - return TupleInspector::local_vid(tuple) * 6 * 4 + TupleInspector::local_eid(tuple) * 4 + - TupleInspector::local_fid(tuple); + long value = TupleInspector::local_vid(tuple) * 6 * 4 + TupleInspector::local_eid(tuple) * 4 + + TupleInspector::local_fid(tuple); + + + // value = (TupleInspector::local_vid(tuple) * 6 + TupleInspector::local_eid(tuple)) * 4 + + // TupleInspector::local_fid(tuple); + return value; +} + +std::array lvid_leid_lfid_from_table_offset(long table_offset) +{ + std::array r; + auto& [lvid, leid, lfid] = r; + lfid = table_offset % 4; + + long ve_offset = table_offset / 4; + leid = ve_offset % 6; + lvid = ve_offset / 6; + return r; } } // namespace wmtk::autogen::tet_mesh diff --git a/src/wmtk/autogen/tet_mesh/local_id_table_offset.hpp b/src/wmtk/autogen/tet_mesh/local_id_table_offset.hpp index bd74c73f4a..caede9d639 100644 --- a/src/wmtk/autogen/tet_mesh/local_id_table_offset.hpp +++ b/src/wmtk/autogen/tet_mesh/local_id_table_offset.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include @@ -6,4 +7,7 @@ namespace wmtk::autogen::tet_mesh { // computes the offset of a tuple's local ids in the tables long local_id_table_offset(const Tuple& t); +// returns a lvid/leid/lfid associated iwth a particular tuple offset +std::array lvid_leid_lfid_from_table_offset(long table_offset); + } // namespace wmtk::autogen::tet_mesh diff --git a/src/wmtk/autogen/tet_mesh/local_switch_tuple.hpp b/src/wmtk/autogen/tet_mesh/local_switch_tuple.hpp index 6d9bb0931e..3ed761407c 100644 --- a/src/wmtk/autogen/tet_mesh/local_switch_tuple.hpp +++ b/src/wmtk/autogen/tet_mesh/local_switch_tuple.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include namespace wmtk::autogen::tet_mesh { diff --git a/src/wmtk/autogen/tri_mesh/is_ccw.cpp b/src/wmtk/autogen/tri_mesh/is_ccw.cpp index 35b496f9f0..d6e9ceac24 100644 --- a/src/wmtk/autogen/tri_mesh/is_ccw.cpp +++ b/src/wmtk/autogen/tri_mesh/is_ccw.cpp @@ -1,12 +1,14 @@ #include "is_ccw.hpp" #include +#include #include "autogenerated_tables.hpp" #include "local_id_table_offset.hpp" namespace wmtk::autogen::tri_mesh { bool is_ccw(const Tuple& tuple) { + assert(tuple_is_valid_for_ccw(tuple)); using namespace utils; const long offset = local_id_table_offset(tuple); return auto_2d_table_ccw[offset] == 1; diff --git a/src/wmtk/autogen/tri_mesh/local_id_table_offset.cpp b/src/wmtk/autogen/tri_mesh/local_id_table_offset.cpp index 5aeda960ec..2c20d149c2 100644 --- a/src/wmtk/autogen/tri_mesh/local_id_table_offset.cpp +++ b/src/wmtk/autogen/tri_mesh/local_id_table_offset.cpp @@ -9,4 +9,14 @@ long local_id_table_offset(const Tuple& tuple) return TupleInspector::local_vid(tuple) * 3 + TupleInspector::local_eid(tuple); } +std::array lvid_leid_from_table_offset(long table_offset) +{ + std::array r; + auto& [lvid, leid] = r; + + lvid = table_offset / 3; + leid = table_offset % 3; + return r; +} + } // namespace wmtk::autogen::tri_mesh diff --git a/src/wmtk/autogen/tri_mesh/local_id_table_offset.hpp b/src/wmtk/autogen/tri_mesh/local_id_table_offset.hpp index 407f733661..6b29f5b560 100644 --- a/src/wmtk/autogen/tri_mesh/local_id_table_offset.hpp +++ b/src/wmtk/autogen/tri_mesh/local_id_table_offset.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include @@ -6,5 +7,8 @@ namespace wmtk::autogen::tri_mesh { // computes the offset of a tuple's local ids in the tables long local_id_table_offset(const Tuple& t); +// returns a lvid/leid associated iwth a particular tuple offset +std::array lvid_leid_from_table_offset(long table_offset); + } // namespace wmtk::autogen::tri_mesh diff --git a/src/wmtk/autogen/tri_mesh/local_switch_tuple.hpp b/src/wmtk/autogen/tri_mesh/local_switch_tuple.hpp index 3a67107896..f8ff6fbcff 100644 --- a/src/wmtk/autogen/tri_mesh/local_switch_tuple.hpp +++ b/src/wmtk/autogen/tri_mesh/local_switch_tuple.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include namespace wmtk::autogen::tri_mesh { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 08a53809f1..c2ded9b176 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,6 +10,7 @@ lagrange_include_modules(io) # Sources set(TEST_SOURCES test_topology.cpp + test_autogen.cpp test_tuple.cpp test_tuple_2d.cpp test_tuple_3d.cpp @@ -22,7 +23,7 @@ set(TEST_SOURCES test_accessor.cpp test_example_meshes.cpp test_3d_operations.cpp - test_multi_mesh.cpp + #test_multi_mesh.cpp tools/DEBUG_PointMesh.hpp tools/DEBUG_TriMesh.hpp tools/DEBUG_TriMesh.cpp diff --git a/tests/test_autogen.cpp b/tests/test_autogen.cpp new file mode 100644 index 0000000000..f2d60fe9d4 --- /dev/null +++ b/tests/test_autogen.cpp @@ -0,0 +1,271 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace wmtk; +using namespace wmtk::autogen; +; +namespace { + +std::vector primitives_up_to(PrimitiveType pt) +{ + std::vector r; + + switch (pt) { + case PrimitiveType::Tetrahedron: r.emplace_back(PrimitiveType::Face); [[fallthrough]]; + case PrimitiveType::Face: r.emplace_back(PrimitiveType::Edge); [[fallthrough]]; + case PrimitiveType::Edge: r.emplace_back(PrimitiveType::Vertex); [[fallthrough]]; + case PrimitiveType::Vertex: + default: break; + } + return r; +} + + +long max_tuple_count(PrimitiveType pt) +{ + switch (pt) { + case PrimitiveType::Face: return long(std::size(wmtk::autogen::tri_mesh::auto_2d_table_ccw)); + case PrimitiveType::Tetrahedron: + return long(std::size(wmtk::autogen::tet_mesh::auto_3d_table_ccw)); + case PrimitiveType::Vertex: + case PrimitiveType::Edge: break; + } + return -1; +} + +Tuple tuple_from_offset_id(PrimitiveType pt, int offset) +{ + long lvid = 0, leid = 0, lfid = 0, gcid = 0, hash = 0; + + switch (pt) { + case PrimitiveType::Face: { + // bug in the standard? tie should work :-( + auto r = tri_mesh::lvid_leid_from_table_offset(offset); + lvid = r[0]; + leid = r[1]; + } break; + case PrimitiveType::Tetrahedron: { + auto r = tet_mesh::lvid_leid_lfid_from_table_offset(offset); + lvid = r[0]; + leid = r[1]; + lfid = r[2]; + } break; + case PrimitiveType::Vertex: + case PrimitiveType::Edge: break; + } + + Tuple r(lvid, leid, lfid, gcid, hash); + if (!tuple_is_valid_for_ccw(pt, r)) { + r = Tuple(); + } + return r; +} + +std::vector all_valid_local_tuples(PrimitiveType pt) +{ + std::vector tups; + tups.reserve(max_tuple_count(pt)); + for (long idx = 0; idx < max_tuple_count(pt); ++idx) { + tups.emplace_back(tuple_from_offset_id(pt, idx)); + } + + tups.erase( + std::remove_if( + tups.begin(), + tups.end(), + [](const Tuple& t) -> bool { return t.is_null(); }), + tups.end()); + return tups; +} +} // namespace + +TEST_CASE("tuple_autogen_sizes", "[tuple]") +{ + size_t valid_face = 6; + size_t valid_tet = 24; + + REQUIRE(all_valid_local_tuples(PrimitiveType::Face).size() == valid_face); + REQUIRE(all_valid_local_tuples(PrimitiveType::Tetrahedron).size() == valid_tet); + + auto get_array_range = [](const auto& array) -> std::array { + return std::array{{array, array + std::size(array)}}; + }; + {// ccw check + {// tri + auto ccw_range = get_array_range(tri_mesh::auto_2d_table_ccw); + size_t count = std::count_if(ccw_range[0], ccw_range[1], [](long v) { return v != -1; }); + CHECK(count == valid_face); +} +{ + auto ccw_range = get_array_range(tet_mesh::auto_3d_table_ccw); + size_t count = std::count_if(ccw_range[0], ccw_range[1], [](long v) { return v != -1; }); + CHECK(count == valid_tet); +} +} +{{// tri + auto range = get_array_range(tri_mesh::auto_2d_table_vertex); +size_t count = + std::count_if(range[0], range[1], [](const long v[2]) { return v[0] != -1 && v[1] != -1; }); +CHECK(count == valid_face); +} +{ // tri + auto range = get_array_range(tri_mesh::auto_2d_table_edge); + size_t count = + std::count_if(range[0], range[1], [](const long v[2]) { return v[0] != -1 && v[1] != -1; }); + CHECK(count == valid_face); +} +} +{ + { // tet + auto range = get_array_range(tet_mesh::auto_3d_table_vertex); + size_t count = std::count_if(range[0], range[1], [](const long v[3]) { + return v[0] != -1 && v[1] != -1 && v[2] != -1; + }); + CHECK(count == valid_tet); + } + { // tet + auto range = get_array_range(tet_mesh::auto_3d_table_edge); + size_t count = std::count_if(range[0], range[1], [](const long v[3]) { + return v[0] != -1 && v[1] != -1 && v[2] != -1; + }); + CHECK(count == valid_tet); + } + { // tet + auto range = get_array_range(tet_mesh::auto_3d_table_face); + size_t count = std::count_if(range[0], range[1], [](const long v[3]) { + return v[0] != -1 && v[1] != -1 && v[2] != -1; + }); + CHECK(count == valid_tet); + } +} +} + +TEST_CASE("tuple_autogen_id_inversion", "[tuple]") +{ + // when other meshes are available add them here + for (PrimitiveType pt : {PrimitiveType::Face, PrimitiveType::Tetrahedron}) { + for (long idx = 0; idx < max_tuple_count(pt); ++idx) { + Tuple t = tuple_from_offset_id(pt, idx); + if (t.is_null()) { + continue; + } else { + switch (pt) { + case PrimitiveType::Face: { + CHECK(idx == tri_mesh::local_id_table_offset(t)); + break; + } + case PrimitiveType::Tetrahedron: { + CHECK(idx == tet_mesh::local_id_table_offset(t)); + break; + } + case PrimitiveType::Vertex: + case PrimitiveType::Edge: break; + } + } + } + } +} + +TEST_CASE("tuple_autogen_ptype_is_ccw_equivalent", "[tuple]") +{ + { + auto tuples = all_valid_local_tuples(PrimitiveType::Face); + for (const auto& t : tuples) { + CHECK(tri_mesh::is_ccw(t) == is_ccw(PrimitiveType::Face, t)); + } + } + + { + auto tuples = all_valid_local_tuples(PrimitiveType::Tetrahedron); + for (const auto& t : tuples) { + CHECK(tet_mesh::is_ccw(t) == is_ccw(PrimitiveType::Tetrahedron, t)); + } + } +} + +TEST_CASE("tuple_autogen_local_id_inversion", "[tuple]") +{ + // NOTE: this works because we assume the unused ids are = 0; from tuple_from_offset_id + // above + { + auto tuples = all_valid_local_tuples(PrimitiveType::Face); + for (const auto& t : tuples) { + long id = tri_mesh::local_id_table_offset(t); + auto [lvid, leid] = tri_mesh::lvid_leid_from_table_offset(id); + Tuple nt(lvid, leid, 0, 0, 0); + long nid = tri_mesh::local_id_table_offset(nt); + + CHECK(t == nt); + CHECK(id == nid); + } + } + + { + auto tuples = all_valid_local_tuples(PrimitiveType::Tetrahedron); + for (const auto& t : tuples) { + long id = tet_mesh::local_id_table_offset(t); + auto [lvid, leid, lfid] = tet_mesh::lvid_leid_lfid_from_table_offset(id); + Tuple nt(lvid, leid, lfid, 0, 0); + long nid = tet_mesh::local_id_table_offset(nt); + CHECK(t == nt); + CHECK(id == nid); + } + } +} + +TEST_CASE("tuple_autogen_ptype_local_switch_tuple_equivalent", "[tuple]") +{ + { + auto tuples = all_valid_local_tuples(PrimitiveType::Face); + for (const auto& t : tuples) { + for (PrimitiveType pt : primitives_up_to(PrimitiveType::Face)) { + CHECK( + tri_mesh::local_switch_tuple(t, pt) == + local_switch_tuple(PrimitiveType::Face, t, pt)); + } + } + } + + { + auto tuples = all_valid_local_tuples(PrimitiveType::Tetrahedron); + for (const auto& t : tuples) { + for (PrimitiveType pt : primitives_up_to(PrimitiveType::Tetrahedron)) { + CHECK( + tet_mesh::local_switch_tuple(t, pt) == + local_switch_tuple(PrimitiveType::Tetrahedron, t, pt)); + } + } + } +} + + +TEST_CASE("tuple_autogen_switch_still_valid", "[tuple]") +{ + // when other meshes are available add them here + for (PrimitiveType mesh_type : {PrimitiveType::Face /*, PrimitiveType::Tetrahedron*/}) { + auto tuples = all_valid_local_tuples(mesh_type); + + for (const auto& t : tuples) { + CHECK(tuple_is_valid_for_ccw(mesh_type, t)); + // for (PrimitiveType pt : primitives_up_to(mesh_type)) { + // CHECK(tuple_is_valid_for_ccw(mesh_type, local_switch_tuple(mesh_type, t, + // pt))); + // } + } + } +} From d77b1daad1581c9d3b06b0c79c6b23ce798e5721 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Wed, 4 Oct 2023 12:22:31 -0400 Subject: [PATCH 15/25] adding missed tuple to tuple parent map in multimesh and adding generic map --- src/wmtk/Mesh.cpp | 4 +-- src/wmtk/MultiMeshManager.cpp | 53 +++++++++++++++++++++++++++++++++-- src/wmtk/MultiMeshManager.hpp | 4 +++ 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/wmtk/Mesh.cpp b/src/wmtk/Mesh.cpp index d72798f6d7..a2fe7ba7bc 100644 --- a/src/wmtk/Mesh.cpp +++ b/src/wmtk/Mesh.cpp @@ -276,10 +276,10 @@ std::vector Mesh::absolute_multi_mesh_id() const return m_multi_mesh_manager.absolute_id(); } void Mesh::register_child_mesh( - const std::shared_ptr& child_mesh, + const std::shared_ptr& child_mesh_ptr, const std::vector>& map_tuples) { - m_multi_mesh_manager.register_child_mesh(child_mesh, map_tuples); + m_multi_mesh_manager.register_child_mesh(*this,child_mesh_ptr, map_tuples); } diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 4074817284..9607ab9402 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -143,10 +143,26 @@ void MultiMeshManager::register_child_mesh( } */ +const Mesh& MultiMeshManager::get_root_mesh(const Mesh& my_mesh) const +{ + if (m_parent == nullptr) { + return my_mesh; + } else { + return m_parent->m_multi_mesh_manager.get_root_mesh(*m_parent); + } +} +Mesh& MultiMeshManager::get_root_mesh(Mesh& my_mesh) +{ + if (m_parent == nullptr) { + return my_mesh; + } else { + return m_parent->m_multi_mesh_manager.get_root_mesh(*m_parent); + } +} std::vector MultiMeshManager::map(const Mesh& my_mesh, const Mesh& other_mesh, const Simplex& my_simplex) const { - const auto ret_tups = map_to_tuples(my_mesh, other_mesh, my_simplex); + const auto ret_tups = map_tuples(my_mesh, other_mesh, my_simplex); return simplex::utils::tuple_vector_to_homogeneous_simplex_vector( ret_tups, my_simplex.primitive_type()); @@ -156,17 +172,44 @@ std::vector MultiMeshManager::map_tuples( const Mesh& other_mesh, const Simplex& my_simplex) const { - throw "Not implemented"; + const PrimitiveType pt = my_simplex.primitive_type(); assert(&my_mesh.m_multi_mesh_manager == this); // TODO: construct relative positions std::vector equivalent_tuples = simplex::top_level_cofaces_tuples(my_mesh, my_simplex); // TODO: construct visitor class that maps up and down // MultiMeshMapVisitor visitor(my_mesh, other_mesh); + // const auto my_id = absolute_id(); someday could be used to map down + const auto other_id = other_mesh.absolute_multi_mesh_id(); // TODO: visitor runs along meshes traversing the path + // get a root tuple + Tuple cur_tuple = my_simplex.tuple(); + const Mesh* cur_mesh = &my_mesh; + while (cur_mesh != nullptr) { + cur_tuple = cur_mesh->m_multi_mesh_manager.map_tuple_to_parent_tuple(*cur_mesh, cur_tuple); + cur_mesh = cur_mesh->m_multi_mesh_manager.m_parent; + } + + // bieng lazy about how i set cur_mesh to nullptr above - could simplify the loop to optimize + cur_mesh = &get_root_mesh(other_mesh); + std::vector tuples; + for (auto it = other_id.rbegin(); it != other_id.rend(); ++it) { + long child_index = *it; + std::vector new_tuples; + const ChildData& cd = cur_mesh->m_multi_mesh_manager.m_children.at(child_index); + for (const Tuple& t : tuples) { + std::vector n = + cur_mesh->m_multi_mesh_manager.map_to_child_tuples(*cur_mesh, cd, Simplex(pt, t)); + new_tuples.insert(new_tuples.end(), n.begin(), n.end()); + } + tuples = std::move(new_tuples); + cur_mesh = cd.mesh.get(); + assert(cur_mesh->absolute_multi_mesh_id() == child_index); + } + // visitor.map(equivalent_tuples, my_simplex.primitive_type()); - return {}; + return tuples; } @@ -176,6 +219,10 @@ Simplex MultiMeshManager::map_to_parent(const Mesh& my_mesh, const Simplex& my_s my_simplex.primitive_type(), map_tuple_to_parent_tuple(my_mesh, my_simplex.tuple())); } +Tuple MultiMeshManager::map_to_parent_tuple(const Mesh& my_mesh, const Simplex& my_simplex) const +{ + return map_tuple_to_parent_tuple(my_mesh, my_simplex.tuple()); +} Tuple MultiMeshManager::map_tuple_to_parent_tuple(const Mesh& my_mesh, const Tuple& my_tuple) const { diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index 0350aa064d..45f0286f31 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -27,6 +27,8 @@ class MultiMeshManager bool is_root() const; long child_id() const; // + // an id computed using the path to the root. NOTE: traversing from the root requies iterating + // these indices backwards std::vector absolute_id() const; @@ -80,6 +82,8 @@ class MultiMeshManager std::vector map_edge_tuple_to_all_children(const Mesh& my_mesh, const Simplex& tuple) const; + const Mesh& get_root_mesh(const Mesh& my_mesh) const; + Mesh& get_root_mesh(Mesh& my_mesh); private: Mesh* m_parent = nullptr; From fe969ee8320431f62f0e3306e672990a96625d30 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Thu, 5 Oct 2023 00:15:06 -0400 Subject: [PATCH 16/25] adding an initial implementation of the "identity map" multimesh mapping --- src/wmtk/Mesh.hpp | 9 +++- src/wmtk/multimesh/CMakeLists.txt | 7 +++ .../same_simplex_dimension_surjection.cpp | 51 +++++++++++++++++++ .../same_simplex_dimension_surjection.hpp | 27 ++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/wmtk/multimesh/same_simplex_dimension_surjection.cpp create mode 100644 src/wmtk/multimesh/same_simplex_dimension_surjection.hpp diff --git a/src/wmtk/Mesh.hpp b/src/wmtk/Mesh.hpp index 5220b3ef3b..71fed7ca9f 100644 --- a/src/wmtk/Mesh.hpp +++ b/src/wmtk/Mesh.hpp @@ -15,6 +15,8 @@ #include "attribute/AttributeManager.hpp" #include "attribute/AttributeScopeHandle.hpp" #include "attribute/MeshAttributes.hpp" +// included to make a friend as this requires IDs +#include #include "simplex/Simplex.hpp" @@ -47,6 +49,10 @@ class Mesh : public std::enable_shared_from_this friend class ParaviewWriter; friend class MeshReader; friend class MultiMeshManager; + friend std::vector> multimesh::same_simplex_dimension_surjection( + const Mesh& parent, + const Mesh& child, + const std::vector& parent_simplices); virtual PrimitiveType top_simplex_type() const = 0; @@ -358,7 +364,8 @@ class Mesh : public std::enable_shared_from_this // std::shared_ptr request_accesor_cache(); //[[nodiscard]] AccessorScopeHandle push_accesor_scope(); -protected: // THese are protected so unit tests can access - do not use manually in other derived classes? +protected: // THese are protected so unit tests can access - do not use manually in other derived + // classes? attribute::AttributeManager m_attribute_manager; MultiMeshManager m_multi_mesh_manager; diff --git a/src/wmtk/multimesh/CMakeLists.txt b/src/wmtk/multimesh/CMakeLists.txt index 512d2b1553..d41a4a8680 100644 --- a/src/wmtk/multimesh/CMakeLists.txt +++ b/src/wmtk/multimesh/CMakeLists.txt @@ -1 +1,8 @@ + +set(SRC_FILES + same_simplex_dimension_surjection.hpp + same_simplex_dimension_surjection.cpp + ) +target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) + add_subdirectory(utils) diff --git a/src/wmtk/multimesh/same_simplex_dimension_surjection.cpp b/src/wmtk/multimesh/same_simplex_dimension_surjection.cpp new file mode 100644 index 0000000000..54d7ff32d5 --- /dev/null +++ b/src/wmtk/multimesh/same_simplex_dimension_surjection.cpp @@ -0,0 +1,51 @@ +#include "same_simplex_dimension_surjection.hpp" +#include +#include + + +namespace wmtk::multimesh { +std::vector> same_simplex_dimension_surjection( + const Mesh& parent, + const Mesh& child) +{ + PrimitiveType primitive_type = parent.top_simplex_type(); + assert(primitive_type == child.top_simplex_type()); + long size = parent.capacity(primitive_type); + assert(size == child.capacity(primitive_type)); + std::vector ps; + ps.reserve(size); + std::iota(ps.begin(), ps.end(), 0); + return same_simplex_dimension_surjection(parent, child, ps); +} + +std::vector> same_simplex_dimension_surjection( + const Mesh& parent, + const Mesh& child, + const std::vector& parent_simplices) +{ + PrimitiveType primitive_type = parent.top_simplex_type(); + assert(primitive_type == child.top_simplex_type()); + + long size = child.capacity(primitive_type); + assert(size == long(parent_simplices.size())); + std::vector> ret; + ret.reserve(size); + + auto parent_flag_accessor = parent.get_const_flag_accessor(primitive_type); + auto child_flag_accessor = child.get_const_flag_accessor(primitive_type); + + for (long index = 0; index < size; ++index) { + const Tuple ct = child.tuple_from_id(primitive_type, index); + const Tuple pt = parent.tuple_from_id(primitive_type, parent_simplices.at(index)); + if (parent_flag_accessor.const_scalar_attribute(pt) & 1 == 0) { + continue; + } + if (child_flag_accessor.const_scalar_attribute(pt) & 1 == 0) { + continue; + } + + ret.emplace_back(std::array{{pt, ct}}); + } + return ret; +} +} // namespace wmtk::multimesh diff --git a/src/wmtk/multimesh/same_simplex_dimension_surjection.hpp b/src/wmtk/multimesh/same_simplex_dimension_surjection.hpp new file mode 100644 index 0000000000..81fb2c75c4 --- /dev/null +++ b/src/wmtk/multimesh/same_simplex_dimension_surjection.hpp @@ -0,0 +1,27 @@ +#pragma once +#include +#include +#include + +namespace wmtk { +class Mesh; +} + +namespace wmtk::multimesh { + +// Handles the "trivial " mapping case as we see in OBJ files +// parent and child are assumed to be homogeneous meshes of the same dimension and the same number +// of top level simplices It is assumed that for each index between [0,num_top_level_simplices) it +// is assumed that the tuple parent.tuple_from_id(pt,index) should be mapped to +// child.tuple_from_id(pt,index) +std::vector> same_simplex_dimension_surjection( + const Mesh& parent, + const Mesh& child); +// same as above except the mapping selects a subset of parent_simplices +// the tuple parent.tuple_from_id(pt,parent_simplices[index]) should be mapped to +// child.tuple_from_id(pt,index) +std::vector> same_simplex_dimension_surjection( + const Mesh& parent, + const Mesh& child, + const std::vector& parent_simplices); +} // namespace wmtk::multimesh From b0318d544b73da4c3201cb5bb4b8aa2fe0e3615e Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Thu, 5 Oct 2023 09:35:08 -0400 Subject: [PATCH 17/25] moving simplex dim surjection to multimesh but hiding it in a private --- src/wmtk/Mesh.hpp | 6 ---- src/wmtk/MultiMeshManager.cpp | 30 +++++++++++++++++++ src/wmtk/MultiMeshManager.hpp | 14 +++++++++ .../same_simplex_dimension_surjection.cpp | 25 +--------------- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/wmtk/Mesh.hpp b/src/wmtk/Mesh.hpp index 71fed7ca9f..2c95d5bcd2 100644 --- a/src/wmtk/Mesh.hpp +++ b/src/wmtk/Mesh.hpp @@ -15,8 +15,6 @@ #include "attribute/AttributeManager.hpp" #include "attribute/AttributeScopeHandle.hpp" #include "attribute/MeshAttributes.hpp" -// included to make a friend as this requires IDs -#include #include "simplex/Simplex.hpp" @@ -49,10 +47,6 @@ class Mesh : public std::enable_shared_from_this friend class ParaviewWriter; friend class MeshReader; friend class MultiMeshManager; - friend std::vector> multimesh::same_simplex_dimension_surjection( - const Mesh& parent, - const Mesh& child, - const std::vector& parent_simplices); virtual PrimitiveType top_simplex_type() const = 0; diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 9607ab9402..0d70448e76 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -402,4 +402,34 @@ bool MultiMeshManager::is_child_map_valid(const Mesh& my_mesh, const ChildData& return true; } */ +std::vector> MultiMeshManager::same_simplex_dimension_surjection( + const Mesh& parent, + const Mesh& child, + const std::vector& parent_simplices) +{ + PrimitiveType primitive_type = parent.top_simplex_type(); + assert(primitive_type == child.top_simplex_type()); + + long size = child.capacity(primitive_type); + assert(size == long(parent_simplices.size())); + std::vector> ret; + ret.reserve(size); + + auto parent_flag_accessor = parent.get_const_flag_accessor(primitive_type); + auto child_flag_accessor = child.get_const_flag_accessor(primitive_type); + + for (long index = 0; index < size; ++index) { + const Tuple ct = child.tuple_from_id(primitive_type, index); + const Tuple pt = parent.tuple_from_id(primitive_type, parent_simplices.at(index)); + if (parent_flag_accessor.const_scalar_attribute(pt) & 1 == 0) { + continue; + } + if (child_flag_accessor.const_scalar_attribute(pt) & 1 == 0) { + continue; + } + + ret.emplace_back(std::array{{pt, ct}}); + } + return ret; +} } // namespace wmtk diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index 45f0286f31..ad5b3d98dd 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -6,6 +6,8 @@ #include "Tuple.hpp" #include "attribute/AttributeScopeHandle.hpp" #include "attribute/MeshAttributes.hpp" +// included to make a friend as this requires IDs +#include namespace wmtk { @@ -13,6 +15,11 @@ class Mesh; class MultiMeshManager { public: + friend std::vector> multimesh::same_simplex_dimension_surjection( + const Mesh& parent, + const Mesh& child, + const std::vector& parent_simplices); + MultiMeshManager(); ~MultiMeshManager(); MultiMeshManager(const MultiMeshManager& o); @@ -139,6 +146,13 @@ class MultiMeshManager const Mesh& target_mesh, const ConstAccessor& source_to_target_map_accessor, const Tuple& source_tuple); + +private: + // this is defined internally but is preferablly invoked through the multimesh free function + static std::vector> same_simplex_dimension_surjection( + const Mesh& parent, + const Mesh& child, + const std::vector& parent_simplices); }; } // namespace wmtk diff --git a/src/wmtk/multimesh/same_simplex_dimension_surjection.cpp b/src/wmtk/multimesh/same_simplex_dimension_surjection.cpp index 54d7ff32d5..0c45a5b046 100644 --- a/src/wmtk/multimesh/same_simplex_dimension_surjection.cpp +++ b/src/wmtk/multimesh/same_simplex_dimension_surjection.cpp @@ -23,29 +23,6 @@ std::vector> same_simplex_dimension_surjection( const Mesh& child, const std::vector& parent_simplices) { - PrimitiveType primitive_type = parent.top_simplex_type(); - assert(primitive_type == child.top_simplex_type()); - - long size = child.capacity(primitive_type); - assert(size == long(parent_simplices.size())); - std::vector> ret; - ret.reserve(size); - - auto parent_flag_accessor = parent.get_const_flag_accessor(primitive_type); - auto child_flag_accessor = child.get_const_flag_accessor(primitive_type); - - for (long index = 0; index < size; ++index) { - const Tuple ct = child.tuple_from_id(primitive_type, index); - const Tuple pt = parent.tuple_from_id(primitive_type, parent_simplices.at(index)); - if (parent_flag_accessor.const_scalar_attribute(pt) & 1 == 0) { - continue; - } - if (child_flag_accessor.const_scalar_attribute(pt) & 1 == 0) { - continue; - } - - ret.emplace_back(std::array{{pt, ct}}); - } - return ret; + return MultiMeshManager::same_simplex_dimension_surjection(parent, child, parent_simplices); } } // namespace wmtk::multimesh From 15465031d2822e1f49db4a89d0e442140a70af7b Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Thu, 5 Oct 2023 09:51:20 -0400 Subject: [PATCH 18/25] updates to map_tuples to fix assert in debug + adding some comments --- src/wmtk/MultiMeshManager.cpp | 21 +++++++++++++++++---- src/wmtk/MultiMeshManager.hpp | 2 ++ tests/test_multi_mesh.cpp | 11 ++++++----- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 0d70448e76..15152ae6e1 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -192,19 +192,32 @@ std::vector MultiMeshManager::map_tuples( // bieng lazy about how i set cur_mesh to nullptr above - could simplify the loop to optimize cur_mesh = &get_root_mesh(other_mesh); + + + // note that (cur_mesh, tuples) always match (i.e tuples are tuples from cur_mesh) std::vector tuples; + tuples.emplace_back(cur_tuple); + for (auto it = other_id.rbegin(); it != other_id.rend(); ++it) { + // get the select ID from the child map long child_index = *it; - std::vector new_tuples; const ChildData& cd = cur_mesh->m_multi_mesh_manager.m_children.at(child_index); + + // for every tuple we have try to collect all versions + std::vector new_tuples; for (const Tuple& t : tuples) { + // get new tuples for every version that exists std::vector n = cur_mesh->m_multi_mesh_manager.map_to_child_tuples(*cur_mesh, cd, Simplex(pt, t)); + // append to teh current set of new tuples new_tuples.insert(new_tuples.end(), n.begin(), n.end()); } + // update teh (mesh,tuples) pair tuples = std::move(new_tuples); cur_mesh = cd.mesh.get(); - assert(cur_mesh->absolute_multi_mesh_id() == child_index); + + // the front id of the current mesh should be the child index from this iteration + assert(cur_mesh->m_multi_mesh_manager.m_child_id == child_index); } // visitor.map(equivalent_tuples, my_simplex.primitive_type()); @@ -421,10 +434,10 @@ std::vector> MultiMeshManager::same_simplex_dimension_surje for (long index = 0; index < size; ++index) { const Tuple ct = child.tuple_from_id(primitive_type, index); const Tuple pt = parent.tuple_from_id(primitive_type, parent_simplices.at(index)); - if (parent_flag_accessor.const_scalar_attribute(pt) & 1 == 0) { + if ((parent_flag_accessor.const_scalar_attribute(pt) & 1) == 0) { continue; } - if (child_flag_accessor.const_scalar_attribute(pt) & 1 == 0) { + if ((child_flag_accessor.const_scalar_attribute(pt) & 1) == 0) { continue; } diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index ad5b3d98dd..6eaf910d94 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -147,6 +147,8 @@ class MultiMeshManager const ConstAccessor& source_to_target_map_accessor, const Tuple& source_tuple); + const std::vector& children() const { return m_children; } + private: // this is defined internally but is preferablly invoked through the multimesh free function static std::vector> same_simplex_dimension_surjection( diff --git a/tests/test_multi_mesh.cpp b/tests/test_multi_mesh.cpp index d84a67c779..9bc96ac2de 100644 --- a/tests/test_multi_mesh.cpp +++ b/tests/test_multi_mesh.cpp @@ -1,6 +1,7 @@ #include #include +#include #include "tools/DEBUG_TriMesh.hpp" #include "tools/TriMesh_examples.hpp" @@ -20,17 +21,17 @@ TEST_CASE("test_register_child_mesh", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); std::shared_ptr child0_ptr = std::make_shared(single_triangle()); - std::vector child0_map = {0}; + auto child0_map = multimesh::same_simplex_dimension_surjection(*parent, *child0_ptr, {0}); std::shared_ptr child1_ptr = std::make_shared(one_ear()); - std::vector child1_map = {0, 1}; + auto child1_map = multimesh::same_simplex_dimension_surjection(*parent, *child1_ptr, {0, 1}); parent.register_child_mesh(child0_ptr, child0_map); parent.register_child_mesh(child1_ptr, child1_map); const auto& p_mul_manager = parent.multi_mesh_manager(); - REQUIRE(p_mul_manager.child_meshes.size() == 2); - REQUIRE(p_mul_manager.child_meshes[0] == child0_ptr); - REQUIRE(p_mul_manager.child_meshes[1] == child1_ptr); + REQUIRE(p_mul_manager.m_children.size() == 2); + REQUIRE(p_mul_manager.m_children[0] == child0_ptr); + REQUIRE(p_mul_manager.m_children[1] == child1_ptr); auto [tuple1, tuple2] = multimesh::utils::read_tuple_map_attribute_slow( p_mul_manager.map_to_child_handles[0], From 04e925ecdf4c148498a69e57595e49f8d65a1811 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Thu, 5 Oct 2023 12:36:24 -0400 Subject: [PATCH 19/25] making multimeshmanager default to -1 for default values --- src/wmtk/MultiMeshManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 15152ae6e1..4578a39a1f 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -83,13 +83,13 @@ void MultiMeshManager::register_child_mesh( long new_child_id = long(m_children.size()); auto child_to_parent_handle = - child_mesh.register_attribute("map_to_parent", child_primitive_type, 10); + child_mesh.register_attribute("map_to_parent", child_primitive_type, 10, false, -1); // TODO: make sure that this attribute doesnt already exist auto parent_to_child_handle = my_mesh.register_attribute( fmt::format("map_to_child_{}", new_child_id), child_primitive_type, - 10); + 10, false, -1); auto child_to_parent_accessor = child_mesh.create_accessor(child_to_parent_handle); From b2690d0c70ae74e6dd2bde230b2db4731f7db945 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Thu, 5 Oct 2023 13:27:18 -0400 Subject: [PATCH 20/25] adding some convenience functions sto start manually testing multimesh attributes --- src/wmtk/Mesh.hpp | 15 +- src/wmtk/MultiMeshManager.cpp | 27 +++- src/wmtk/MultiMeshManager.hpp | 3 + src/wmtk/attribute/MeshAttributes.cpp | 19 ++- src/wmtk/attribute/MeshAttributes.hpp | 8 +- tests/CMakeLists.txt | 2 +- tests/test_multi_mesh.cpp | 203 +++++++++++++++++--------- 7 files changed, 188 insertions(+), 89 deletions(-) diff --git a/src/wmtk/Mesh.hpp b/src/wmtk/Mesh.hpp index afd0065377..0b330b29cc 100644 --- a/src/wmtk/Mesh.hpp +++ b/src/wmtk/Mesh.hpp @@ -99,8 +99,12 @@ class Mesh : public std::enable_shared_from_this PrimitiveType type, long size, bool replace = false, - T default_value = T(0) - ); + T default_value = T(0)); + + template + bool has_attribute( + const std::string& name, + const PrimitiveType ptype) const; // block standard topology tools template MeshAttributeHandle get_attribute_handle( @@ -416,6 +420,13 @@ MeshAttributeHandle Mesh::get_attribute_handle( r.m_primitive_type = ptype; return r; } + +template +bool Mesh::has_attribute(const std::string& name, const PrimitiveType ptype) const +{ + return m_attribute_manager.get(ptype).has_attribute(name); +} + template long Mesh::get_attribute_dimension(const MeshAttributeHandle& handle) const { diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 4578a39a1f..cac747b7d5 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -82,23 +82,25 @@ void MultiMeshManager::register_child_mesh( PrimitiveType child_primitive_type = child_mesh.top_simplex_type(); long new_child_id = long(m_children.size()); - auto child_to_parent_handle = - child_mesh.register_attribute("map_to_parent", child_primitive_type, 10, false, -1); + auto child_to_parent_handle = child_mesh.register_attribute( + child_to_parent_map_attribute_name(), + child_primitive_type, + 10, + false, + -1); // TODO: make sure that this attribute doesnt already exist auto parent_to_child_handle = my_mesh.register_attribute( - fmt::format("map_to_child_{}", new_child_id), + parent_to_child_map_attribute_name(new_child_id), child_primitive_type, - 10, false, -1); + 10, + false, + -1); auto child_to_parent_accessor = child_mesh.create_accessor(child_to_parent_handle); auto parent_to_child_accessor = my_mesh.create_accessor(parent_to_child_handle); - // default initialize the parent to child map which can have entries missing - for (long id = 0; id < my_mesh.capacity(child_primitive_type); ++id) { - multimesh::utils::write_tuple_map_attribute(parent_to_child_accessor, Tuple(), Tuple()); - } // register maps for (const auto& [my_tuple, child_tuple] : child_mesh_simplex_map) { multimesh::utils::write_tuple_map_attribute( @@ -445,4 +447,13 @@ std::vector> MultiMeshManager::same_simplex_dimension_surje } return ret; } + +std::string MultiMeshManager::parent_to_child_map_attribute_name(long index) +{ + return fmt::format("map_to_child_{}", index); +} +std::string MultiMeshManager::child_to_parent_map_attribute_name() +{ + return "map_to_parent"; +} } // namespace wmtk diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index 6eaf910d94..c384e494e6 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -149,6 +149,9 @@ class MultiMeshManager const std::vector& children() const { return m_children; } + static std::string parent_to_child_map_attribute_name(long index); + static std::string child_to_parent_map_attribute_name(); + private: // this is defined internally but is preferablly invoked through the multimesh free function static std::vector> same_simplex_dimension_surjection( diff --git a/src/wmtk/attribute/MeshAttributes.cpp b/src/wmtk/attribute/MeshAttributes.cpp index a052c18cfe..906dfe5083 100644 --- a/src/wmtk/attribute/MeshAttributes.cpp +++ b/src/wmtk/attribute/MeshAttributes.cpp @@ -53,8 +53,11 @@ void MeshAttributes::clear_current_scope() } } template -AttributeHandle -MeshAttributes::register_attribute(const std::string& name, long dimension, bool replace, T default_value) +AttributeHandle MeshAttributes::register_attribute( + const std::string& name, + long dimension, + bool replace, + T default_value) { assert(replace || m_handles.find(name) == m_handles.end()); @@ -79,6 +82,11 @@ AttributeHandle MeshAttributes::attribute_handle(const std::string& name) con { return m_handles.at(name); } +template +bool MeshAttributes::has_attribute(const std::string& name) const +{ + return m_handles.find(name) != m_handles.end(); +} template bool MeshAttributes::operator==(const MeshAttributes& other) const @@ -129,9 +137,10 @@ void MeshAttributes::reserve(const long size) } } template - long MeshAttributes::dimension(const AttributeHandle& handle) const { - return attribute(handle).dimension(); - } +long MeshAttributes::dimension(const AttributeHandle& handle) const +{ + return attribute(handle).dimension(); +} template class MeshAttributes; diff --git a/src/wmtk/attribute/MeshAttributes.hpp b/src/wmtk/attribute/MeshAttributes.hpp index 0aaad07f51..15f9f8795c 100644 --- a/src/wmtk/attribute/MeshAttributes.hpp +++ b/src/wmtk/attribute/MeshAttributes.hpp @@ -37,8 +37,11 @@ class MeshAttributes void serialize(const int dim, MeshWriter& writer) const; - [[nodiscard]] AttributeHandle - register_attribute(const std::string& name, long dimension, bool replace = false, T default_value = T(0)); + [[nodiscard]] AttributeHandle register_attribute( + const std::string& name, + long dimension, + bool replace = false, + T default_value = T(0)); long reserved_size() const; void reserve(const long size); @@ -53,6 +56,7 @@ class MeshAttributes protected: AttributeHandle attribute_handle(const std::string& name) const; + bool has_attribute(const std::string& name) const; Attribute& attribute(const AttributeHandle& handle); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c2ded9b176..69df6ecdd1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,7 +23,7 @@ set(TEST_SOURCES test_accessor.cpp test_example_meshes.cpp test_3d_operations.cpp - #test_multi_mesh.cpp + test_multi_mesh.cpp tools/DEBUG_PointMesh.hpp tools/DEBUG_TriMesh.hpp tools/DEBUG_TriMesh.cpp diff --git a/tests/test_multi_mesh.cpp b/tests/test_multi_mesh.cpp index 9bc96ac2de..4e7f04bc4f 100644 --- a/tests/test_multi_mesh.cpp +++ b/tests/test_multi_mesh.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "tools/DEBUG_TriMesh.hpp" #include "tools/TriMesh_examples.hpp" @@ -17,58 +18,117 @@ constexpr PrimitiveType PV = PrimitiveType::Vertex; constexpr PrimitiveType PE = PrimitiveType::Edge; constexpr PrimitiveType PF = PrimitiveType::Face; + +namespace { +class DEBUG_MultiMeshManager : public MultiMeshManager +{ +public: + using MultiMeshManager::child_to_parent_map_attribute_name; + using MultiMeshManager::children; + using MultiMeshManager::parent_to_child_map_attribute_name; +}; +} // namespace + + TEST_CASE("test_register_child_mesh", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); std::shared_ptr child0_ptr = std::make_shared(single_triangle()); - auto child0_map = multimesh::same_simplex_dimension_surjection(*parent, *child0_ptr, {0}); std::shared_ptr child1_ptr = std::make_shared(one_ear()); - auto child1_map = multimesh::same_simplex_dimension_surjection(*parent, *child1_ptr, {0, 1}); - - parent.register_child_mesh(child0_ptr, child0_map); - parent.register_child_mesh(child1_ptr, child1_map); - - const auto& p_mul_manager = parent.multi_mesh_manager(); - REQUIRE(p_mul_manager.m_children.size() == 2); - REQUIRE(p_mul_manager.m_children[0] == child0_ptr); - REQUIRE(p_mul_manager.m_children[1] == child1_ptr); - - auto [tuple1, tuple2] = multimesh::utils::read_tuple_map_attribute_slow( - p_mul_manager.map_to_child_handles[0], - parent, - parent.tuple_from_id(PF, 0)); - REQUIRE(tuple1 == parent.tuple_from_id(PF, 0)); - REQUIRE(tuple2 == child0_ptr->tuple_from_id(PF, 0)); - - auto [tuple3, tuple4] = multimesh::utils::read_tuple_map_attribute_slow( - p_mul_manager.map_to_child_handles[0], - parent, - parent.tuple_from_id(PF, 1)); - REQUIRE(!tuple3.is_null()); - REQUIRE(tuple4.is_null()); - auto c2_mul_manager = child1_ptr->multi_mesh_manager; + auto& child0 = *child0_ptr; + auto& child1 = *child1_ptr; - REQUIRE(c2_mul_manager.is_parent_mesh() == false); - REQUIRE(c2_mul_manager.child_id() == 1); - - auto [tuple5, tuple6] = multimesh::utils::read_tuple_map_attribute_slow( - c2_mul_manager.map_to_parent_handle, - *child1_ptr, - child1_ptr->tuple_from_id(PF, 1)); + auto child0_map = multimesh::same_simplex_dimension_surjection(parent, child0, {2}); + auto child1_map = multimesh::same_simplex_dimension_surjection(parent, child1, {0, 1}); - REQUIRE(tuple5 == child1_ptr->tuple_from_id(PF, 1)); - REQUIRE(tuple6 == parent.tuple_from_id(PF, 1)); + parent.register_child_mesh(child0_ptr, child0_map); + parent.register_child_mesh(child1_ptr, child1_map); - REQUIRE(p_mul_manager.is_map_valid(parent) == true); + const auto& p_mul_manager = + reinterpret_cast(parent.multi_mesh_manager()); + REQUIRE(p_mul_manager.children().size() == 2); + REQUIRE(p_mul_manager.children()[0].mesh == child0_ptr); + REQUIRE(p_mul_manager.children()[1].mesh == child1_ptr); + + + // test id computation + REQUIRE(parent.absolute_multi_mesh_id().empty()); + REQUIRE(child0.absolute_multi_mesh_id() == std::vector{{0}}); + REQUIRE(child1.absolute_multi_mesh_id() == std::vector{{1}}); + + // test attribute contents + { + const std::string c_to_p_name = + DEBUG_MultiMeshManager::child_to_parent_map_attribute_name(); + ; + const std::string p_to_c0_name = + DEBUG_MultiMeshManager::parent_to_child_map_attribute_name(0); + const std::string p_to_c1_name = + DEBUG_MultiMeshManager::parent_to_child_map_attribute_name(1); + REQUIRE(parent.has_attribute(p_to_c0_name, PF)); + REQUIRE(parent.has_attribute(p_to_c1_name, PF)); + REQUIRE(child0.has_attribute(c_to_p_name, PF)); + REQUIRE(child1.has_attribute(c_to_p_name, PF)); + + auto parent_to_child0_handle = parent.get_attribute_handle(p_to_c0_name, PF); + auto parent_to_child1_handle = parent.get_attribute_handle(p_to_c1_name, PF); + auto child0_to_parent_handle = child0.get_attribute_handle(c_to_p_name, PF); + auto child1_to_parent_handle = child1.get_attribute_handle(c_to_p_name, PF); + + auto parent_to_child0_acc = parent.create_const_accessor(parent_to_child0_handle); + auto parent_to_child1_acc = parent.create_const_accessor(parent_to_child1_handle); + auto child0_to_parent_acc = child0.create_const_accessor(child0_to_parent_handle); + auto child1_to_parent_acc = child1.create_const_accessor(child1_to_parent_handle); + } + + // test actual api calls + { + // try the tuples that should succeed + for (const auto& [pt, ct] : child0_map) { + auto ncts = parent.map_to_child_tuples(child0, Simplex(PrimitiveType::Face, pt)); + REQUIRE(ncts.size() == 1); + auto nct = ncts[0]; + auto npt = child0.map_to_parent_tuple(Simplex(PrimitiveType::Face, ct)); + + CHECK(nct == ct); + CHECK(npt == pt); + } + for (const auto& [pt, ct] : child1_map) { + auto ncts = parent.map_to_child_tuples(child1, Simplex(PrimitiveType::Face, pt)); + REQUIRE(ncts.size() == 1); + auto nct = ncts[0]; + auto npt = child1.map_to_parent_tuple(Simplex(PrimitiveType::Face, ct)); + + CHECK(nct == ct); + CHECK(npt == pt); + } + + + // go through simplex indices that aren't available in the map + for (long index = 1; index < 3; ++index) { + auto pt = parent.tuple_from_id(PF, index); + auto ncts = parent.map_to_child(child0, Simplex(PrimitiveType::Face, pt)); + CHECK(ncts.size() == 0); + } + for (long index = 2; index < 3; ++index) { + auto pt = parent.tuple_from_id(PF, index); + auto ncts = parent.map_to_child(child1, Simplex(PrimitiveType::Face, pt)); + CHECK(ncts.size() == 0); + } + } + + + // REQUIRE(p_mul_manager.is_map_valid(parent) == true); } +/* TEST_CASE("test_multi_mesh_navigation", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); - std::shared_ptr child0_ptr = std::make_shared(single_triangle()); - std::vector child0_map = {0}; + std::shared_ptr child0_ptr = +std::make_shared(single_triangle()); std::vector child0_map = {0}; std::shared_ptr child1_ptr = std::make_shared(one_ear()); std::vector child1_map = {0, 1}; std::shared_ptr child2_ptr = @@ -96,19 +156,19 @@ TEST_CASE("test_multi_mesh_navigation", "[multimesh][2D]") parent.multi_mesh_manager.map_to_child_handles[2], edge); - CHECK(edge_child0 == child0_ptr->edge_tuple_between_v1_v2(1, 0, 0)); - CHECK(edge_child1 == child1_ptr->edge_tuple_between_v1_v2(1, 0, 0)); + CHECK(edge_child0 == child0.edge_tuple_between_v1_v2(1, 0, 0)); + CHECK(edge_child1 == child1.edge_tuple_between_v1_v2(1, 0, 0)); CHECK(edge_child2 == child2_ptr->edge_tuple_between_v1_v2(1, 0, 0)); CHECK( - child0_ptr->switch_vertex(edge_child0) == + child0.switch_vertex(edge_child0) == MultiMeshManager::map_tuple_between_meshes( parent, *child0_ptr, parent.multi_mesh_manager.map_to_child_handles[0], parent.switch_vertex(edge))); CHECK( - child1_ptr->switch_vertex(edge_child1) == + child1.switch_vertex(edge_child1) == MultiMeshManager::map_tuple_between_meshes( parent, *child1_ptr, @@ -123,14 +183,14 @@ TEST_CASE("test_multi_mesh_navigation", "[multimesh][2D]") parent.switch_vertex(edge))); CHECK( - child0_ptr->switch_edge(edge_child0) == + child0.switch_edge(edge_child0) == MultiMeshManager::map_tuple_between_meshes( parent, *child0_ptr, parent.multi_mesh_manager.map_to_child_handles[0], parent.switch_edge(edge))); CHECK( - child1_ptr->switch_edge(edge_child1) == + child1.switch_edge(edge_child1) == MultiMeshManager::map_tuple_between_meshes( parent, *child1_ptr, @@ -148,8 +208,8 @@ TEST_CASE("test_multi_mesh_navigation", "[multimesh][2D]") TEST_CASE("test_split_multi_mesh", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); - std::shared_ptr child0_ptr = std::make_shared(single_triangle()); - std::vector child0_map = {0}; + std::shared_ptr child0_ptr = +std::make_shared(single_triangle()); std::vector child0_map = {0}; std::shared_ptr child1_ptr = std::make_shared(one_ear()); std::vector child1_map = {0, 1}; std::shared_ptr child2_ptr = @@ -167,8 +227,8 @@ TEST_CASE("test_split_multi_mesh", "[multimesh][2D]") executor.split_edge(); REQUIRE(parent.is_connectivity_valid()); - REQUIRE(child0_ptr->is_connectivity_valid()); - REQUIRE(child1_ptr->is_connectivity_valid()); + REQUIRE(child0.is_connectivity_valid()); + REQUIRE(child1.is_connectivity_valid()); REQUIRE(child2_ptr->is_connectivity_valid()); REQUIRE(parent.multi_mesh_manager.is_map_valid(parent) == true); @@ -177,12 +237,12 @@ TEST_CASE("test_split_multi_mesh", "[multimesh][2D]") CHECK(parent.fv_from_fid(4) == Eigen::Matrix(0, 5, 2)); CHECK(parent.fv_from_fid(5) == Eigen::Matrix(3, 1, 5)); CHECK(parent.fv_from_fid(6) == Eigen::Matrix(3, 5, 0)); - CHECK(child0_ptr->fv_from_fid(1) == Eigen::Matrix(3, 1, 2)); - CHECK(child0_ptr->fv_from_fid(2) == Eigen::Matrix(0, 3, 2)); - CHECK(child1_ptr->fv_from_fid(2) == Eigen::Matrix(4, 1, 2)); - CHECK(child1_ptr->fv_from_fid(3) == Eigen::Matrix(0, 4, 2)); - CHECK(child1_ptr->fv_from_fid(4) == Eigen::Matrix(3, 1, 4)); - CHECK(child1_ptr->fv_from_fid(5) == Eigen::Matrix(3, 4, 0)); + CHECK(child0.fv_from_fid(1) == Eigen::Matrix(3, 1, 2)); + CHECK(child0.fv_from_fid(2) == Eigen::Matrix(0, 3, 2)); + CHECK(child1.fv_from_fid(2) == Eigen::Matrix(4, 1, 2)); + CHECK(child1.fv_from_fid(3) == Eigen::Matrix(0, 4, 2)); + CHECK(child1.fv_from_fid(4) == Eigen::Matrix(3, 1, 4)); + CHECK(child1.fv_from_fid(5) == Eigen::Matrix(3, 4, 0)); CHECK(child2_ptr->fv_from_fid(2) == Eigen::Matrix(0, 2, 4)); CHECK(child2_ptr->fv_from_fid(3) == Eigen::Matrix(7, 1, 2)); CHECK(child2_ptr->fv_from_fid(4) == Eigen::Matrix(0, 7, 2)); @@ -195,8 +255,8 @@ TEST_CASE("test_split_multi_mesh", "[multimesh][2D]") executor1.split_edge(); REQUIRE(parent.is_connectivity_valid()); - REQUIRE(child0_ptr->is_connectivity_valid()); - REQUIRE(child1_ptr->is_connectivity_valid()); + REQUIRE(child0.is_connectivity_valid()); + REQUIRE(child1.is_connectivity_valid()); REQUIRE(child2_ptr->is_connectivity_valid()); REQUIRE(parent.multi_mesh_manager.is_map_valid(parent) == true); @@ -208,16 +268,16 @@ TEST_CASE("test_split_multi_mesh", "[multimesh][2D]") CHECK(parent.fv_from_fid(9) == Eigen::Matrix(3, 6, 0)); CHECK(parent.fv_from_fid(10) == Eigen::Matrix(3, 5, 6)); - CHECK(child0_ptr->fv_from_fid(1) == Eigen::Matrix(3, 1, 2)); - CHECK(child0_ptr->fv_from_fid(3) == Eigen::Matrix(0, 4, 2)); - CHECK(child0_ptr->fv_from_fid(4) == Eigen::Matrix(4, 3, 2)); + CHECK(child0.fv_from_fid(1) == Eigen::Matrix(3, 1, 2)); + CHECK(child0.fv_from_fid(3) == Eigen::Matrix(0, 4, 2)); + CHECK(child0.fv_from_fid(4) == Eigen::Matrix(4, 3, 2)); - CHECK(child1_ptr->fv_from_fid(2) == Eigen::Matrix(4, 1, 2)); - CHECK(child1_ptr->fv_from_fid(4) == Eigen::Matrix(3, 1, 4)); - CHECK(child1_ptr->fv_from_fid(6) == Eigen::Matrix(0, 5, 2)); - CHECK(child1_ptr->fv_from_fid(7) == Eigen::Matrix(5, 4, 2)); - CHECK(child1_ptr->fv_from_fid(8) == Eigen::Matrix(3, 5, 0)); - CHECK(child1_ptr->fv_from_fid(9) == Eigen::Matrix(3, 4, 5)); + CHECK(child1.fv_from_fid(2) == Eigen::Matrix(4, 1, 2)); + CHECK(child1.fv_from_fid(4) == Eigen::Matrix(3, 1, 4)); + CHECK(child1.fv_from_fid(6) == Eigen::Matrix(0, 5, 2)); + CHECK(child1.fv_from_fid(7) == Eigen::Matrix(5, 4, 2)); + CHECK(child1.fv_from_fid(8) == Eigen::Matrix(3, 5, 0)); + CHECK(child1.fv_from_fid(9) == Eigen::Matrix(3, 4, 5)); CHECK(child2_ptr->fv_from_fid(2) == Eigen::Matrix(0, 2, 4)); CHECK(child2_ptr->fv_from_fid(3) == Eigen::Matrix(7, 1, 2)); @@ -231,8 +291,8 @@ TEST_CASE("test_split_multi_mesh", "[multimesh][2D]") TEST_CASE("test_collapse_multi_mesh", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); - std::shared_ptr child0_ptr = std::make_shared(two_neighbors()); - std::vector child0_map = {0, 1, 2}; + std::shared_ptr child0_ptr = +std::make_shared(two_neighbors()); std::vector child0_map = {0, 1, 2}; std::shared_ptr child1_ptr = std::make_shared(one_ear()); std::vector child1_map = {0, 1}; std::shared_ptr child2_ptr = @@ -250,17 +310,18 @@ TEST_CASE("test_collapse_multi_mesh", "[multimesh][2D]") executor.collapse_edge(); REQUIRE(parent.is_connectivity_valid()); - REQUIRE(child0_ptr->is_connectivity_valid()); - REQUIRE(child1_ptr->is_connectivity_valid()); + REQUIRE(child0.is_connectivity_valid()); + REQUIRE(child1.is_connectivity_valid()); REQUIRE(child2_ptr->is_connectivity_valid()); REQUIRE(parent.multi_mesh_manager.is_map_valid(parent) == true); CHECK(parent.fv_from_fid(1) == Eigen::Matrix(3, 2, 0)); CHECK(parent.fv_from_fid(2) == Eigen::Matrix(0, 2, 4)); - CHECK(child0_ptr->fv_from_fid(1) == Eigen::Matrix(3, 2, 0)); - CHECK(child0_ptr->fv_from_fid(2) == Eigen::Matrix(0, 2, 4)); - CHECK(child1_ptr->fv_from_fid(1) == Eigen::Matrix(3, 2, 0)); + CHECK(child0.fv_from_fid(1) == Eigen::Matrix(3, 2, 0)); + CHECK(child0.fv_from_fid(2) == Eigen::Matrix(0, 2, 4)); + CHECK(child1.fv_from_fid(1) == Eigen::Matrix(3, 2, 0)); CHECK(child2_ptr->fv_from_fid(1) == Eigen::Matrix(3, 5, 6)); CHECK(child2_ptr->fv_from_fid(2) == Eigen::Matrix(0, 2, 4)); } +*/ From deaccdadec4482f811ff9b376a98b8d82419d7dd Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Thu, 5 Oct 2023 18:23:13 -0400 Subject: [PATCH 21/25] enabled multimeshmanager registration unit and fixed identity initialization order --- src/wmtk/MultiMeshManager.cpp | 18 +++--- src/wmtk/MultiMeshManager.hpp | 3 +- tests/test_multi_mesh.cpp | 110 ++++++++++++++++++++++++++++++++-- 3 files changed, 117 insertions(+), 14 deletions(-) diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index cac747b7d5..28af7a44c0 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -72,7 +72,7 @@ std::vector MultiMeshManager::absolute_id() const void MultiMeshManager::register_child_mesh( Mesh& my_mesh, const std::shared_ptr& child_mesh_ptr, - const std::vector>& child_mesh_simplex_map) + const std::vector>& child_tuple_my_tuple_map) { assert(&my_mesh.m_multi_mesh_manager == this); assert(bool(child_mesh_ptr)); @@ -102,13 +102,13 @@ void MultiMeshManager::register_child_mesh( auto parent_to_child_accessor = my_mesh.create_accessor(parent_to_child_handle); // register maps - for (const auto& [my_tuple, child_tuple] : child_mesh_simplex_map) { + for (const auto& [child_tuple, my_tuple] : child_tuple_my_tuple_map) { multimesh::utils::write_tuple_map_attribute( - child_to_parent_accessor, + parent_to_child_accessor, my_tuple, child_tuple); multimesh::utils::write_tuple_map_attribute( - parent_to_child_accessor, + child_to_parent_accessor, child_tuple, my_tuple); } @@ -132,16 +132,16 @@ void MultiMeshManager::register_child_mesh( const std::vector& child_mesh_simplex_id_map) { PrimitiveType map_type = child_mesh->top_simplex_type(); - std::vector> child_mesh_simplex_map; + std::vector> child_tuple_my_tuple_map; for (long child_cell_id = 0; child_cell_id < long(child_mesh_simplex_id_map.size()); ++child_cell_id) { long parent_cell_id = child_mesh_simplex_id_map[child_cell_id]; - child_mesh_simplex_map.push_back( + child_tuple_my_tuple_map.push_back( {child_mesh->tuple_from_id(map_type, child_cell_id), my_mesh.tuple_from_id(map_type, parent_cell_id)}); } - register_child_mesh(my_mesh, child_mesh, child_mesh_simplex_map); + register_child_mesh(my_mesh, child_mesh, child_tuple_my_tuple_map); } */ @@ -439,11 +439,11 @@ std::vector> MultiMeshManager::same_simplex_dimension_surje if ((parent_flag_accessor.const_scalar_attribute(pt) & 1) == 0) { continue; } - if ((child_flag_accessor.const_scalar_attribute(pt) & 1) == 0) { + if ((child_flag_accessor.const_scalar_attribute(ct) & 1) == 0) { continue; } - ret.emplace_back(std::array{{pt, ct}}); + ret.emplace_back(std::array{{ct, pt}}); } return ret; } diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index c384e494e6..c16efa6c09 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -40,10 +40,11 @@ class MultiMeshManager // register child_meshes and the map from child_meshes to this mesh, child_mesh_simplex + // void register_child_mesh( Mesh& my_mesh, const std::shared_ptr& child_mesh, - const std::vector>& child_mesh_simplex_map); + const std::vector>& child_tuple_my_tuple_map); // bool are_maps_valid(const Mesh& my_mesh) const; diff --git a/tests/test_multi_mesh.cpp b/tests/test_multi_mesh.cpp index 4e7f04bc4f..2cf61b9bbf 100644 --- a/tests/test_multi_mesh.cpp +++ b/tests/test_multi_mesh.cpp @@ -25,6 +25,7 @@ class DEBUG_MultiMeshManager : public MultiMeshManager public: using MultiMeshManager::child_to_parent_map_attribute_name; using MultiMeshManager::children; + using MultiMeshManager::is_root; using MultiMeshManager::parent_to_child_map_attribute_name; }; } // namespace @@ -48,9 +49,19 @@ TEST_CASE("test_register_child_mesh", "[multimesh][2D]") const auto& p_mul_manager = reinterpret_cast(parent.multi_mesh_manager()); + const auto& c0_mul_manager = + reinterpret_cast(child0.multi_mesh_manager()); + const auto& c1_mul_manager = + reinterpret_cast(child1.multi_mesh_manager()); REQUIRE(p_mul_manager.children().size() == 2); REQUIRE(p_mul_manager.children()[0].mesh == child0_ptr); REQUIRE(p_mul_manager.children()[1].mesh == child1_ptr); + REQUIRE(c0_mul_manager.children().size() == 0); + REQUIRE(c1_mul_manager.children().size() == 0); + + REQUIRE(p_mul_manager.is_root()); + REQUIRE(!c0_mul_manager.is_root()); + REQUIRE(!c1_mul_manager.is_root()); // test id computation @@ -62,7 +73,6 @@ TEST_CASE("test_register_child_mesh", "[multimesh][2D]") { const std::string c_to_p_name = DEBUG_MultiMeshManager::child_to_parent_map_attribute_name(); - ; const std::string p_to_c0_name = DEBUG_MultiMeshManager::parent_to_child_map_attribute_name(0); const std::string p_to_c1_name = @@ -81,12 +91,104 @@ TEST_CASE("test_register_child_mesh", "[multimesh][2D]") auto parent_to_child1_acc = parent.create_const_accessor(parent_to_child1_handle); auto child0_to_parent_acc = child0.create_const_accessor(child0_to_parent_handle); auto child1_to_parent_acc = child1.create_const_accessor(child1_to_parent_handle); + + { + std::vector> p_to_c0_map{ + std::tuple{Tuple(), Tuple()}, + std::tuple{Tuple(), Tuple()}, + std::tuple{parent.tuple_from_id(PF, 2), child0.tuple_from_id(PF, 0)}}; + + std::vector> p_to_c1_map{ + std::tuple{parent.tuple_from_id(PF, 0), child1.tuple_from_id(PF, 0)}, + std::tuple{parent.tuple_from_id(PF, 1), child1.tuple_from_id(PF, 1)}, + std::tuple{Tuple(), Tuple()}, + }; + + std::vector> c0_to_p_map{ + std::tuple{child0.tuple_from_id(PF, 0), parent.tuple_from_id(PF, 2)}}; + + std::vector> c1_to_p_map{ + std::tuple{child1.tuple_from_id(PF, 0), parent.tuple_from_id(PF, 0)}, + std::tuple{child1.tuple_from_id(PF, 1), parent.tuple_from_id(PF, 1)}}; + + + for (long parent_index = 0; parent_index < 3; ++parent_index) { + auto ptuple = parent.tuple_from_id(PF, parent_index); + auto p_to_c0_tuple_tuple = + multimesh::utils::read_tuple_map_attribute(parent_to_child0_acc, ptuple); + auto p_to_c1_tuple_tuple = + multimesh::utils::read_tuple_map_attribute(parent_to_child1_acc, ptuple); + + CHECK(p_to_c0_tuple_tuple == p_to_c0_map[parent_index]); + CHECK(p_to_c1_tuple_tuple == p_to_c1_map[parent_index]); + } + for (size_t child0_index = 0; child0_index < c0_to_p_map.size(); ++child0_index) { + auto tuple = child0.tuple_from_id(PF, child0_index); + auto c0_to_p_tuple_tuple = + multimesh::utils::read_tuple_map_attribute(child0_to_parent_acc, tuple); + + CHECK(c0_to_p_tuple_tuple == c0_to_p_map[child0_index]); + } + for (size_t child1_index = 0; child1_index < c1_to_p_map.size(); ++child1_index) { + auto tuple = child1.tuple_from_id(PF, child1_index); + auto c1_to_p_tuple_tuple = + multimesh::utils::read_tuple_map_attribute(child1_to_parent_acc, tuple); + + CHECK(c1_to_p_tuple_tuple == c1_to_p_map[child1_index]); + } + } + { + std::vector p_to_c0_map{Tuple(), Tuple(), child0.tuple_from_id(PF, 0)}; + + std::vector p_to_c1_map{ + child1.tuple_from_id(PF, 0), + child1.tuple_from_id(PF, 1), + Tuple()}; + + std::vector c0_to_p_map{parent.tuple_from_id(PF, 2)}; + + std::vector c1_to_p_map{ + parent.tuple_from_id(PF, 0), + parent.tuple_from_id(PF, 1)}; + + + for (long parent_index = 0; parent_index < 3; ++parent_index) { + auto ptuple = parent.tuple_from_id(PF, parent_index); + Simplex psimplex = Simplex(PF, ptuple); + + Tuple c0_expected = p_to_c0_map[parent_index]; + if (!c0_expected.is_null()) { + auto c0tuples = parent.map_to_child_tuples(child0, psimplex); + REQUIRE(c0tuples.size() == 1); + CHECK(c0tuples[0] == c0_expected); + } + + Tuple c1_expected = p_to_c1_map[parent_index]; + if (!c1_expected.is_null()) { + auto c1tuples = parent.map_to_child_tuples(child1, psimplex); + REQUIRE(c1tuples.size() == 1); + CHECK(c1tuples[0] == c1_expected); + } + } + for (size_t child0_index = 0; child0_index < c0_to_p_map.size(); ++child0_index) { + auto tuple = child0.tuple_from_id(PF, child0_index); + Simplex csimplex = Simplex(PF, tuple); + auto ptuple = child0.map_to_parent_tuple(csimplex); + CHECK(ptuple == c0_to_p_map[child0_index]); + } + for (size_t child1_index = 0; child1_index < c1_to_p_map.size(); ++child1_index) { + auto tuple = child1.tuple_from_id(PF, child1_index); + Simplex csimplex = Simplex(PF, tuple); + auto ptuple = child1.map_to_parent_tuple(csimplex); + CHECK(ptuple == c1_to_p_map[child1_index]); + } + } } // test actual api calls { // try the tuples that should succeed - for (const auto& [pt, ct] : child0_map) { + for (const auto& [ct, pt] : child0_map) { auto ncts = parent.map_to_child_tuples(child0, Simplex(PrimitiveType::Face, pt)); REQUIRE(ncts.size() == 1); auto nct = ncts[0]; @@ -95,7 +197,7 @@ TEST_CASE("test_register_child_mesh", "[multimesh][2D]") CHECK(nct == ct); CHECK(npt == pt); } - for (const auto& [pt, ct] : child1_map) { + for (const auto& [ct, pt] : child1_map) { auto ncts = parent.map_to_child_tuples(child1, Simplex(PrimitiveType::Face, pt)); REQUIRE(ncts.size() == 1); auto nct = ncts[0]; @@ -107,7 +209,7 @@ TEST_CASE("test_register_child_mesh", "[multimesh][2D]") // go through simplex indices that aren't available in the map - for (long index = 1; index < 3; ++index) { + for (long index = 0; index < 2; ++index) { auto pt = parent.tuple_from_id(PF, index); auto ncts = parent.map_to_child(child0, Simplex(PrimitiveType::Face, pt)); CHECK(ncts.size() == 0); From 1415a9388cda7e16e839edecd0a3a62272ee5d9a Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Thu, 5 Oct 2023 20:19:24 -0400 Subject: [PATCH 22/25] adding some more unit tests on mulmanager --- src/wmtk/MultiMeshManager.cpp | 110 ------------------------- tests/test_multi_mesh.cpp | 22 ++--- tests/tools/DEBUG_MultiMeshManager.cpp | 110 +++++++++++++++++++++++++ tests/tools/DEBUG_MultiMeshManager.hpp | 13 +++ tests/tools/DEBUG_TriMesh.hpp | 6 +- 5 files changed, 134 insertions(+), 127 deletions(-) create mode 100644 tests/tools/DEBUG_MultiMeshManager.cpp create mode 100644 tests/tools/DEBUG_MultiMeshManager.hpp diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 28af7a44c0..04c0b179b4 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -307,116 +307,6 @@ std::vector MultiMeshManager::map_to_child( } -// bool MultiMeshManager::is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const -//{ -// assert(&my_mesh.m_multi_mesh_manager == this); -// // TODO: implement this -// -// return true; -//} -// -// std::vector MultiMeshManager::map_edge_tuple_to_all_children( -// const Mesh& my_mesh, -// const Tuple& edge_tuple) -//{ -// assert(&my_mesh.m_multi_mesh_manager == this); -// std::vector ret; -// for (const auto& child_data : m_children) { -// const Mesh& child_mesh = *child_data.mesh; -// const auto map_to_child_handle = child_data.map_handle; -// Tuple child_tuple = -// map_tuple_between_meshes(my_mesh, child_mesh, map_to_child_handle, edge_tuple); -// ret.push_back(child_tuple); -// } -// return ret; -//} - -/* -bool MultiMeshManager::is_map_valid(const Mesh& my_mesh) const -{ - assert(&my_mesh.m_multi_mesh_manager == this); - for (size_t index = 0; index < m_children.size(); ++index) { - const auto& child_data = m_children[index]; - if (child_data.mesh->mesh_manager.m_child_id != index) { - return false; - } - if (!is_child_map_valid(my_mesh, child_data)) { - return false; - } - } - return true; -} -bool MultiMeshManager::is_child_map_valid(const Mesh& my_mesh, const ChildData& child_data) const -{ - assert(&my_mesh.m_multi_mesh_manager == this); - const Mesh& child_mesh = *child_data.mesh; - const auto parent_to_child_handle = child_data.map_handle; - PrimitiveType map_type = child_mesh.top_simplex_type(); - - auto child_to_parent_handle = child_mesh.m_multi_mesh_manager.map_to_parent_handle; - auto child_cell_flag_accessor = child_mesh.get_flag_accessor(map_type); - - for (const child_tuple : child_mesh.get_simplices(map_type)) { - // 1. test if all maps in child_mesh exisits - auto [child_tuple_from_child, parent_tuple_from_child] = - read_tuple_map_attribute(child_to_parent_handle, child_mesh, child_tuple); - - // 2. test if tuples in maps are valid (and up_to_date) - { - if (!child_mesh.is_valid_slow(child_tuple_from_child)) { - return false; - } - if (!my_mesh.is_valid_slow(parent_tuple_from_child)) { - return false; - } - } - - // 3. test if map is symmetric - { - auto [parent_tuple_from_parent, child_tuple_from_parent] = - read_tuple_map_attribute(parent_to_child_handle, my_mesh, parent_tuple); - - if (child_tuple_from_child != child_tuple_from_parent || - parent_tuple_from_child != parent_tuple_from_parent) { - return false; - } - } - - // 4. test switch_top_simplex operation - // for 4, current code support only mapping between triangle meshes - if (map_type == PrimitiveType::Face && my_mesh.top_simplex_type() == PrimitiveType::Face) { - Tuple cur_child_tuple = child_tuple; - Tuple cur_parent_tuple = parent_tuple; - - for (int i = 0; i < 3; i++) { - if (!child_mesh_ptr->is_boundary(cur_child_tuple)) { - if (my_mesh.is_boundary(cur_parent_tuple)) { - return false; - } - - Tuple child_tuple_opp = child_mesh.switch_face(cur_child_tuple); - Tuple parent_tuple_opp = my_mesh.switch_face(cur_parent_tuple); - - if (parent_tuple_opp != map_tuple_between_meshes( - *child_mesh_ptr, - my_mesh, - child_to_parent_handle, - child_tuple_opp)) { - return false; - } - } - cur_child_tuple = - child_mesh_ptr->switch_edge(child_mesh_ptr->switch_vertex(cur_child_tuple)); - cur_parent_tuple = my_mesh.switch_edge(my_mesh.switch_vertex(cur_parent_tuple)); - } - } else { - // TODO: implement other cases - continue; - } - } - return true; -} -*/ std::vector> MultiMeshManager::same_simplex_dimension_surjection( const Mesh& parent, const Mesh& child, diff --git a/tests/test_multi_mesh.cpp b/tests/test_multi_mesh.cpp index 2cf61b9bbf..9f0577aa41 100644 --- a/tests/test_multi_mesh.cpp +++ b/tests/test_multi_mesh.cpp @@ -19,16 +19,7 @@ constexpr PrimitiveType PE = PrimitiveType::Edge; constexpr PrimitiveType PF = PrimitiveType::Face; -namespace { -class DEBUG_MultiMeshManager : public MultiMeshManager -{ -public: - using MultiMeshManager::child_to_parent_map_attribute_name; - using MultiMeshManager::children; - using MultiMeshManager::is_root; - using MultiMeshManager::parent_to_child_map_attribute_name; -}; -} // namespace +namespace {} // namespace TEST_CASE("test_register_child_mesh", "[multimesh][2D]") @@ -47,17 +38,16 @@ TEST_CASE("test_register_child_mesh", "[multimesh][2D]") parent.register_child_mesh(child0_ptr, child0_map); parent.register_child_mesh(child1_ptr, child1_map); - const auto& p_mul_manager = - reinterpret_cast(parent.multi_mesh_manager()); - const auto& c0_mul_manager = - reinterpret_cast(child0.multi_mesh_manager()); - const auto& c1_mul_manager = - reinterpret_cast(child1.multi_mesh_manager()); + const auto& p_mul_manager = parent.multi_mesh_manager(); + const auto& c0_mul_manager = child0.multi_mesh_manager(); + const auto& c1_mul_manager = child1.multi_mesh_manager(); REQUIRE(p_mul_manager.children().size() == 2); REQUIRE(p_mul_manager.children()[0].mesh == child0_ptr); REQUIRE(p_mul_manager.children()[1].mesh == child1_ptr); REQUIRE(c0_mul_manager.children().size() == 0); REQUIRE(c1_mul_manager.children().size() == 0); + REQUIRE(&c0_mul_manager.get_root_mesh(child0) == &parent); + REQUIRE(&c1_mul_manager.get_root_mesh(child1) == &parent); REQUIRE(p_mul_manager.is_root()); REQUIRE(!c0_mul_manager.is_root()); diff --git a/tests/tools/DEBUG_MultiMeshManager.cpp b/tests/tools/DEBUG_MultiMeshManager.cpp new file mode 100644 index 0000000000..a2022033ef --- /dev/null +++ b/tests/tools/DEBUG_MultiMeshManager.cpp @@ -0,0 +1,110 @@ + +bool DEBUG_MultiMeshManager::is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const +{ + assert(&my_mesh.m_multi_mesh_manager == this); + // TODO: implement this + + return true; +} + +std::vector DEBUG_MultiMeshManager::map_edge_tuple_to_all_children( + const Mesh& my_mesh, + const Tuple& edge_tuple) +{ + assert(&my_mesh.m_multi_mesh_manager == this); + std::vector ret; + for (const auto& child_data : m_children) { + const Mesh& child_mesh = *child_data.mesh; + const auto map_to_child_handle = child_data.map_handle; + Tuple child_tuple = + map_tuple_between_meshes(my_mesh, child_mesh, map_to_child_handle, edge_tuple); + ret.push_back(child_tuple); + } + return ret; +} + +bool DEBUG_MultiMeshManager::is_map_valid(const Mesh& my_mesh) const +{ + assert(&my_mesh.m_multi_mesh_manager == this); + for (size_t index = 0; index < m_children.size(); ++index) { + const auto& child_data = m_children[index]; + if (child_data.mesh->mesh_manager.m_child_id != index) { + return false; + } + if (!is_child_map_valid(my_mesh, child_data)) { + return false; + } + } + return true; +} +bool DEBUG_MultiMeshManager::is_child_map_valid(const Mesh& my_mesh, const ChildData& child_data) + const +{ + assert(&my_mesh.m_multi_mesh_manager == this); + const Mesh& child_mesh = *child_data.mesh; + const auto parent_to_child_handle = child_data.map_handle; + PrimitiveType map_type = child_mesh.top_simplex_type(); + + auto child_to_parent_handle = child_mesh.m_multi_mesh_manager.map_to_parent_handle; + auto child_cell_flag_accessor = child_mesh.get_flag_accessor(map_type); + + for (const child_tuple : child_mesh.get_simplices(map_type)) { + // 1. test if all maps in child_mesh exisits + auto [child_tuple_from_child, parent_tuple_from_child] = + read_tuple_map_attribute(child_to_parent_handle, child_mesh, child_tuple); + + // 2. test if tuples in maps are valid (and up_to_date) + { + if (!child_mesh.is_valid_slow(child_tuple_from_child)) { + return false; + } + if (!my_mesh.is_valid_slow(parent_tuple_from_child)) { + return false; + } + } + + // 3. test if map is symmetric + { + auto [parent_tuple_from_parent, child_tuple_from_parent] = + read_tuple_map_attribute(parent_to_child_handle, my_mesh, parent_tuple); + + if (child_tuple_from_child != child_tuple_from_parent || + parent_tuple_from_child != parent_tuple_from_parent) { + return false; + } + } + + // 4. test switch_top_simplex operation + // for 4, current code support only mapping between triangle meshes + if (map_type == PrimitiveType::Face && my_mesh.top_simplex_type() == PrimitiveType::Face) { + Tuple cur_child_tuple = child_tuple; + Tuple cur_parent_tuple = parent_tuple; + + for (int i = 0; i < 3; i++) { + if (!child_mesh_ptr->is_boundary(cur_child_tuple)) { + if (my_mesh.is_boundary(cur_parent_tuple)) { + return false; + } + + Tuple child_tuple_opp = child_mesh.switch_face(cur_child_tuple); + Tuple parent_tuple_opp = my_mesh.switch_face(cur_parent_tuple); + + if (parent_tuple_opp != map_tuple_between_meshes( + *child_mesh_ptr, + my_mesh, + child_to_parent_handle, + child_tuple_opp)) { + return false; + } + } + cur_child_tuple = + child_mesh_ptr->switch_edge(child_mesh_ptr->switch_vertex(cur_child_tuple)); + cur_parent_tuple = my_mesh.switch_edge(my_mesh.switch_vertex(cur_parent_tuple)); + } + } else { + // TODO: implement other cases + continue; + } + } + return true; +} diff --git a/tests/tools/DEBUG_MultiMeshManager.hpp b/tests/tools/DEBUG_MultiMeshManager.hpp new file mode 100644 index 0000000000..9ce1155f6a --- /dev/null +++ b/tests/tools/DEBUG_MultiMeshManager.hpp @@ -0,0 +1,13 @@ +#include + +namespace wmtk::tests { + +class DEBUG_MultiMeshManager : public MultiMeshManager +{ +public: + using MultiMeshManager::child_to_parent_map_attribute_name; + using MultiMeshManager::children; + using MultiMeshManager::is_root; + using MultiMeshManager::parent_to_child_map_attribute_name; +}; +} // namespace wmtk::tests diff --git a/tests/tools/DEBUG_TriMesh.hpp b/tests/tools/DEBUG_TriMesh.hpp index e493a94fe9..62fc6e80e6 100644 --- a/tests/tools/DEBUG_TriMesh.hpp +++ b/tests/tools/DEBUG_TriMesh.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include "DEBUG_MultiMeshManager.hpp" namespace wmtk::tests { class DEBUG_TriMesh : public TriMesh @@ -17,7 +18,10 @@ class DEBUG_TriMesh : public TriMesh // uses spdlog to print out a variety of information about the mesh void print_state() const; - MultiMeshManager& multi_mesh_manager() { return m_multi_mesh_manager; } + DEBUG_MultiMeshManager& multi_mesh_manager() + { + return reinterpret_cast(m_multi_mesh_manager); + } void print_vf() const; Eigen::Matrix fv_from_fid(const long fid) const; From 256a3c2d8582c872ad5eeefeb828de4b5f0d6c91 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Fri, 6 Oct 2023 01:33:51 -0400 Subject: [PATCH 23/25] old multimesh validation now in DEBUG_Multimeshmanager --- src/wmtk/MultiMeshManager.hpp | 16 ++-- tests/CMakeLists.txt | 5 ++ tests/test_multi_mesh.cpp | 2 +- tests/tools/DEBUG_Mesh.cpp | 30 +++++++ tests/tools/DEBUG_Mesh.hpp | 52 ++++++++++++ tests/tools/DEBUG_MultiMeshManager.cpp | 106 +++++++++++-------------- tests/tools/DEBUG_MultiMeshManager.hpp | 7 ++ tests/tools/DEBUG_TriMesh.hpp | 2 +- 8 files changed, 151 insertions(+), 69 deletions(-) create mode 100644 tests/tools/DEBUG_Mesh.cpp create mode 100644 tests/tools/DEBUG_Mesh.hpp diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index c16efa6c09..b1b088b56b 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -93,13 +93,7 @@ class MultiMeshManager const Mesh& get_root_mesh(const Mesh& my_mesh) const; Mesh& get_root_mesh(Mesh& my_mesh); -private: - Mesh* m_parent = nullptr; - // only valid if this is teh child of some other mesh - // store the map to the base_tuple of the my_mesh - MeshAttributeHandle map_to_parent_handle; - long m_child_id = -1; - +protected: struct ChildData { std::shared_ptr mesh; @@ -110,6 +104,14 @@ class MultiMeshManager MeshAttributeHandle map_handle; }; +private: + Mesh* m_parent = nullptr; + // only valid if this is teh child of some other mesh + // store the map to the base_tuple of the my_mesh + MeshAttributeHandle map_to_parent_handle; + long m_child_id = -1; + + // Child Meshes std::vector m_children; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c67c9e6505..5f011cddab 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,6 +34,11 @@ set(TEST_SOURCES tools/TetMesh_examples.cpp tools/DEBUG_TetMesh.hpp tools/DEBUG_TetMesh.cpp + + tools/DEBUG_Mesh.hpp + tools/DEBUG_Mesh.cpp + tools/DEBUG_MultiMeshManager.hpp + tools/DEBUG_MultiMeshManager.cpp ) add_executable(wmtk_tests ${TEST_SOURCES}) diff --git a/tests/test_multi_mesh.cpp b/tests/test_multi_mesh.cpp index 9f0577aa41..2278ee9997 100644 --- a/tests/test_multi_mesh.cpp +++ b/tests/test_multi_mesh.cpp @@ -212,7 +212,7 @@ TEST_CASE("test_register_child_mesh", "[multimesh][2D]") } - // REQUIRE(p_mul_manager.is_map_valid(parent) == true); + p_mul_manager.check_map_valid(parent); } /* diff --git a/tests/tools/DEBUG_Mesh.cpp b/tests/tools/DEBUG_Mesh.cpp new file mode 100644 index 0000000000..b9c8365b04 --- /dev/null +++ b/tests/tools/DEBUG_Mesh.cpp @@ -0,0 +1,30 @@ +#include "DEBUG_Mesh.hpp" +#include + +namespace wmtk::tests { + + +bool DEBUG_Mesh::operator==(const DEBUG_Mesh& o) const +{ + return static_cast(*this) == static_cast(o); +} +bool DEBUG_Mesh::operator!=(const DEBUG_Mesh& o) const +{ + return !(*this == o); +} + + +void DEBUG_Mesh::print_state() const {} + + +void DEBUG_Mesh::reserve_attributes(PrimitiveType type, long size) +{ + Mesh::reserve_attributes(type, size); +} + + +Accessor DEBUG_Mesh::get_cell_hash_accessor() +{ + return Mesh::get_cell_hash_accessor(); +} +} // namespace wmtk::tests diff --git a/tests/tools/DEBUG_Mesh.hpp b/tests/tools/DEBUG_Mesh.hpp new file mode 100644 index 0000000000..dc248a801c --- /dev/null +++ b/tests/tools/DEBUG_Mesh.hpp @@ -0,0 +1,52 @@ + +#pragma once +#include +#include "DEBUG_Mesh.hpp" +#include "DEBUG_MultiMeshManager.hpp" + +namespace wmtk::tests { +class DEBUG_Mesh : public virtual Mesh +{ +public: + using Mesh::Mesh; + bool operator==(const DEBUG_Mesh& o) const; + bool operator!=(const DEBUG_Mesh& o) const; + + // uses spdlog to print out a variety of information about the mesh + void print_state() const; + DEBUG_MultiMeshManager& multi_mesh_manager() + { + return reinterpret_cast(m_multi_mesh_manager); + } + const DEBUG_MultiMeshManager& multi_mesh_manager() const + { + return reinterpret_cast(m_multi_mesh_manager); + } + + template + attribute::AccessorBase create_base_accessor(const MeshAttributeHandle& handle) + { + return attribute::AccessorBase(*this, handle); + } + + template + attribute::AccessorBase create_const_base_accessor( + const MeshAttributeHandle& handle) const + { + return attribute::AccessorBase(const_cast(*this), handle); + } + template + attribute::AccessorBase create_base_accessor(const MeshAttributeHandle& handle) const + { + return create_const_base_accessor(handle); + } + + void reserve_attributes(PrimitiveType type, long size); + + + using Mesh::tuple_from_id; + + Accessor get_cell_hash_accessor(); +}; + +} // namespace wmtk::tests diff --git a/tests/tools/DEBUG_MultiMeshManager.cpp b/tests/tools/DEBUG_MultiMeshManager.cpp index a2022033ef..38bf4c341d 100644 --- a/tests/tools/DEBUG_MultiMeshManager.cpp +++ b/tests/tools/DEBUG_MultiMeshManager.cpp @@ -1,104 +1,90 @@ +#include "DEBUG_MultiMeshManager.hpp" +#include +#include +#include +#include "DEBUG_Mesh.hpp" -bool DEBUG_MultiMeshManager::is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const + +namespace wmtk::tests { +void DEBUG_MultiMeshManager::check_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) + const { - assert(&my_mesh.m_multi_mesh_manager == this); // TODO: implement this - - return true; } -std::vector DEBUG_MultiMeshManager::map_edge_tuple_to_all_children( - const Mesh& my_mesh, - const Tuple& edge_tuple) -{ - assert(&my_mesh.m_multi_mesh_manager == this); - std::vector ret; - for (const auto& child_data : m_children) { - const Mesh& child_mesh = *child_data.mesh; - const auto map_to_child_handle = child_data.map_handle; - Tuple child_tuple = - map_tuple_between_meshes(my_mesh, child_mesh, map_to_child_handle, edge_tuple); - ret.push_back(child_tuple); - } - return ret; -} -bool DEBUG_MultiMeshManager::is_map_valid(const Mesh& my_mesh) const +void DEBUG_MultiMeshManager::check_map_valid(const Mesh& my_mesh) const { - assert(&my_mesh.m_multi_mesh_manager == this); - for (size_t index = 0; index < m_children.size(); ++index) { - const auto& child_data = m_children[index]; - if (child_data.mesh->mesh_manager.m_child_id != index) { - return false; - } - if (!is_child_map_valid(my_mesh, child_data)) { - return false; - } + for (long index = 0; index < long(children().size()); ++index) { + const auto& child_data = children()[index]; + REQUIRE(bool(child_data.mesh)); + REQUIRE(child_data.mesh->absolute_multi_mesh_id().front() == index); + check_child_map_valid(my_mesh, child_data); } - return true; } -bool DEBUG_MultiMeshManager::is_child_map_valid(const Mesh& my_mesh, const ChildData& child_data) +void DEBUG_MultiMeshManager::check_child_map_valid(const Mesh& my_mesh, const ChildData& child_data) const { - assert(&my_mesh.m_multi_mesh_manager == this); const Mesh& child_mesh = *child_data.mesh; const auto parent_to_child_handle = child_data.map_handle; PrimitiveType map_type = child_mesh.top_simplex_type(); - auto child_to_parent_handle = child_mesh.m_multi_mesh_manager.map_to_parent_handle; + const std::string c_to_p_name = child_to_parent_map_attribute_name(); + + REQUIRE(child_mesh.has_attribute(c_to_p_name, map_type)); + auto child_to_parent_handle = child_mesh.get_attribute_handle(c_to_p_name, map_type); auto child_cell_flag_accessor = child_mesh.get_flag_accessor(map_type); - for (const child_tuple : child_mesh.get_simplices(map_type)) { + for (const Tuple& child_tuple : child_mesh.get_all(map_type)) { // 1. test if all maps in child_mesh exisits auto [child_tuple_from_child, parent_tuple_from_child] = - read_tuple_map_attribute(child_to_parent_handle, child_mesh, child_tuple); + multimesh::utils::read_tuple_map_attribute_slow( + child_mesh, + child_to_parent_handle, + child_tuple); // 2. test if tuples in maps are valid (and up_to_date) { - if (!child_mesh.is_valid_slow(child_tuple_from_child)) { - return false; - } - if (!my_mesh.is_valid_slow(parent_tuple_from_child)) { - return false; - } + CHECK(child_mesh.is_valid_slow(child_tuple_from_child)); + CHECK(my_mesh.is_valid_slow(parent_tuple_from_child)); } // 3. test if map is symmetric { auto [parent_tuple_from_parent, child_tuple_from_parent] = - read_tuple_map_attribute(parent_to_child_handle, my_mesh, parent_tuple); + multimesh::utils::read_tuple_map_attribute_slow( + my_mesh, + parent_to_child_handle, + parent_tuple_from_child); - if (child_tuple_from_child != child_tuple_from_parent || - parent_tuple_from_child != parent_tuple_from_parent) { - return false; - } + CHECK( + (child_tuple_from_child == child_tuple_from_parent && + parent_tuple_from_child == parent_tuple_from_parent)); } // 4. test switch_top_simplex operation // for 4, current code support only mapping between triangle meshes if (map_type == PrimitiveType::Face && my_mesh.top_simplex_type() == PrimitiveType::Face) { Tuple cur_child_tuple = child_tuple; - Tuple cur_parent_tuple = parent_tuple; + Tuple cur_parent_tuple = parent_tuple_from_child; + auto child_to_parent_accessor = + child_mesh.create_const_accessor(child_to_parent_handle); for (int i = 0; i < 3; i++) { - if (!child_mesh_ptr->is_boundary(cur_child_tuple)) { - if (my_mesh.is_boundary(cur_parent_tuple)) { - return false; - } + if (!child_mesh.is_boundary(cur_child_tuple)) { + REQUIRE(!my_mesh.is_boundary(cur_parent_tuple)); Tuple child_tuple_opp = child_mesh.switch_face(cur_child_tuple); Tuple parent_tuple_opp = my_mesh.switch_face(cur_parent_tuple); - if (parent_tuple_opp != map_tuple_between_meshes( - *child_mesh_ptr, + CHECK( + parent_tuple_opp == map_tuple_between_meshes( + child_mesh, my_mesh, - child_to_parent_handle, - child_tuple_opp)) { - return false; - } + child_to_parent_accessor, + child_tuple_opp)); } - cur_child_tuple = - child_mesh_ptr->switch_edge(child_mesh_ptr->switch_vertex(cur_child_tuple)); + cur_child_tuple = child_mesh.switch_edge(child_mesh.switch_vertex(cur_child_tuple)); cur_parent_tuple = my_mesh.switch_edge(my_mesh.switch_vertex(cur_parent_tuple)); } } else { @@ -106,5 +92,5 @@ bool DEBUG_MultiMeshManager::is_child_map_valid(const Mesh& my_mesh, const Child continue; } } - return true; } +} // namespace wmtk::tests diff --git a/tests/tools/DEBUG_MultiMeshManager.hpp b/tests/tools/DEBUG_MultiMeshManager.hpp index 9ce1155f6a..fecc8425a6 100644 --- a/tests/tools/DEBUG_MultiMeshManager.hpp +++ b/tests/tools/DEBUG_MultiMeshManager.hpp @@ -1,3 +1,4 @@ +#pragma once #include namespace wmtk::tests { @@ -9,5 +10,11 @@ class DEBUG_MultiMeshManager : public MultiMeshManager using MultiMeshManager::children; using MultiMeshManager::is_root; using MultiMeshManager::parent_to_child_map_attribute_name; + + + // these run catch2 tests + void check_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const; + void check_map_valid(const Mesh& my_mesh) const; + void check_child_map_valid(const Mesh& my_mesh, const ChildData& child_data) const; }; } // namespace wmtk::tests diff --git a/tests/tools/DEBUG_TriMesh.hpp b/tests/tools/DEBUG_TriMesh.hpp index 62fc6e80e6..e1c0cebcb2 100644 --- a/tests/tools/DEBUG_TriMesh.hpp +++ b/tests/tools/DEBUG_TriMesh.hpp @@ -4,7 +4,7 @@ #include "DEBUG_MultiMeshManager.hpp" namespace wmtk::tests { -class DEBUG_TriMesh : public TriMesh +class DEBUG_TriMesh : public TriMesh //, public virtual DEBUG_Mesh { public: using TriMesh::TriMesh; From 195c9fcb92292db1a8cd74f74b7982d04b8a6193 Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Fri, 6 Oct 2023 01:43:59 -0400 Subject: [PATCH 24/25] rejuvenated 2d multimesh navigation --- tests/test_multi_mesh.cpp | 108 ++++++++++++++------------------------ 1 file changed, 38 insertions(+), 70 deletions(-) diff --git a/tests/test_multi_mesh.cpp b/tests/test_multi_mesh.cpp index 2278ee9997..ec8868cc26 100644 --- a/tests/test_multi_mesh.cpp +++ b/tests/test_multi_mesh.cpp @@ -215,93 +215,61 @@ TEST_CASE("test_register_child_mesh", "[multimesh][2D]") p_mul_manager.check_map_valid(parent); } -/* TEST_CASE("test_multi_mesh_navigation", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); - std::shared_ptr child0_ptr = -std::make_shared(single_triangle()); std::vector child0_map = {0}; + std::shared_ptr child0_ptr = std::make_shared(single_triangle()); std::shared_ptr child1_ptr = std::make_shared(one_ear()); - std::vector child1_map = {0, 1}; std::shared_ptr child2_ptr = std::make_shared(two_neighbors_cut_on_edge01()); - std::vector child2_map = {0, 1, 2}; - MultiMeshManager::register_child_mesh(parent, child0_ptr, child0_map); - MultiMeshManager::register_child_mesh(parent, child1_ptr, child1_map); - MultiMeshManager::register_child_mesh(parent, child2_ptr, child2_map); + auto& child0 = *child0_ptr; + auto& child1 = *child1_ptr; + auto& child2 = *child2_ptr; + + auto child0_map = multimesh::same_simplex_dimension_surjection(parent, child0, {0}); + auto child1_map = multimesh::same_simplex_dimension_surjection(parent, child1, {0, 1}); + auto child2_map = multimesh::same_simplex_dimension_surjection(parent, child2, {0, 1, 2}); + + parent.register_child_mesh(child0_ptr, child0_map); + parent.register_child_mesh(child1_ptr, child1_map); + parent.register_child_mesh(child2_ptr, child2_map); + + + auto get_single_child_tuple = [&](const auto& mesh, const auto& tuple) -> Tuple { + auto tups = parent.map_to_child_tuples(mesh, Simplex(PF, tuple)); + REQUIRE(tups.size() == 1); + return tups[0]; + }; Tuple edge = parent.edge_tuple_between_v1_v2(1, 0, 0); - Tuple edge_child0 = MultiMeshManager::map_tuple_between_meshes( - parent, - *child0_ptr, - parent.multi_mesh_manager.map_to_child_handles[0], - edge); - Tuple edge_child1 = MultiMeshManager::map_tuple_between_meshes( - parent, - *child1_ptr, - parent.multi_mesh_manager.map_to_child_handles[1], - edge); - Tuple edge_child2 = MultiMeshManager::map_tuple_between_meshes( - parent, - *child2_ptr, - parent.multi_mesh_manager.map_to_child_handles[2], - edge); + Tuple edge_child0 = get_single_child_tuple(child0, edge); + Tuple edge_child1 = get_single_child_tuple(child1, edge); + Tuple edge_child2 = get_single_child_tuple(child2, edge); CHECK(edge_child0 == child0.edge_tuple_between_v1_v2(1, 0, 0)); CHECK(edge_child1 == child1.edge_tuple_between_v1_v2(1, 0, 0)); CHECK(edge_child2 == child2_ptr->edge_tuple_between_v1_v2(1, 0, 0)); - CHECK( - child0.switch_vertex(edge_child0) == - MultiMeshManager::map_tuple_between_meshes( - parent, - *child0_ptr, - parent.multi_mesh_manager.map_to_child_handles[0], - parent.switch_vertex(edge))); - CHECK( - child1.switch_vertex(edge_child1) == - MultiMeshManager::map_tuple_between_meshes( - parent, - *child1_ptr, - parent.multi_mesh_manager.map_to_child_handles[1], - parent.switch_vertex(edge))); - CHECK( - child2_ptr->switch_vertex(edge_child2) == - MultiMeshManager::map_tuple_between_meshes( - parent, - *child2_ptr, - parent.multi_mesh_manager.map_to_child_handles[2], - parent.switch_vertex(edge))); - - CHECK( - child0.switch_edge(edge_child0) == - MultiMeshManager::map_tuple_between_meshes( - parent, - *child0_ptr, - parent.multi_mesh_manager.map_to_child_handles[0], - parent.switch_edge(edge))); - CHECK( - child1.switch_edge(edge_child1) == - MultiMeshManager::map_tuple_between_meshes( - parent, - *child1_ptr, - parent.multi_mesh_manager.map_to_child_handles[1], - parent.switch_edge(edge))); - CHECK( - child2_ptr->switch_edge(edge_child2) == - MultiMeshManager::map_tuple_between_meshes( - parent, - *child2_ptr, - parent.multi_mesh_manager.map_to_child_handles[2], - parent.switch_edge(edge))); + for (PrimitiveType pt : {PV, PE}) { + CHECK( + child0.switch_tuple(edge_child0, pt) == + get_single_child_tuple(child0, parent.switch_tuple(edge, pt))); + CHECK( + child1.switch_tuple(edge_child1, pt) == + get_single_child_tuple(child1, parent.switch_tuple(edge, pt))); + CHECK( + child2.switch_tuple(edge_child2, pt) == + get_single_child_tuple(child2, parent.switch_tuple(edge, pt))); + } } +/* TEST_CASE("test_split_multi_mesh", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); - std::shared_ptr child0_ptr = -std::make_shared(single_triangle()); std::vector child0_map = {0}; + std::shared_ptr child0_ptr = std::make_shared(single_triangle()); + std::vector child0_map = {0}; std::shared_ptr child1_ptr = std::make_shared(one_ear()); std::vector child1_map = {0, 1}; std::shared_ptr child2_ptr = @@ -383,8 +351,8 @@ std::make_shared(single_triangle()); std::vector child0_map TEST_CASE("test_collapse_multi_mesh", "[multimesh][2D]") { DEBUG_TriMesh parent = two_neighbors(); - std::shared_ptr child0_ptr = -std::make_shared(two_neighbors()); std::vector child0_map = {0, 1, 2}; + std::shared_ptr child0_ptr = std::make_shared(two_neighbors()); + std::vector child0_map = {0, 1, 2}; std::shared_ptr child1_ptr = std::make_shared(one_ear()); std::vector child1_map = {0, 1}; std::shared_ptr child2_ptr = From ac0b795bec5d9e49705478ec443dfc041d12a0ac Mon Sep 17 00:00:00 2001 From: Michael Tao Date: Sat, 7 Oct 2023 02:18:44 -0400 Subject: [PATCH 25/25] comments and constness type changes frm daniel comments --- src/wmtk/MultiMeshManager.cpp | 40 ++++++++++++++++++----------------- src/wmtk/MultiMeshManager.hpp | 8 ++----- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/wmtk/MultiMeshManager.cpp b/src/wmtk/MultiMeshManager.cpp index 04c0b179b4..c714d43dd1 100644 --- a/src/wmtk/MultiMeshManager.cpp +++ b/src/wmtk/MultiMeshManager.cpp @@ -20,7 +20,7 @@ Tuple MultiMeshManager::map_tuple_between_meshes( PrimitiveType min_primitive_type = std::min(source_mesh_primitive_type, target_mesh_primitive_type); - auto [source_mesh_base_tuple, target_mesh_base_tuple] = + const auto [source_mesh_base_tuple, target_mesh_base_tuple] = multimesh::utils::read_tuple_map_attribute(map_accessor, source_tuple); if (source_mesh_base_tuple.is_null() || target_mesh_base_tuple.is_null()) { @@ -74,28 +74,31 @@ void MultiMeshManager::register_child_mesh( const std::shared_ptr& child_mesh_ptr, const std::vector>& child_tuple_my_tuple_map) { - assert(&my_mesh.m_multi_mesh_manager == this); + assert((&my_mesh.m_multi_mesh_manager) == this); assert(bool(child_mesh_ptr)); Mesh& child_mesh = *child_mesh_ptr; - PrimitiveType child_primitive_type = child_mesh.top_simplex_type(); - long new_child_id = long(m_children.size()); + const PrimitiveType child_primitive_type = child_mesh.top_simplex_type(); + const long new_child_id = long(m_children.size()); + + constexpr static long TWO_TUPLE_SIZE = 10; + constexpr static long DEFAULT_TUPLES_VALUES = -1; auto child_to_parent_handle = child_mesh.register_attribute( child_to_parent_map_attribute_name(), child_primitive_type, - 10, + TWO_TUPLE_SIZE, false, - -1); + DEFAULT_TUPLES_VALUES); // TODO: make sure that this attribute doesnt already exist auto parent_to_child_handle = my_mesh.register_attribute( parent_to_child_map_attribute_name(new_child_id), child_primitive_type, - 10, + TWO_TUPLE_SIZE, false, - -1); + DEFAULT_TUPLES_VALUES); auto child_to_parent_accessor = child_mesh.create_accessor(child_to_parent_handle); @@ -147,7 +150,7 @@ void MultiMeshManager::register_child_mesh( const Mesh& MultiMeshManager::get_root_mesh(const Mesh& my_mesh) const { - if (m_parent == nullptr) { + if (is_root()) { return my_mesh; } else { return m_parent->m_multi_mesh_manager.get_root_mesh(*m_parent); @@ -155,7 +158,7 @@ const Mesh& MultiMeshManager::get_root_mesh(const Mesh& my_mesh) const } Mesh& MultiMeshManager::get_root_mesh(Mesh& my_mesh) { - if (m_parent == nullptr) { + if (is_root()) { return my_mesh; } else { return m_parent->m_multi_mesh_manager.get_root_mesh(*m_parent); @@ -175,19 +178,17 @@ std::vector MultiMeshManager::map_tuples( const Simplex& my_simplex) const { const PrimitiveType pt = my_simplex.primitive_type(); - assert(&my_mesh.m_multi_mesh_manager == this); - // TODO: construct relative positions + assert((&my_mesh.m_multi_mesh_manager) == this); std::vector equivalent_tuples = simplex::top_level_cofaces_tuples(my_mesh, my_simplex); - // TODO: construct visitor class that maps up and down // MultiMeshMapVisitor visitor(my_mesh, other_mesh); // const auto my_id = absolute_id(); someday could be used to map down const auto other_id = other_mesh.absolute_multi_mesh_id(); - // TODO: visitor runs along meshes traversing the path - // get a root tuple + // get a root tuple by converting the tuple up parent meshes until root is found Tuple cur_tuple = my_simplex.tuple(); const Mesh* cur_mesh = &my_mesh; - while (cur_mesh != nullptr) { + while (cur_mesh != + nullptr) { // cur_mesh == nullptr if we just walked past the root node so we stop cur_tuple = cur_mesh->m_multi_mesh_manager.map_tuple_to_parent_tuple(*cur_mesh, cur_tuple); cur_mesh = cur_mesh->m_multi_mesh_manager.m_parent; } @@ -241,7 +242,7 @@ Tuple MultiMeshManager::map_to_parent_tuple(const Mesh& my_mesh, const Simplex& Tuple MultiMeshManager::map_tuple_to_parent_tuple(const Mesh& my_mesh, const Tuple& my_tuple) const { - assert(&my_mesh.m_multi_mesh_manager == this); + assert((&my_mesh.m_multi_mesh_manager) == this); assert(!is_root()); const Mesh& parent_mesh = *m_parent; @@ -257,11 +258,12 @@ std::vector MultiMeshManager::map_to_child_tuples( const ChildData& child_data, const Simplex& my_simplex) const { - assert(&my_mesh.m_multi_mesh_manager == this); + assert((&my_mesh.m_multi_mesh_manager) == this); const Mesh& child_mesh = *child_data.mesh; const auto map_handle = child_data.map_handle; - // we will rewrite these tuples inline with the mapped ones + // we will overwrite these tuples inline with the mapped ones while running down the map + // functionalities std::vector tuples = simplex::top_level_cofaces_tuples(my_mesh, my_simplex); auto map_accessor = my_mesh.create_accessor(map_handle); diff --git a/src/wmtk/MultiMeshManager.hpp b/src/wmtk/MultiMeshManager.hpp index b1b088b56b..7e380bc88f 100644 --- a/src/wmtk/MultiMeshManager.hpp +++ b/src/wmtk/MultiMeshManager.hpp @@ -61,6 +61,8 @@ class MultiMeshManager // if K < J // if M == K then it is one to many // if M < K then it is many to many + // + // Note also that functions that end with _tuple or _tuples willl return tuples rather than simplices //=========== // Simplex maps @@ -136,12 +138,6 @@ class MultiMeshManager map_to_child_tuples(const Mesh& my_mesh, long child_id, const Simplex& simplex) const; - //// helper function to check if this mesh is a valid child_mesh of my_mesh - //// i.e. the connectivity of this mesh is a subset of this in my_mesh - // bool is_child_mesh_valid(const Mesh& my_mesh, const Mesh& child_mesh) const; - - //// checks that the map is consistent - // bool is_child_map_valid(const Mesh& my_mesh, const ChildData& child) const; static Tuple map_tuple_between_meshes(