diff --git a/CMakeLists.txt b/CMakeLists.txt index d9527bce5d..0a5aac7817 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ endif() project(WildMeshingToolkit DESCRIPTION "A mesh optimization toolkit" LANGUAGES C CXX) # ############################################################################### +option(WMTK_ENABLE_APPLICATIONS "Enable applications (required for any applications to build)" ${WILDMESHING_TOOLKIT_TOPLEVEL_PROJECT}) option(WMTK_BUILD_DOCS "Build doxygen" OFF) option (BUILD_SHARED_LIBS "Build Shared Libraries" OFF) # we globally want to disable this option due to use of TBB @@ -207,5 +208,7 @@ endif() # Compile extras only if this is a top-level project if(WILDMESHING_TOOLKIT_TOPLEVEL_PROJECT) add_subdirectory(tests) +endif() +if(WMTK_ENABLE_APPLICATIONS) add_subdirectory(applications) endif() diff --git a/src/wmtk/EdgeMesh.cpp b/src/wmtk/EdgeMesh.cpp index 8725e0ac37..62ba9969a4 100644 --- a/src/wmtk/EdgeMesh.cpp +++ b/src/wmtk/EdgeMesh.cpp @@ -5,7 +5,7 @@ #include #include namespace wmtk { - EdgeMesh::~EdgeMesh() = default; +EdgeMesh::~EdgeMesh() = default; EdgeMesh::EdgeMesh() : MeshCRTP(1) , m_ve_handle(register_attribute_typed("m_ve", PrimitiveType::Vertex, 1, false, -1)) @@ -111,8 +111,8 @@ void EdgeMesh::initialize( attribute::Accessor ee_accessor = create_accessor(m_ee_handle); attribute::Accessor ve_accessor = create_accessor(m_ve_handle); - attribute::Accessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); - attribute::Accessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); + attribute::FlagAccessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); + attribute::FlagAccessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); // iterate over the matrices and fill attributes @@ -120,12 +120,12 @@ void EdgeMesh::initialize( ev_accessor.index_access().vector_attribute<2>(i) = EV.row(i).transpose(); ee_accessor.index_access().vector_attribute<2>(i) = EE.row(i).transpose(); - e_flag_accessor.index_access().scalar_attribute(i) |= 0x1; + e_flag_accessor.index_access().activate(i); } // m_ve for (int64_t i = 0; i < capacity(PrimitiveType::Vertex); ++i) { ve_accessor.index_access().scalar_attribute(i) = VE(i); - v_flag_accessor.index_access().scalar_attribute(i) |= 0x1; + v_flag_accessor.index_access().activate(i); } } @@ -239,31 +239,38 @@ bool EdgeMesh::is_connectivity_valid() const const attribute::Accessor ev_accessor = create_const_accessor(m_ev_handle); const attribute::Accessor ee_accessor = create_const_accessor(m_ee_handle); const attribute::Accessor ve_accessor = create_const_accessor(m_ve_handle); - const attribute::Accessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); - const attribute::Accessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); + const attribute::FlagAccessor v_flag_accessor = + get_flag_accessor(PrimitiveType::Vertex); + const attribute::FlagAccessor e_flag_accessor = + get_flag_accessor(PrimitiveType::Edge); // VE and EV for (int64_t i = 0; i < capacity(PrimitiveType::Vertex); ++i) { - if (v_flag_accessor.index_access().const_scalar_attribute(i) == 0) { - wmtk::logger().debug("Vertex {} is deleted", i); + if (!v_flag_accessor.index_access().is_active(i)) { continue; } int cnt = 0; for (int64_t j = 0; j < 2; ++j) { if (ev_accessor.index_access().const_vector_attribute<2>( - ve_accessor.index_access().const_scalar_attribute(i))[j] == i) { + ve_accessor.index_access().const_scalar_attribute(i))(j) == i) { cnt++; } } if (cnt == 0) { + int64_t idx = ve_accessor.index_access().const_scalar_attribute(i); + wmtk::logger().error( + "EV[VE[{}]={},:]] ({}) = doesn't contain {}", + i, + idx, + fmt::join(ev_accessor.index_access().const_vector_attribute<2>(idx), ","), + i); return false; } } // EV and EE for (int64_t i = 0; i < capacity(PrimitiveType::Edge); ++i) { - if (e_flag_accessor.index_access().const_scalar_attribute(i) == 0) { - wmtk::logger().debug("Edge {} is deleted", i); + if (!e_flag_accessor.index_access().is_active(i)) { continue; } // TODO: need to handle cornor case (self-loop) diff --git a/src/wmtk/EdgeMeshOperationExecutor.cpp b/src/wmtk/EdgeMeshOperationExecutor.cpp index c5fca4d8dc..4dcc8a7557 100644 --- a/src/wmtk/EdgeMeshOperationExecutor.cpp +++ b/src/wmtk/EdgeMeshOperationExecutor.cpp @@ -38,7 +38,7 @@ void EdgeMesh::EdgeMeshOperationExecutor::delete_simplices() { for (size_t d = 0; d < simplex_ids_to_delete.size(); ++d) { for (const int64_t id : simplex_ids_to_delete[d]) { - flag_accessors[d].index_access().scalar_attribute(id) = 0; + flag_accessors[d].index_access().deactivate(id) ; } } } diff --git a/src/wmtk/EdgeMeshOperationExecutor.hpp b/src/wmtk/EdgeMeshOperationExecutor.hpp index f21dbcdeef..ec8f5aee43 100644 --- a/src/wmtk/EdgeMeshOperationExecutor.hpp +++ b/src/wmtk/EdgeMeshOperationExecutor.hpp @@ -11,7 +11,7 @@ class EdgeMesh::EdgeMeshOperationExecutor : public operations::edge_mesh::EdgeOp void delete_simplices(); void update_cell_hash(); - std::array, 2> flag_accessors; + std::array, 2> flag_accessors; attribute::Accessor ee_accessor; attribute::Accessor ev_accessor; attribute::Accessor ve_accessor; diff --git a/src/wmtk/Mesh.cpp b/src/wmtk/Mesh.cpp index 0c1778687d..06cfe8a746 100644 --- a/src/wmtk/Mesh.cpp +++ b/src/wmtk/Mesh.cpp @@ -56,11 +56,11 @@ std::vector Mesh::get_all_id_simplex( const int64_t cap = capacity(type); - const attribute::Accessor flag_accessor = get_flag_accessor(type); - const attribute::CachingAccessor& flag_accessor_indices = flag_accessor.index_access(); + const attribute::FlagAccessor<> flag_accessor = get_flag_accessor(type); + const attribute::IndexFlagAccessor<>& flag_accessor_indices = flag_accessor.index_access(); ret.reserve(cap); for (size_t index = 0; index < cap; ++index) { - if (flag_accessor_indices.const_scalar_attribute(index) & 1) + if (flag_accessor_indices.is_active(index)) ret.emplace_back(simplex::IdSimplex(type, index)); else if (include_deleted) ret.emplace_back(); @@ -77,14 +77,15 @@ std::vector Mesh::get_all(PrimitiveType type, const bool include_deleted) const int64_t cap = capacity(type); - const attribute::Accessor flag_accessor = get_flag_accessor(type); - const attribute::CachingAccessor& flag_accessor_indices = flag_accessor.index_access(); + const attribute::FlagAccessor<> flag_accessor = get_flag_accessor(type); + const attribute::IndexFlagAccessor<>& flag_accessor_indices = flag_accessor.index_access(); ret.reserve(cap); for (size_t index = 0; index < cap; ++index) { - if (flag_accessor_indices.const_scalar_attribute(index) & 1) + if (flag_accessor_indices.is_active(index)) { ret.emplace_back(tuple_from_id(type, index)); - else if (include_deleted) + } else if (include_deleted) { ret.emplace_back(); + } } return ret; } @@ -137,7 +138,7 @@ bool Mesh::is_removed(int64_t index) const bool Mesh::is_removed(int64_t index, PrimitiveType pt) const { const auto& flag_accessor = get_const_flag_accessor(pt); - return !(flag_accessor.index_access().const_scalar_attribute(index) & 0x1); + return !flag_accessor.index_access().is_active(index); } bool Mesh::is_valid(const simplex::Simplex& s) const @@ -155,17 +156,19 @@ bool Mesh::is_valid(const simplex::Simplex& s) const } -const attribute::Accessor Mesh::get_flag_accessor(PrimitiveType type) const +const attribute::FlagAccessor Mesh::get_flag_accessor(PrimitiveType type) const { return get_const_flag_accessor(type); } -const attribute::Accessor Mesh::get_const_flag_accessor(PrimitiveType type) const +const attribute::FlagAccessor Mesh::get_const_flag_accessor(PrimitiveType type) const { - return create_const_accessor(m_flag_handles.at(get_primitive_type_id(type))); + return attribute::FlagAccessor( + create_const_accessor(m_flag_handles.at(get_primitive_type_id(type)))); } -attribute::Accessor Mesh::get_flag_accessor(PrimitiveType type) +attribute::FlagAccessor Mesh::get_flag_accessor(PrimitiveType type) { - return create_accessor(m_flag_handles.at(get_primitive_type_id(type))); + return attribute::FlagAccessor( + create_accessor(m_flag_handles.at(get_primitive_type_id(type)))); } diff --git a/src/wmtk/Mesh.hpp b/src/wmtk/Mesh.hpp index eb66d9ffda..e850800167 100644 --- a/src/wmtk/Mesh.hpp +++ b/src/wmtk/Mesh.hpp @@ -24,6 +24,7 @@ #include "attribute/AttributeScopeHandle.hpp" #include "attribute/MeshAttributeHandle.hpp" #include "attribute/MeshAttributes.hpp" +#include "attribute/FlagAccessor.hpp" #include "multimesh/attribute/AttributeScopeHandle.hpp" #include "multimesh/attribute/UseParentScopeRAII.hpp" @@ -295,8 +296,8 @@ class Mesh : public std::enable_shared_from_this, public wmtk::utils::Merk decltype(auto) parent_scope(Functor&& f, Args&&... args) const; - const attribute::Accessor get_flag_accessor(PrimitiveType type) const; - const attribute::Accessor get_const_flag_accessor(PrimitiveType type) const; + const attribute::FlagAccessor get_flag_accessor(PrimitiveType type) const; + const attribute::FlagAccessor get_const_flag_accessor(PrimitiveType type) const; bool operator==(const Mesh& other) const; @@ -307,7 +308,7 @@ class Mesh : public std::enable_shared_from_this, public wmtk::utils::Merk virtual std::vector orient_vertices(const Tuple& t) const = 0; protected: // member functions - attribute::Accessor get_flag_accessor(PrimitiveType type); + attribute::FlagAccessor<> get_flag_accessor(PrimitiveType type); protected: diff --git a/src/wmtk/Mesh_attributes.cpp b/src/wmtk/Mesh_attributes.cpp index 42c7686933..750f1556b1 100644 --- a/src/wmtk/Mesh_attributes.cpp +++ b/src/wmtk/Mesh_attributes.cpp @@ -47,8 +47,8 @@ std::vector Mesh::request_simplex_indices(PrimitiveType type, int64_t c int64_t current_capacity = capacity(type); // enable newly requested simplices - attribute::Accessor flag_accessor = get_flag_accessor(type); - int64_t max_size = flag_accessor.reserved_size(); + attribute::FlagAccessor flag_accessor = get_flag_accessor(type); + int64_t max_size = flag_accessor.base_accessor().reserved_size(); if (current_capacity + count > max_size) { logger().warn( @@ -71,11 +71,11 @@ std::vector Mesh::request_simplex_indices(PrimitiveType type, int64_t c m_attribute_manager.m_capacities[primitive_id] = new_capacity; - attribute::CachingAccessor& flag_accessor_indices = flag_accessor.index_access(); + attribute::IndexFlagAccessor& flag_accessor_indices = flag_accessor.index_access(); for (const int64_t simplex_index : ret) { // wmtk::logger().trace("Activating {}-simplex {}", primitive_id, simplex_index); - flag_accessor_indices.scalar_attribute(simplex_index) |= 0x1; + flag_accessor_indices.activate(simplex_index); } return ret; @@ -218,10 +218,10 @@ std::tuple>, std::vector>> // Initialize both maps for (int64_t d = 0; d < tcp; d++) { - attribute::Accessor flag_accessor = + attribute::FlagAccessor flag_accessor = get_flag_accessor(wmtk::get_primitive_type_from_id(d)); for (int64_t i = 0; i < capacity(wmtk::get_primitive_type_from_id(d)); ++i) { - if (flag_accessor.index_access().scalar_attribute(i) & 1) { + if (flag_accessor.index_access().is_active(i)) { old2new[d].push_back(new2old[d].size()); new2old[d].push_back(old2new[d].size() - 1); // -1 since we just pushed into it } else { diff --git a/src/wmtk/PointMesh.cpp b/src/wmtk/PointMesh.cpp index 686e1ef8e8..6b8f84f091 100644 --- a/src/wmtk/PointMesh.cpp +++ b/src/wmtk/PointMesh.cpp @@ -52,9 +52,9 @@ void PointMesh::initialize(int64_t count) { set_capacities({count}); reserve_attributes_to_fit(); - attribute::Accessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); + attribute::FlagAccessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); for (int64_t i = 0; i < capacity(PrimitiveType::Vertex); ++i) { - v_flag_accessor.index_access().scalar_attribute(i) |= 0x1; + v_flag_accessor.index_access().activate(i); } } diff --git a/src/wmtk/TetMesh.cpp b/src/wmtk/TetMesh.cpp index aa4b27856f..bbe0d20bd4 100644 --- a/src/wmtk/TetMesh.cpp +++ b/src/wmtk/TetMesh.cpp @@ -103,10 +103,11 @@ void TetMesh::initialize( auto te_accessor = create_accessor(m_te_handle); auto tf_accessor = create_accessor(m_tf_handle); auto tt_accessor = create_accessor(m_tt_handle); - attribute::Accessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); - attribute::Accessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); - attribute::Accessor f_flag_accessor = get_flag_accessor(PrimitiveType::Triangle); - attribute::Accessor t_flag_accessor = get_flag_accessor(PrimitiveType::Tetrahedron); + attribute::FlagAccessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); + attribute::FlagAccessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); + attribute::FlagAccessor f_flag_accessor = get_flag_accessor(PrimitiveType::Triangle); + attribute::FlagAccessor t_flag_accessor = + get_flag_accessor(PrimitiveType::Tetrahedron); // iterate over the matrices and fill attributes for (int64_t i = 0; i < capacity(PrimitiveType::Tetrahedron); ++i) { @@ -114,22 +115,23 @@ void TetMesh::initialize( te_accessor.index_access().vector_attribute<6>(i) = TE.row(i).transpose(); tf_accessor.index_access().vector_attribute<4>(i) = TF.row(i).transpose(); tt_accessor.index_access().vector_attribute<4>(i) = TT.row(i).transpose(); - t_flag_accessor.index_access().scalar_attribute(i) |= 0x1; + t_flag_accessor.index_access().activate(i); + e_flag_accessor.index_access().activate(i); } // m_vt for (int64_t i = 0; i < capacity(PrimitiveType::Vertex); ++i) { vt_accessor.index_access().scalar_attribute(i) = VT(i); - v_flag_accessor.index_access().scalar_attribute(i) |= 0x1; + v_flag_accessor.index_access().activate(i); } // m_et for (int64_t i = 0; i < capacity(PrimitiveType::Edge); ++i) { et_accessor.index_access().scalar_attribute(i) = ET(i); - e_flag_accessor.index_access().scalar_attribute(i) |= 0x1; + e_flag_accessor.index_access().activate(i); } // m_ft for (int64_t i = 0; i < capacity(PrimitiveType::Triangle); ++i) { ft_accessor.index_access().scalar_attribute(i) = FT(i); - f_flag_accessor.index_access().scalar_attribute(i) |= 0x1; + f_flag_accessor.index_access().activate(i); } } @@ -326,7 +328,7 @@ bool TetMesh::is_valid(const Tuple& tuple) const if (!is_connectivity_valid) { #if !defined(NDEBUG) - logger().debug( + logger().trace( "tuple.m_local_vid={} >= 0 && tuple.m_local_eid={} >= 0 &&" "tuple.m_local_fid={} >= 0 &&" " tuple.m_global_cid={} >= 0 &&" @@ -405,15 +407,60 @@ bool TetMesh::is_connectivity_valid() const const attribute::Accessor vt_accessor = create_const_accessor(m_vt_handle); const attribute::Accessor et_accessor = create_const_accessor(m_et_handle); const attribute::Accessor ft_accessor = create_const_accessor(m_ft_handle); - const attribute::Accessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); - const attribute::Accessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); - const attribute::Accessor f_flag_accessor = get_flag_accessor(PrimitiveType::Triangle); - const attribute::Accessor t_flag_accessor = get_flag_accessor(PrimitiveType::Tetrahedron); + const attribute::FlagAccessor v_flag_accessor = + get_flag_accessor(PrimitiveType::Vertex); + const attribute::FlagAccessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); + const attribute::FlagAccessor f_flag_accessor = + get_flag_accessor(PrimitiveType::Triangle); + const attribute::FlagAccessor t_flag_accessor = + get_flag_accessor(PrimitiveType::Tetrahedron); + + for (int64_t i = 0; i < capacity(PrimitiveType::Tetrahedron); ++i) { + if (!t_flag_accessor.index_access().is_active(i)) { + continue; + } + auto tf = tf_accessor.index_access().const_vector_attribute<4>(i); + auto te = te_accessor.index_access().const_vector_attribute<6>(i); + auto tv = tv_accessor.index_access().const_vector_attribute<4>(i); + + bool bad_face = false; + for (int64_t j = 0; j < 6; ++j) { + int64_t ei = te(j); + if (!e_flag_accessor.index_access().is_active(ei)) { + wmtk::logger().error( + "Tet {} refers to edge {} at local index {} which was deleted", + i, + ei, + j); + bad_face = true; + } + } + + for (int64_t j = 0; j < 4; ++j) { + int64_t vi = tv(j); + int64_t fi = tf(j); + if (!v_flag_accessor.index_access().is_active(vi)) { + wmtk::logger().error( + "Tet {} refers to vertex{} at local index {} which was deleted", + i, + vi, + j); + bad_face = true; + } + if (!f_flag_accessor.index_access().is_active(fi)) { + wmtk::logger() + .error("Tet {} refers to face{} at local index {} which was deleted", i, fi, j); + bad_face = true; + } + } + if (bad_face) { + return false; + } + } // VT and TV for (int64_t i = 0; i < capacity(PrimitiveType::Vertex); ++i) { - if (v_flag_accessor.index_access().const_scalar_attribute(i) == 0) { - wmtk::logger().debug("Vertex {} is deleted", i); + if (!v_flag_accessor.index_access().is_active(i)) { continue; } int cnt = 0; @@ -431,8 +478,7 @@ bool TetMesh::is_connectivity_valid() const // ET and TE for (int64_t i = 0; i < capacity(PrimitiveType::Edge); ++i) { - if (e_flag_accessor.index_access().const_scalar_attribute(i) == 0) { - wmtk::logger().debug("Edge {} is deleted", i); + if (!e_flag_accessor.index_access().is_active(i)) { continue; } int cnt = 0; @@ -450,8 +496,7 @@ bool TetMesh::is_connectivity_valid() const // FT and TF for (int64_t i = 0; i < capacity(PrimitiveType::Triangle); ++i) { - if (f_flag_accessor.index_access().const_scalar_attribute(i) == 0) { - wmtk::logger().debug("Face {} is deleted", i); + if (!f_flag_accessor.index_access().is_active(i)) { continue; } int cnt = 0; @@ -469,8 +514,7 @@ bool TetMesh::is_connectivity_valid() const // TF and TT for (int64_t i = 0; i < capacity(PrimitiveType::Tetrahedron); ++i) { - if (t_flag_accessor.index_access().const_scalar_attribute(i) == 0) { - wmtk::logger().debug("Tet {} is deleted", i); + if (!t_flag_accessor.index_access().is_active(i)) { continue; } @@ -479,7 +523,7 @@ bool TetMesh::is_connectivity_valid() const if (nb == -1) { if (ft_accessor.index_access().const_scalar_attribute( tf_accessor.index_access().const_vector_attribute<4>(i)(j)) != i) { - wmtk::logger().info("fail TF and TT 1"); + wmtk::logger().error("FT[TF[{},{}]] != {}", i, j, i); return false; } continue; @@ -494,13 +538,24 @@ bool TetMesh::is_connectivity_valid() const } } if (cnt != 1) { - wmtk::logger().info("fail TF and TT 2"); + wmtk::logger().error("Tet {} was adjacent to tet {} {} <= 1 times", nb, i, cnt); return false; } if (tf_accessor.index_access().const_vector_attribute<4>(i)(j) != tf_accessor.index_access().const_vector_attribute<4>(nb)(id_in_nb)) { - wmtk::logger().info("fail TF and TT 3"); + wmtk::logger().error( + "TF[{},{}] = {} != {} = TF[{},{}] even though TT[{},{}] == {}", + i, + j, + tf_accessor.index_access().const_vector_attribute<4>(i)(j), + tf_accessor.index_access().const_vector_attribute<4>(nb)(id_in_nb), + nb, + id_in_nb, + i, + j, + nb); + return false; } } diff --git a/src/wmtk/TetMeshOperationExecutor.cpp b/src/wmtk/TetMeshOperationExecutor.cpp index d6be4c9542..0806952b96 100644 --- a/src/wmtk/TetMeshOperationExecutor.cpp +++ b/src/wmtk/TetMeshOperationExecutor.cpp @@ -186,7 +186,7 @@ void TetMesh::TetMeshOperationExecutor::delete_simplices() { for (size_t d = 0; d < simplex_ids_to_delete.size(); ++d) { for (const int64_t id : simplex_ids_to_delete[d]) { - flag_accessors[d].index_access().scalar_attribute(id) = 0; // TODO: reset single bit + flag_accessors[d].index_access().deactivate(id); } } } diff --git a/src/wmtk/TetMeshOperationExecutor.hpp b/src/wmtk/TetMeshOperationExecutor.hpp index 4a031a89c1..4dff71c94e 100644 --- a/src/wmtk/TetMeshOperationExecutor.hpp +++ b/src/wmtk/TetMeshOperationExecutor.hpp @@ -11,7 +11,7 @@ class TetMesh::TetMeshOperationExecutor : public operations::tet_mesh::EdgeOpera void delete_simplices(); void update_cell_hash(); - std::array, 4> flag_accessors; + std::array, 4> flag_accessors; attribute::Accessor& tt_accessor; attribute::Accessor& tf_accessor; attribute::Accessor& te_accessor; diff --git a/src/wmtk/TriMesh.cpp b/src/wmtk/TriMesh.cpp index a50c6b43de..257581fba8 100644 --- a/src/wmtk/TriMesh.cpp +++ b/src/wmtk/TriMesh.cpp @@ -198,9 +198,9 @@ void TriMesh::initialize( attribute::Accessor vf_accessor = create_accessor(m_vf_handle); attribute::Accessor ef_accessor = create_accessor(m_ef_handle); - attribute::Accessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); - attribute::Accessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); - attribute::Accessor f_flag_accessor = get_flag_accessor(PrimitiveType::Triangle); + attribute::FlagAccessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); + attribute::FlagAccessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); + attribute::FlagAccessor f_flag_accessor = get_flag_accessor(PrimitiveType::Triangle); // iterate over the matrices and fill attributes for (int64_t i = 0; i < capacity(PrimitiveType::Triangle); ++i) { @@ -208,19 +208,19 @@ void TriMesh::initialize( fe_accessor.index_access().vector_attribute<3>(i) = FE.row(i).transpose(); ff_accessor.index_access().vector_attribute<3>(i) = FF.row(i).transpose(); - f_flag_accessor.index_access().scalar_attribute(i) |= 0x1; + f_flag_accessor.index_access().activate(i); } // m_vf for (int64_t i = 0; i < capacity(PrimitiveType::Vertex); ++i) { auto& vf = vf_accessor.index_access().scalar_attribute(i); vf = VF(i); - v_flag_accessor.index_access().scalar_attribute(i) |= 0x1; + v_flag_accessor.index_access().activate(i); } // m_ef for (int64_t i = 0; i < capacity(PrimitiveType::Edge); ++i) { auto& ef = ef_accessor.index_access().scalar_attribute(i); ef = EF(i); - e_flag_accessor.index_access().scalar_attribute(i) |= 0x1; + e_flag_accessor.index_access().activate(i); } } @@ -329,7 +329,7 @@ Tuple TriMesh::face_tuple_from_id(int64_t id) const bool TriMesh::is_valid(const Tuple& tuple) const { if (!Mesh::is_valid(tuple)) { - logger().debug("Tuple was null and therefore not valid"); + logger().trace("Tuple was null and therefore not valid"); return false; } const bool is_connectivity_valid = tuple.m_local_vid >= 0 && tuple.m_local_eid >= 0 && @@ -338,7 +338,7 @@ bool TriMesh::is_valid(const Tuple& tuple) const if (!is_connectivity_valid) { #if !defined(NDEBUG) - logger().debug( + logger().trace( "tuple.m_local_vid={} >= 0 && tuple.m_local_eid={} >= 0 &&" " tuple.m_global_cid={} >= 0 &&" " autogen::tri_mesh::tuple_is_valid_for_ccw(tuple)={}", @@ -364,14 +364,49 @@ bool TriMesh::is_connectivity_valid() const const attribute::Accessor ff_accessor = create_const_accessor(m_ff_handle); const attribute::Accessor vf_accessor = create_const_accessor(m_vf_handle); const attribute::Accessor ef_accessor = create_const_accessor(m_ef_handle); - const attribute::Accessor v_flag_accessor = get_flag_accessor(PrimitiveType::Vertex); - const attribute::Accessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); - const attribute::Accessor f_flag_accessor = get_flag_accessor(PrimitiveType::Triangle); + const attribute::FlagAccessor v_flag_accessor = + get_flag_accessor(PrimitiveType::Vertex); + const attribute::FlagAccessor e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); + const attribute::FlagAccessor f_flag_accessor = + get_flag_accessor(PrimitiveType::Triangle); + + for (int64_t i = 0; i < capacity(PrimitiveType::Triangle); ++i) { + if (!f_flag_accessor.index_access().is_active(i)) { + continue; + } + auto fe = fe_accessor.index_access().const_vector_attribute<3>(i); + auto fv = fv_accessor.index_access().const_vector_attribute<3>(i); + + bool bad_face = false; + + for (int64_t j = 0; j < 3; ++j) { + int64_t ei = fe(j); + int64_t vi = fv(j); + if (!e_flag_accessor.index_access().is_active(ei)) { + wmtk::logger().error( + "Face {} refers to edge {} at local index {} which was deleted", + i, + ei, + j); + bad_face = true; + } + if (!v_flag_accessor.index_access().is_active(vi)) { + wmtk::logger().error( + "Face {} refers to vertex{} at local index {} which was deleted", + i, + vi, + j); + bad_face = true; + } + } + if (bad_face) { + return false; + } + } // EF and FE for (int64_t i = 0; i < capacity(PrimitiveType::Edge); ++i) { - if (e_flag_accessor.index_access().const_scalar_attribute(i) == 0) { - wmtk::logger().debug("Edge {} is deleted", i); + if (!e_flag_accessor.index_access().is_active(i)) { continue; } int cnt = 0; @@ -384,7 +419,7 @@ bool TriMesh::is_connectivity_valid() const } } if (cnt == 0) { - wmtk::logger().debug( + wmtk::logger().error( "EF[{0}] {1} and FE:[EF[{0}]] = {2} are not " "compatible ", i, @@ -399,8 +434,7 @@ bool TriMesh::is_connectivity_valid() const // VF and FV for (int64_t i = 0; i < capacity(PrimitiveType::Vertex); ++i) { const int64_t vf = vf_accessor.index_access().const_scalar_attribute(i); - if (v_flag_accessor.index_access().const_scalar_attribute(i) == 0) { - wmtk::logger().debug("Vertex {} is deleted", i); + if (!v_flag_accessor.index_access().is_active(i)) { continue; } int cnt = 0; @@ -412,7 +446,7 @@ bool TriMesh::is_connectivity_valid() const } } if (cnt == 0) { - wmtk::logger().debug( + wmtk::logger().error( "VF and FV not compatible, could not find VF[{}] = {} " "in FV[{}] = [{}]", i, @@ -425,8 +459,7 @@ bool TriMesh::is_connectivity_valid() const // FE and EF for (int64_t i = 0; i < capacity(PrimitiveType::Triangle); ++i) { - if (f_flag_accessor.index_access().const_scalar_attribute(i) == 0) { - wmtk::logger().debug("Face {} is deleted", i); + if (!f_flag_accessor.index_access().is_active(i)) { continue; } auto fe = fe_accessor.index_access().const_vector_attribute<3>(i); @@ -438,7 +471,7 @@ bool TriMesh::is_connectivity_valid() const if (is_boundary) { auto ef = ef_accessor.index_access().const_scalar_attribute(fe(j)); if (ef != i) { - wmtk::logger().debug( + wmtk::logger().error( "Even though local edge {} of face {} is " "boundary (global eid is {}), " "ef[{}] = {} != {}", @@ -452,7 +485,7 @@ bool TriMesh::is_connectivity_valid() const } } else { if (neighbor_fid == i) { - logger().warn( + logger().error( "Connectivity check cannot work when mapping a " "face to itself (face {})", i); @@ -476,7 +509,7 @@ bool TriMesh::is_connectivity_valid() const } } if (edge_shared_count != 1) { - wmtk::logger().debug( + wmtk::logger().error( "face {} with fe={} neighbor fe[{}] = {} " "was unable to find itself " "uniquely (found {})", @@ -488,7 +521,7 @@ bool TriMesh::is_connectivity_valid() const return false; } } else { - wmtk::logger().debug( + wmtk::logger().error( "face {} with ff={} neighbor ff[{}] = {} was " "unable to find itself", i, diff --git a/src/wmtk/TriMeshOperationExecutor.cpp b/src/wmtk/TriMeshOperationExecutor.cpp index a041f72d77..496d5bc74f 100644 --- a/src/wmtk/TriMeshOperationExecutor.cpp +++ b/src/wmtk/TriMeshOperationExecutor.cpp @@ -129,7 +129,7 @@ void TriMesh::TriMeshOperationExecutor::delete_simplices() d, fmt::join(simplex_ids_to_delete[d], ",")); for (const int64_t id : simplex_ids_to_delete[d]) { - flag_accessors[d].index_access().scalar_attribute(id) = 0; + flag_accessors[d].index_access().deactivate(id); } } } diff --git a/src/wmtk/TriMeshOperationExecutor.hpp b/src/wmtk/TriMeshOperationExecutor.hpp index 02dbc44b7f..e58e454c45 100644 --- a/src/wmtk/TriMeshOperationExecutor.hpp +++ b/src/wmtk/TriMeshOperationExecutor.hpp @@ -12,7 +12,7 @@ class TriMesh::TriMeshOperationExecutor : public operations::tri_mesh::EdgeOpera TriMeshOperationExecutor(TriMesh& m, const Tuple& operating_tuple); void delete_simplices(); - std::array, 3> flag_accessors; + std::array, 3> flag_accessors; attribute::Accessor& ff_accessor; attribute::Accessor& fe_accessor; attribute::Accessor& fv_accessor; diff --git a/src/wmtk/attribute/FlagAccessor.hpp b/src/wmtk/attribute/FlagAccessor.hpp new file mode 100644 index 0000000000..521bb5f062 --- /dev/null +++ b/src/wmtk/attribute/FlagAccessor.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include "Accessor.hpp" +namespace wmtk::attribute { + + +template +class IndexFlagAccessor +{ +public: + enum class FlagBit : char { Active = 0x1 }; + static bool _is_active(char value) { return value & static_cast(FlagBit::Active); } + static void _activate(char& value) { value |= static_cast(FlagBit::Active); } + static void _deactivate(char& value) { value &= inverse_mask(FlagBit::Active); } + using BaseAccessor = Accessor; + + + IndexFlagAccessor(BaseAccessor acc) + : m_base_accessor{std::move(acc)} + {} + template + IndexFlagAccessor(const IndexFlagAccessor& o) + : m_base_accessor{o.m_base_accessor} + {} + + bool is_active(int64_t t) const + { + return _is_active(m_base_accessor.index_access().const_scalar_attribute(t)); + } + void activate(int64_t t) + { + return _activate(m_base_accessor.index_access().scalar_attribute(t)); + } + void deactivate(int64_t t) + { + return _deactivate(m_base_accessor.index_access().scalar_attribute(t)); + } + + constexpr static char inverse_mask(FlagBit bit) { return 0xFF ^ static_cast(bit); } + + + BaseAccessor& base_accessor() { return m_base_accessor; } + const BaseAccessor& base_accessor() const { return m_base_accessor; } + operator BaseAccessor() const { return m_base_accessor; } + +protected: + BaseAccessor m_base_accessor; + + + IndexFlagAccessor index_access() const { return IndexAccessor(*this); } +}; + +template +class FlagAccessor : private IndexFlagAccessor +{ +public: + enum class FlagBit : char { Active = 1 }; + using IndexBaseType = IndexFlagAccessor; + + using IndexBaseType::base_accessor; + using IndexBaseType::IndexBaseType; + + template + FlagAccessor(const FlagAccessor& o) + : IndexBaseType{o.base_accessor()} + {} + + template + bool is_active(const T& t) const + { + return IndexBaseType::_is_active(IndexBaseType::m_base_accessor.const_scalar_attribute(t)); + } + template + void activate(const T& t) + { + IndexBaseType::_activate(IndexBaseType::m_base_accessor.scalar_attribute(t)); + } + template + void deactivate(const T& t) + { + IndexBaseType::_deactivate(IndexBaseType::m_base_accessor.scalar_attribute(t)); + } + + + const IndexBaseType& index_access() const { return *this; } + IndexBaseType& index_access() { return *this; } +}; + + +} // namespace wmtk::attribute diff --git a/src/wmtk/multimesh/MultiMeshManager.cpp b/src/wmtk/multimesh/MultiMeshManager.cpp index 5b824734a8..0544671919 100644 --- a/src/wmtk/multimesh/MultiMeshManager.cpp +++ b/src/wmtk/multimesh/MultiMeshManager.cpp @@ -689,10 +689,10 @@ std::vector> MultiMeshManager::same_simplex_dimension_surje for (int64_t 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.is_active(pt))) { continue; } - if ((child_flag_accessor.const_scalar_attribute(ct) & 1) == 0) { + if (!(child_flag_accessor.is_active(ct))) { continue; } diff --git a/src/wmtk/operations/AttributesUpdate.cpp b/src/wmtk/operations/AttributesUpdate.cpp index b7299066d7..c91921add9 100644 --- a/src/wmtk/operations/AttributesUpdate.cpp +++ b/src/wmtk/operations/AttributesUpdate.cpp @@ -33,14 +33,9 @@ std::vector AttributesUpdate::execute(const simplex::Simplex& // // assert(!mesh().is_valid(simplex.tuple(), accessor)); -#if defined(WMTK_ENABLE_HASH_UPDATE) - auto new_tuple = resurrect_tuple(simplex.tuple()); -#else - auto new_tuple = simplex.tuple(); -#endif - assert(mesh().is_valid(new_tuple)); - - return {simplex::Simplex(mesh(), primitive_type(), new_tuple)}; + assert(mesh().is_valid(simplex.tuple())); + + return {simplex}; } AttributesUpdateWithFunction::AttributesUpdateWithFunction(Mesh& m) diff --git a/src/wmtk/operations/Operation.cpp b/src/wmtk/operations/Operation.cpp index 530a80ffdb..7deb38c263 100644 --- a/src/wmtk/operations/Operation.cpp +++ b/src/wmtk/operations/Operation.cpp @@ -151,6 +151,8 @@ void Operation::apply_attribute_transfer(const std::vector& di for (const auto& s : direct_mods) { if (!s.tuple().is_null()) { + assert(m_mesh.is_valid(s)); + assert(m_mesh.get_const_flag_accessor(s.primitive_type()).is_active(s)); for (const simplex::IdSimplex& ss : simplex::closed_star_iterable(m_mesh, s)) { all.add(ss); } diff --git a/src/wmtk/operations/utils/UpdateEdgeOperationMultiMeshMapFunctor.cpp b/src/wmtk/operations/utils/UpdateEdgeOperationMultiMeshMapFunctor.cpp index 71401529b4..207574d0a4 100644 --- a/src/wmtk/operations/utils/UpdateEdgeOperationMultiMeshMapFunctor.cpp +++ b/src/wmtk/operations/utils/UpdateEdgeOperationMultiMeshMapFunctor.cpp @@ -88,9 +88,7 @@ void UpdateEdgeOperationMultiMeshMapFunctor::update_ear_replacement( // check also the flag accessor of child mesh - const char child_flag = - child_cell_flag_accessor.const_scalar_attribute(child_tuple); - bool child_tuple_exists = 1 == (child_flag & 1); + const bool child_tuple_exists = child_cell_flag_accessor.is_active(child_tuple); if (!child_tuple_exists) { continue; } @@ -184,9 +182,7 @@ void UpdateEdgeOperationMultiMeshMapFunctor::update_ear_replacement( } - const char child_flag = - child_cell_flag_accessor.const_scalar_attribute(child_tuple); - bool child_tuple_exists = 1 == (child_flag & 1); + bool child_tuple_exists = child_cell_flag_accessor.is_active(child_tuple); if (!child_tuple_exists) { continue; } @@ -294,9 +290,7 @@ void UpdateEdgeOperationMultiMeshMapFunctor::update_ear_replacement( } - const char child_flag = - child_cell_flag_accessor.const_scalar_attribute(child_tuple); - bool child_tuple_exists = 1 == (child_flag & 1); + bool child_tuple_exists = child_cell_flag_accessor.is_active(child_tuple); if (!child_tuple_exists) { continue; } diff --git a/tests/multimesh/consolidate.cpp b/tests/multimesh/consolidate.cpp index 4729dd90a1..10b6f27370 100644 --- a/tests/multimesh/consolidate.cpp +++ b/tests/multimesh/consolidate.cpp @@ -80,8 +80,8 @@ TEST_CASE("consolidate_multimesh", "[mesh][consolidate_multimesh]") // CHECK_THROWS(m.tuple_from_id(PrimitiveType::Vertex, 4)); - REQUIRE(executor.flag_accessors[2].index_access().const_scalar_attribute(2) == 0); - REQUIRE(executor.flag_accessors[2].index_access().const_scalar_attribute(7) == 0); + REQUIRE(executor.flag_accessors[2].index_access().is_active(2) == false); + REQUIRE(executor.flag_accessors[2].index_access().is_active(7) == false); CHECK(fv_accessor.vector_attribute(0)[1] == 5); CHECK(fv_accessor.vector_attribute(1)[0] == 5); CHECK(fv_accessor.vector_attribute(3)[0] == 5); diff --git a/tests/operations/collapse_2d.cpp b/tests/operations/collapse_2d.cpp index 5acbc742b6..07c2b6b8b2 100644 --- a/tests/operations/collapse_2d.cpp +++ b/tests/operations/collapse_2d.cpp @@ -64,8 +64,8 @@ TEST_CASE("collapse_edge", "[operations][collapse][2D]") // CHECK_THROWS(m.tuple_from_id(PrimitiveType::Vertex, 4)); - REQUIRE(face_flag_accessor.index_access().const_scalar_attribute(2) == 0); - REQUIRE(face_flag_accessor.index_access().const_scalar_attribute(7) == 0); + REQUIRE(face_flag_accessor.index_access().is_active(2) == false); + REQUIRE(face_flag_accessor.index_access().is_active(7) == false); CHECK(fv_accessor.vector_attribute(0)[1] == 5); CHECK(fv_accessor.vector_attribute(1)[0] == 5); CHECK(fv_accessor.vector_attribute(3)[0] == 5); @@ -84,8 +84,8 @@ TEST_CASE("collapse_edge", "[operations][collapse][2D]") // CHECK_THROWS(m.tuple_from_id(PrimitiveType::Vertex, 4)); - REQUIRE(face_flag_accessor.index_access().const_scalar_attribute(0) == 0); - REQUIRE(face_flag_accessor.index_access().const_scalar_attribute(1) == 0); + REQUIRE(face_flag_accessor.index_access().is_active(0) == false); + REQUIRE(face_flag_accessor.index_access().is_active(1) == false); CHECK(fv_accessor.vector_attribute(2)[0] == 0); CHECK(fv_accessor.vector_attribute(5)[2] == 0); @@ -125,7 +125,7 @@ TEST_CASE("collapse_edge", "[operations][collapse][2D]") // CHECK_THROWS(m.tuple_from_id(PrimitiveType::Vertex, 0)); - REQUIRE(face_flag_accessor.index_access().const_scalar_attribute(1) == 0); + REQUIRE(face_flag_accessor.index_access().is_active(1) == false); CHECK(fv_accessor.vector_attribute(0)[2] == 1); } diff --git a/tests/operations/split_2d.cpp b/tests/operations/split_2d.cpp index 4465042e07..26eef37af2 100644 --- a/tests/operations/split_2d.cpp +++ b/tests/operations/split_2d.cpp @@ -132,8 +132,8 @@ TEST_CASE("delete_simplices", "[operations][2D]") executor.simplex_ids_to_delete = TMOE::get_split_simplices_to_delete(edge, m); executor.delete_simplices(); - REQUIRE(executor.flag_accessors[1].index_access().const_scalar_attribute(edge_index) == 0); - REQUIRE(executor.flag_accessors[2].index_access().const_scalar_attribute(face_index) == 0); + REQUIRE(executor.flag_accessors[1].index_access().is_active(edge_index) == false); + REQUIRE(executor.flag_accessors[2].index_access().is_active(face_index) == false); REQUIRE(executor.ff_accessor.index_access().const_vector_attribute(face_index)[0] == -1); REQUIRE(executor.ff_accessor.index_access().const_vector_attribute(face_index)[1] == 2); REQUIRE(executor.ff_accessor.index_access().const_vector_attribute(face_index)[2] == 1); diff --git a/tests/test_mesh.cpp b/tests/test_mesh.cpp index c24546cec5..16e1391c34 100644 --- a/tests/test_mesh.cpp +++ b/tests/test_mesh.cpp @@ -99,8 +99,8 @@ TEST_CASE("consolidate", "[mesh][consolidate]") // CHECK_THROWS(m.tuple_from_id(PrimitiveType::Vertex, 4)); - REQUIRE(executor.flag_accessors[2].index_access().scalar_attribute(2) == 0); - REQUIRE(executor.flag_accessors[2].index_access().scalar_attribute(7) == 0); + REQUIRE(executor.flag_accessors[2].index_access().is_active(2) == false); + REQUIRE(executor.flag_accessors[2].index_access().is_active(7) == false); CHECK(fv_accessor.vector_attribute(0)[1] == 5); CHECK(fv_accessor.vector_attribute(1)[0] == 5); CHECK(fv_accessor.vector_attribute(3)[0] == 5); diff --git a/tests/tools/DEBUG_EdgeMesh.cpp b/tests/tools/DEBUG_EdgeMesh.cpp index c665f5ba1d..f138bc4b64 100644 --- a/tests/tools/DEBUG_EdgeMesh.cpp +++ b/tests/tools/DEBUG_EdgeMesh.cpp @@ -33,7 +33,7 @@ void DEBUG_EdgeMesh::print_ve() const auto e_flag_accessor = get_flag_accessor(PrimitiveType::Edge); for (int64_t id = 0; id < capacity(PrimitiveType::Edge); ++id) { auto ev = ev_accessor.const_vector_attribute(id); - if (e_flag_accessor.const_scalar_attribute(tuple_from_id(PrimitiveType::Edge, id)) == 0) { + if (!e_flag_accessor.is_active(tuple_from_id(PrimitiveType::Edge, id))) { std::cout << "edge " << id << " is deleted" << std::endl; } else { std::cout << ev(0) << " " << ev(1) << std::endl; @@ -111,6 +111,6 @@ auto DEBUG_EdgeMesh::get_emoe(const Tuple& t) -> EdgeMeshOperationExecutor bool DEBUG_EdgeMesh::is_simplex_deleted(PrimitiveType type, const int64_t id) const { const auto flag_accessor = get_flag_accessor(type); - return flag_accessor.index_access().scalar_attribute(id) == 0; + return !flag_accessor.index_access().is_active(id) ; } } // namespace wmtk::tests diff --git a/tests/tools/DEBUG_TetMesh.cpp b/tests/tools/DEBUG_TetMesh.cpp index 93fbc67c3f..beb5577d91 100644 --- a/tests/tools/DEBUG_TetMesh.cpp +++ b/tests/tools/DEBUG_TetMesh.cpp @@ -286,7 +286,7 @@ int64_t DEBUG_TetMesh::valid_primitive_count(PrimitiveType type) const int64_t cnt = 0; const auto& flag_accessor = get_const_flag_accessor(type); for (int i = 0; i < capacity(type); i++) { - if (flag_accessor.index_access().const_scalar_attribute(i) != 0) { + if (flag_accessor.index_access().is_active(i)) { cnt++; } } diff --git a/tests/tools/DEBUG_TriMesh.cpp b/tests/tools/DEBUG_TriMesh.cpp index b1d83e3d51..c2098bf5c5 100644 --- a/tests/tools/DEBUG_TriMesh.cpp +++ b/tests/tools/DEBUG_TriMesh.cpp @@ -34,8 +34,7 @@ void DEBUG_TriMesh::print_vf() const auto f_flag_accessor = get_flag_accessor(PrimitiveType::Triangle); for (int64_t id = 0; id < capacity(PrimitiveType::Triangle); ++id) { auto fv = fv_accessor.const_vector_attribute(id); - if (f_flag_accessor.const_scalar_attribute(tuple_from_id(PrimitiveType::Triangle, id)) == - 0) { + if (!f_flag_accessor.is_active(tuple_from_id(PrimitiveType::Triangle, id))) { std::cout << "face " << id << " is deleted" << std::endl; } else { std::cout << fv(0) << " " << fv(1) << " " << fv(2) << std::endl;