diff --git a/src/wmtk/Mesh.hpp b/src/wmtk/Mesh.hpp index a7ddb8aab3..5d8894e447 100644 --- a/src/wmtk/Mesh.hpp +++ b/src/wmtk/Mesh.hpp @@ -89,6 +89,7 @@ template class MultiMeshVisitorExecutor; namespace utils { + class MapValidator; namespace internal { class TupleTag; } @@ -121,8 +122,7 @@ class Mesh : public std::enable_shared_from_this, public wmtk::utils::Merk friend class multimesh::MultiMeshSimplexVisitorExecutor; template friend class multimesh::MultiMeshVisitor; - friend bool multimesh::utils::check_child_maps_valid(const Mesh& m); - friend bool multimesh::utils::check_parent_map_valid(const Mesh& m); + friend class multimesh::utils::MapValidator; template friend class multimesh::MultiMeshVisitorExecutor; friend class multimesh::attribute::AttributeScopeHandle; diff --git a/src/wmtk/multimesh/MultiMeshManager.hpp b/src/wmtk/multimesh/MultiMeshManager.hpp index 1a8b8de01e..63a8803507 100644 --- a/src/wmtk/multimesh/MultiMeshManager.hpp +++ b/src/wmtk/multimesh/MultiMeshManager.hpp @@ -13,6 +13,7 @@ #include "utils/check_map_valid.hpp" + namespace wmtk { class Mesh; @@ -38,6 +39,10 @@ class MultiMeshVisitor; template class MultiMeshVisitorExecutor; +namespace utils { + class MapValidator; +} + } // namespace multimesh class Mesh; namespace simplex { @@ -72,8 +77,7 @@ class MultiMeshManager : public wmtk::utils::MerkleTreeInteriorNode friend class multimesh::MultiMeshVisitorExecutor; friend class wmtk::HDF5Reader; - friend bool utils::check_child_maps_valid(const Mesh& m); - friend bool utils::check_parent_map_valid(const Mesh& m); + friend class utils::MapValidator; // @param the max dimension of the mesh we will get passed diff --git a/src/wmtk/multimesh/utils/CMakeLists.txt b/src/wmtk/multimesh/utils/CMakeLists.txt index 5d9486240d..33a180b497 100644 --- a/src/wmtk/multimesh/utils/CMakeLists.txt +++ b/src/wmtk/multimesh/utils/CMakeLists.txt @@ -25,5 +25,8 @@ set(SRC_FILES check_map_valid.cpp check_map_valid.hpp + + MapValidator.hpp + MapValidator.cpp ) target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) diff --git a/src/wmtk/multimesh/utils/MapValidator.cpp b/src/wmtk/multimesh/utils/MapValidator.cpp new file mode 100644 index 0000000000..2d51bf9161 --- /dev/null +++ b/src/wmtk/multimesh/utils/MapValidator.cpp @@ -0,0 +1,191 @@ + +#include "MapValidator.hpp" +#include +#include +#include +#include +#include +#include +#include +namespace wmtk::multimesh::utils { + +MapValidator::MapValidator(const Mesh& m) + : m_mesh(m) +{} +bool MapValidator::check_all() const +{ + bool ok = true; + ok &= check_parent_map_attribute_valid(); + ok &= check_child_map_attributes_valid(); + if (!ok) { + return ok; + } + ok &= check_switch_homomorphism(); + + return ok; +} + +bool MapValidator::check_child_map_attributes_valid() const +{ + bool ok = true; + for (const auto& [cptr, attr] : m_mesh.m_multi_mesh_manager.m_children) { + const auto& child = *cptr; + auto map_accessor = m_mesh.create_const_accessor(attr); + + for (int64_t j = 0; j < child.top_cell_dimension(); ++j) { + wmtk::PrimitiveType prim_type = wmtk::PrimitiveType(j); + + for (const auto& pt : m_mesh.get_all(prim_type)) { + wmtk::simplex::Simplex s(m_mesh, prim_type, pt); + + auto tups = simplex::top_dimension_cofaces_tuples(m_mesh, s); + + for (const auto& source_tuple : tups) { + 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()) { + if (source_mesh_base_tuple.is_null() && target_mesh_base_tuple.is_null()) { + ok = false; + wmtk::logger().error( + "Map from parent {} to child {} on tuple {} (dim {}) fails on {} " + "or " + "{} null", + fmt::join(m_mesh.absolute_multi_mesh_id(), ","), + fmt::join(child.absolute_multi_mesh_id(), ","), + j, + wmtk::utils::TupleInspector::as_string(pt), + wmtk::utils::TupleInspector::as_string(source_mesh_base_tuple), + wmtk::utils::TupleInspector::as_string(target_mesh_base_tuple) + + ); + } + } else if (!child.is_valid(target_mesh_base_tuple)) { + wmtk::logger().error( + "Map from parent {} to child {} on tuple {} (dim {}) fails on {} -> " + "{}", + fmt::join(m_mesh.absolute_multi_mesh_id(), ","), + fmt::join(child.absolute_multi_mesh_id(), ","), + j, + wmtk::utils::TupleInspector::as_string(pt), + wmtk::utils::TupleInspector::as_string(source_mesh_base_tuple), + wmtk::utils::TupleInspector::as_string(target_mesh_base_tuple) + + ); + ok = false; + } + } + } + } + } + return ok; +} + +bool MapValidator::check_parent_map_attribute_valid() const +{ + bool ok = true; + const auto& parent_ptr = m_mesh.m_multi_mesh_manager.m_parent; + if (parent_ptr == nullptr) { + return true; + } + const auto& attr = m_mesh.m_multi_mesh_manager.map_to_parent_handle; + const auto& parent = *parent_ptr; + auto map_accessor = m_mesh.create_const_accessor(attr); + + wmtk::PrimitiveType prim_type = m_mesh.top_simplex_type(); + + for (const auto& source_tuple : m_mesh.get_all(prim_type)) { + 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()) { + wmtk::logger().error( + "Map from child {} to parent {} on tuple {} (dim {}) has null entry {} -> " + "{}", + fmt::join(m_mesh.absolute_multi_mesh_id(), ","), + fmt::join(parent.absolute_multi_mesh_id(), ","), + m_mesh.top_cell_dimension(), + wmtk::utils::TupleInspector::as_string(source_tuple), + wmtk::utils::TupleInspector::as_string(source_mesh_base_tuple), + wmtk::utils::TupleInspector::as_string(target_mesh_base_tuple) + + ); + ok = false; + } else if (!parent.is_valid(target_mesh_base_tuple)) { + wmtk::logger().error( + "Map from child {} to parent {} on tuple {} (dim {}) fails on {} -> " + "{}", + fmt::join(m_mesh.absolute_multi_mesh_id(), ","), + fmt::join(parent.absolute_multi_mesh_id(), ","), + m_mesh.top_cell_dimension(), + wmtk::utils::TupleInspector::as_string(source_tuple), + wmtk::utils::TupleInspector::as_string(source_mesh_base_tuple), + wmtk::utils::TupleInspector::as_string(target_mesh_base_tuple) + + ); + ok = false; + } + } + return ok; +} + + +bool MapValidator::check_switch_homomorphism() const +{ + bool ok = true; + for (const auto& cptr : m_mesh.get_child_meshes()) { + ok &= check_child_switch_homomorphism(*cptr); + } + return ok; +} +bool MapValidator::check_child_switch_homomorphism(const Mesh& child) const +{ + assert(child.m_multi_mesh_manager.m_parent == &m_mesh); + bool ok = true; + for (PrimitiveType pt : wmtk::utils::primitive_below(child.top_simplex_type())) { + auto tups = child.get_all(pt); + for (const wmtk::Tuple& t : tups) { + wmtk::simplex::Simplex s(child, pt, t); + + wmtk::Tuple parent_tuple = child.map_to_parent_tuple(s); + for (PrimitiveType spt : wmtk::utils::primitive_below(child.top_simplex_type())) { + // skip switches over boundaries + if (spt == pt && + child.is_boundary(wmtk::PrimitiveType(child.top_cell_dimension() - 1), t)) { + continue; + } + + wmtk::simplex::Simplex switched_simplex(child, pt, m_mesh.switch_tuple(t, pt)); + wmtk::Tuple switch_map = child.map_to_parent_tuple(switched_simplex); + wmtk::Tuple map_switch = m_mesh.switch_tuple(parent_tuple, pt); + for (PrimitiveType my_pt : wmtk::utils::primitive_below(child.top_simplex_type())) { + bool worked = wmtk::simplex::utils::SimplexComparisons::equal( + m_mesh, + my_pt, + switch_map, + map_switch); + if (!worked) { + wmtk::logger().error( + "Map from child {0} to parent {1} on tuple {2} (dim {3}) fails on " + "switch(map({2}),{4}) = {5} != " + "map(switch({2},{4})) = {6} (dim {7} id {8} != {9})", + fmt::join(child.absolute_multi_mesh_id(), ","), // 0 + fmt::join(m_mesh.absolute_multi_mesh_id(), ","), // 1 + wmtk::utils::TupleInspector::as_string(t), // 2 + child.top_cell_dimension(), // 3 + primitive_type_name(pt), // 4 + wmtk::utils::TupleInspector::as_string(map_switch), // 5 + wmtk::utils::TupleInspector::as_string(switch_map), // 6 + primitive_type_name(my_pt), // 7 + m_mesh.id(map_switch, my_pt), // 8 + m_mesh.id(switch_map, my_pt) // 9 + ); + ok = false; + } + } + } + } + } + return ok; +} + + +} // namespace wmtk::multimesh::utils diff --git a/src/wmtk/multimesh/utils/MapValidator.hpp b/src/wmtk/multimesh/utils/MapValidator.hpp new file mode 100644 index 0000000000..6b69779cb2 --- /dev/null +++ b/src/wmtk/multimesh/utils/MapValidator.hpp @@ -0,0 +1,24 @@ +#pragma once +namespace wmtk { +class Mesh; +namespace multimesh { +class MultiMeshManager; +} +} // namespace wmtk + +namespace wmtk::multimesh::utils { + + class MapValidator { + public: + MapValidator(const Mesh& m); + bool check_child_map_attributes_valid() const ; + bool check_parent_map_attribute_valid() const ; + bool check_all() const; + + bool check_switch_homomorphism() const; + bool check_child_switch_homomorphism(const Mesh& child) const; + + private: + const Mesh& m_mesh; + }; +} diff --git a/src/wmtk/multimesh/utils/check_map_valid.cpp b/src/wmtk/multimesh/utils/check_map_valid.cpp index c96992b660..c0fe9a9a98 100644 --- a/src/wmtk/multimesh/utils/check_map_valid.cpp +++ b/src/wmtk/multimesh/utils/check_map_valid.cpp @@ -1,80 +1,23 @@ - #include #include #include #include #include +#include "MapValidator.hpp" namespace wmtk::multimesh::utils { +bool check_maps_valid(const Mesh& m) +{ + MapValidator validator(m); + return validator.check_all(); +} bool check_child_maps_valid(const Mesh& m) { - bool ok = true; - for (const auto& [cptr, attr] : m.m_multi_mesh_manager.m_children) { - const auto& child = *cptr; - auto map_accessor = m.create_const_accessor(attr); - - for (int64_t j = 0; j < child.top_cell_dimension(); ++j) { - wmtk::PrimitiveType prim_type = wmtk::PrimitiveType(j); - - for (const auto& pt : m.get_all(prim_type)) { - wmtk::simplex::Simplex s(m, prim_type, pt); - - auto tups = simplex::top_dimension_cofaces_tuples(m, s); - - for (const auto& source_tuple : tups) { - const auto [source_mesh_base_tuple, target_mesh_base_tuple] = - multimesh::utils::read_tuple_map_attribute(map_accessor, source_tuple); - if (!child.is_valid(target_mesh_base_tuple)) { - wmtk::logger().error( - "Map from parent {} to child {} on tuple {} (dim {}) fails on {} -> " - "{}", - fmt::join(m.absolute_multi_mesh_id(), ","), - fmt::join(child.absolute_multi_mesh_id(), ","), - j, - wmtk::utils::TupleInspector::as_string(pt), - wmtk::utils::TupleInspector::as_string(source_mesh_base_tuple), - wmtk::utils::TupleInspector::as_string(target_mesh_base_tuple) - - ); - ok = false; - } - } - } - } - } - return ok; + MapValidator validator(m); + return validator.check_child_map_attributes_valid(); } - bool check_parent_map_valid(const Mesh& m) { - bool ok = true; - const auto& parent_ptr = m.m_multi_mesh_manager.m_parent; - if (parent_ptr == nullptr) { - return true; - } - const auto& attr = m.m_multi_mesh_manager.map_to_parent_handle; - const auto& parent = *parent_ptr; - auto map_accessor = m.create_const_accessor(attr); - - wmtk::PrimitiveType prim_type = m.top_simplex_type(); - - for (const auto& source_tuple : m.get_all(prim_type)) { - const auto [source_mesh_base_tuple, target_mesh_base_tuple] = - multimesh::utils::read_tuple_map_attribute(map_accessor, source_tuple); - if (!parent.is_valid(target_mesh_base_tuple)) { - wmtk::logger().error( - "Map from child {} to parent {} on tuple {} (dim {}) fails on {} -> " - "{}", - fmt::join(m.absolute_multi_mesh_id(), ","), - fmt::join(parent.absolute_multi_mesh_id(), ","), - m.top_cell_dimension(), - wmtk::utils::TupleInspector::as_string(source_tuple), - wmtk::utils::TupleInspector::as_string(source_mesh_base_tuple), - wmtk::utils::TupleInspector::as_string(target_mesh_base_tuple) - - ); - ok = false; - } - } - return ok; + MapValidator validator(m); + return validator.check_child_map_attributes_valid(); } } // namespace wmtk::multimesh::utils diff --git a/src/wmtk/multimesh/utils/check_map_valid.hpp b/src/wmtk/multimesh/utils/check_map_valid.hpp index ec46a4dd52..60fcb5305d 100644 --- a/src/wmtk/multimesh/utils/check_map_valid.hpp +++ b/src/wmtk/multimesh/utils/check_map_valid.hpp @@ -8,7 +8,9 @@ class MultiMeshManager; } // namespace wmtk namespace wmtk::multimesh::utils { + +bool check_maps_valid(const Mesh& m); + bool check_child_maps_valid(const Mesh& m); bool check_parent_map_valid(const Mesh& m); - } // namespace wmtk::multimesh::utils diff --git a/tests/multimesh/test_multi_mesh.cpp b/tests/multimesh/test_multi_mesh.cpp index 203cc7864e..2864fb5497 100644 --- a/tests/multimesh/test_multi_mesh.cpp +++ b/tests/multimesh/test_multi_mesh.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include "../tools/DEBUG_Tuple.hpp" #include "../tools/EdgeMesh_examples.hpp" #include "../tools/TriMesh_examples.hpp" +#include using namespace wmtk; using namespace wmtk::tests; @@ -74,6 +76,7 @@ TEST_CASE("test_register_child_mesh_bijection", "[multimesh][2D]") REQUIRE(wmtk::multimesh::utils::check_child_maps_valid(parent)); REQUIRE(wmtk::multimesh::utils::check_child_maps_valid(child0)); REQUIRE(wmtk::multimesh::utils::check_child_maps_valid(child1)); + REQUIRE(wmtk::multimesh::utils::MapValidator(parent).check_all()); // some debug mode only checks #if !defined(NDEBUG) // chekc that it fails when the # simplices is wrong