Skip to content

Commit

Permalink
Merge pull request #773 from wildmeshing/mtao/check_map_valid_func
Browse files Browse the repository at this point in the history
adding a tool for checking if all tuples mapped are valid
  • Loading branch information
mtao authored Nov 5, 2024
2 parents 01b4d9e + a6055a6 commit c374150
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 72 deletions.
4 changes: 2 additions & 2 deletions src/wmtk/Mesh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ template <typename Visitor>
class MultiMeshVisitorExecutor;

namespace utils {
class MapValidator;
namespace internal {
class TupleTag;
}
Expand Down Expand Up @@ -121,8 +122,7 @@ class Mesh : public std::enable_shared_from_this<Mesh>, public wmtk::utils::Merk
friend class multimesh::MultiMeshSimplexVisitorExecutor;
template <typename NodeFunctor>
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 <typename Visitor>
friend class multimesh::MultiMeshVisitorExecutor;
friend class multimesh::attribute::AttributeScopeHandle;
Expand Down
8 changes: 6 additions & 2 deletions src/wmtk/multimesh/MultiMeshManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "utils/check_map_valid.hpp"



namespace wmtk {

class Mesh;
Expand All @@ -38,6 +39,10 @@ class MultiMeshVisitor;
template <typename Visitor>
class MultiMeshVisitorExecutor;

namespace utils {
class MapValidator;
}

} // namespace multimesh
class Mesh;
namespace simplex {
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/wmtk/multimesh/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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})
191 changes: 191 additions & 0 deletions src/wmtk/multimesh/utils/MapValidator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@

#include "MapValidator.hpp"
#include <wmtk/Mesh.hpp>
#include <wmtk/multimesh/utils/tuple_map_attribute_io.hpp>
#include <wmtk/simplex/top_dimension_cofaces.hpp>
#include <wmtk/simplex/utils/SimplexComparisons.hpp>
#include <wmtk/utils/Logger.hpp>
#include <wmtk/utils/TupleInspector.hpp>
#include <wmtk/utils/primitive_range.hpp>
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
24 changes: 24 additions & 0 deletions src/wmtk/multimesh/utils/MapValidator.hpp
Original file line number Diff line number Diff line change
@@ -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;
};
}
77 changes: 10 additions & 67 deletions src/wmtk/multimesh/utils/check_map_valid.cpp
Original file line number Diff line number Diff line change
@@ -1,80 +1,23 @@

#include <wmtk/Mesh.hpp>
#include <wmtk/multimesh/utils/tuple_map_attribute_io.hpp>
#include <wmtk/simplex/top_dimension_cofaces.hpp>
#include <wmtk/utils/Logger.hpp>
#include <wmtk/utils/TupleInspector.hpp>
#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
4 changes: 3 additions & 1 deletion src/wmtk/multimesh/utils/check_map_valid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions tests/multimesh/test_multi_mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <wmtk/multimesh/same_simplex_dimension_surjection.hpp>
#include <wmtk/multimesh/utils/check_map_valid.hpp>
#include <wmtk/multimesh/utils/tuple_map_attribute_io.hpp>
#include <wmtk/multimesh/utils/check_map_valid.hpp>
#include <wmtk/operations/EdgeCollapse.hpp>
#include <wmtk/operations/EdgeSplit.hpp>
#include <wmtk/simplex/utils/SimplexComparisons.hpp>
Expand All @@ -13,6 +14,7 @@
#include "../tools/DEBUG_Tuple.hpp"
#include "../tools/EdgeMesh_examples.hpp"
#include "../tools/TriMesh_examples.hpp"
#include <wmtk/multimesh/utils/MapValidator.hpp>

using namespace wmtk;
using namespace wmtk::tests;
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit c374150

Please sign in to comment.