From 4f2d646652f557ea503f6dd69a9650450be8b8dc Mon Sep 17 00:00:00 2001 From: JcDai Date: Wed, 20 Dec 2023 13:50:59 -0500 Subject: [PATCH 1/4] minor change to reduce compilation warnings --- .../internal/IsotropicRemeshing.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/wmtk_components/isotropic_remeshing/internal/IsotropicRemeshing.cpp b/components/wmtk_components/isotropic_remeshing/internal/IsotropicRemeshing.cpp index 56133384ef..cafc2d3546 100644 --- a/components/wmtk_components/isotropic_remeshing/internal/IsotropicRemeshing.cpp +++ b/components/wmtk_components/isotropic_remeshing/internal/IsotropicRemeshing.cpp @@ -126,7 +126,7 @@ void IsotropicRemeshing::remeshing(const long iterations) m_mesh.serialize(writer1); - for (const auto v : child_meshes[0]->get_all(PrimitiveType::Vertex)) { + for (const auto& v : child_meshes[0]->get_all(PrimitiveType::Vertex)) { auto parent_v = child_meshes[0]->map_to_root_tuple(Simplex(PrimitiveType::Vertex, v)); child_vertex_accessor.vector_attribute(v) = @@ -167,7 +167,7 @@ void IsotropicRemeshing::remeshing(const long iterations) m_mesh.serialize(writer2); - for (const auto v : child_meshes[0]->get_all(PrimitiveType::Vertex)) { + for (const auto& v : child_meshes[0]->get_all(PrimitiveType::Vertex)) { auto parent_v = child_meshes[0]->map_to_root_tuple(Simplex(PrimitiveType::Vertex, v)); child_vertex_accessor.vector_attribute(v) = @@ -213,7 +213,7 @@ void IsotropicRemeshing::remeshing(const long iterations) m_mesh.serialize(writer3); - for (const auto v : child_meshes[0]->get_all(PrimitiveType::Vertex)) { + for (const auto& v : child_meshes[0]->get_all(PrimitiveType::Vertex)) { auto parent_v = child_meshes[0]->map_to_root_tuple(Simplex(PrimitiveType::Vertex, v)); child_vertex_accessor.vector_attribute(v) = @@ -233,12 +233,12 @@ void IsotropicRemeshing::remeshing(const long iterations) } if (m_do_smooth) { - //m_scheduler.run_operation_on_all(PrimitiveType::Vertex, "smooth"); - //is_conn_valid = m_mesh.is_connectivity_valid(); - //if (!is_conn_valid) throw std::runtime_error("invalid mesh connectivty"); + // m_scheduler.run_operation_on_all(PrimitiveType::Vertex, "smooth"); + // is_conn_valid = m_mesh.is_connectivity_valid(); + // if (!is_conn_valid) throw std::runtime_error("invalid mesh connectivty"); - //wmtk::logger().info("Is connectivity valid: {}", is_conn_valid); - //wmtk::logger().info("Done smooth {}\n", i); + // wmtk::logger().info("Is connectivity valid: {}", is_conn_valid); + // wmtk::logger().info("Done smooth {}\n", i); } // debug write @@ -254,7 +254,7 @@ void IsotropicRemeshing::remeshing(const long iterations) m_mesh.serialize(writer4); - for (const auto v : child_meshes[0]->get_all(PrimitiveType::Vertex)) { + for (const auto& v : child_meshes[0]->get_all(PrimitiveType::Vertex)) { auto parent_v = child_meshes[0]->map_to_root_tuple(Simplex(PrimitiveType::Vertex, v)); child_vertex_accessor.vector_attribute(v) = From 708e63f69e4dba0d9daa0ece7a2f1d8450af919d Mon Sep 17 00:00:00 2001 From: JcDai Date: Wed, 20 Dec 2023 17:41:10 -0500 Subject: [PATCH 2/4] add edgeswap for tetmesh (no test) --- src/wmtk/TetMeshOperationExecutor.cpp | 28 +++-- src/wmtk/TetMeshOperationExecutor.hpp | 4 +- src/wmtk/operations/Operation.cpp | 10 ++ src/wmtk/operations/Operation.hpp | 3 + src/wmtk/operations/tet_mesh/CMakeLists.txt | 2 + src/wmtk/operations/tet_mesh/EdgeCollapse.cpp | 29 +++-- src/wmtk/operations/tet_mesh/EdgeCollapse.hpp | 6 +- .../operations/tet_mesh/EdgeOperationData.hpp | 11 +- src/wmtk/operations/tet_mesh/EdgeSplit.cpp | 6 + src/wmtk/operations/tet_mesh/EdgeSplit.hpp | 4 + src/wmtk/operations/tet_mesh/EdgeSwap.cpp | 106 ++++++++++++++++++ src/wmtk/operations/tet_mesh/EdgeSwap.hpp | 73 ++++++++++++ 12 files changed, 255 insertions(+), 27 deletions(-) create mode 100644 src/wmtk/operations/tet_mesh/EdgeSwap.cpp create mode 100644 src/wmtk/operations/tet_mesh/EdgeSwap.hpp diff --git a/src/wmtk/TetMeshOperationExecutor.cpp b/src/wmtk/TetMeshOperationExecutor.cpp index 482f3c6f72..641a0601c4 100644 --- a/src/wmtk/TetMeshOperationExecutor.cpp +++ b/src/wmtk/TetMeshOperationExecutor.cpp @@ -2,10 +2,10 @@ #include namespace wmtk { - namespace { - constexpr static PrimitiveType PE = PrimitiveType::Edge; - constexpr static PrimitiveType PF = PrimitiveType::Face; - } +namespace { +constexpr static PrimitiveType PE = PrimitiveType::Edge; +constexpr static PrimitiveType PF = PrimitiveType::Face; +} // namespace std::tuple, std::vector> TetMesh::TetMeshOperationExecutor::get_incident_tets_and_faces(Tuple t) @@ -305,6 +305,9 @@ void TetMesh::TetMeshOperationExecutor::split_edge() std::vector new_tids = this->request_simplex_indices(PrimitiveType::Tetrahedron, 2); std::vector split_fids = this->request_simplex_indices(PrimitiveType::Face, 1); + m_new_tet_ids.push_back(new_tids[0]); + m_new_tet_ids.push_back(new_tids[1]); + TetSplitData tsd; tsd.tid_old = m_mesh.id_tet(incident_tets[i]); tsd.tid_new_1 = new_tids[0]; @@ -412,9 +415,9 @@ void TetMesh::TetMeshOperationExecutor::split_edge() return_tid = t2; return_fid = f4; spdlog::info("split fid is {}", f_split); - spdlog::info("fids {} {} are joined by edge {}", f3,f4,e_split_2); + spdlog::info("fids {} {} are joined by edge {}", f3, f4, e_split_2); #ifndef NDEBUG - return_split_fid =f_split; + return_split_fid = f_split; #endif return_flag = true; } @@ -693,10 +696,15 @@ void TetMesh::TetMeshOperationExecutor::split_edge() assert(return_fid == m_mesh.id(Simplex::face(m_output_tuple))); assert(return_tid == m_mesh.id(Simplex::tetrahedron(m_output_tuple))); - spdlog::info("split fid is {}",m_mesh.id(Simplex::face(m_mesh.switch_tuples(m_output_tuple, {PE, PF})))); - //assert(m_mesh.id(Simplex::edge(m_mesh.switch_tuples(m_output_tuple, {PE}))) = return_face_spine_eid); - assert(m_mesh.id(Simplex::face(m_mesh.switch_tuples(m_output_tuple, {PE, PF}))) == return_split_fid); - assert(!m_mesh.is_boundary_face(m_mesh.switch_tuples(m_output_tuple, {PE, PF}))); + spdlog::info( + "split fid is {}", + m_mesh.id(Simplex::face(m_mesh.switch_tuples(m_output_tuple, {PE, PF})))); + // assert(m_mesh.id(Simplex::edge(m_mesh.switch_tuples(m_output_tuple, {PE}))) = + // return_face_spine_eid); + assert( + m_mesh.id(Simplex::face(m_mesh.switch_tuples(m_output_tuple, {PE, PF}))) == + return_split_fid); + assert(!m_mesh.is_boundary_face(m_mesh.switch_tuples(m_output_tuple, {PE, PF}))); } void TetMesh::TetMeshOperationExecutor::collapse_edge() diff --git a/src/wmtk/TetMeshOperationExecutor.hpp b/src/wmtk/TetMeshOperationExecutor.hpp index 43a31d7204..d3522b1c04 100644 --- a/src/wmtk/TetMeshOperationExecutor.hpp +++ b/src/wmtk/TetMeshOperationExecutor.hpp @@ -77,13 +77,13 @@ class TetMesh::TetMeshOperationExecutor : public operations::tet_mesh::EdgeOpera * * This function will return the tuple that has: the same vertex as the input, a new edge * along the input edge, a new face on the input face, and a new tet with is half of the input - * tet. In the illustration it will return Tuple(v1, v1-v_new, v1-v_new-v4, v1-v_new-v4-v3) + * tet. In the illustration it will return Tuple(v_new, v_new-v2, v_new-v2-v4, v_new-v_2-v4-v3) * */ void split_edge(); /** - * @brief split edge v1-v2 + * @brief collapse edge v1-v2 * * * // 5 --------- 4 ---------- 6 diff --git a/src/wmtk/operations/Operation.cpp b/src/wmtk/operations/Operation.cpp index 85427087d8..4f2dbdf041 100644 --- a/src/wmtk/operations/Operation.cpp +++ b/src/wmtk/operations/Operation.cpp @@ -64,4 +64,14 @@ const Accessor& Operation::hash_accessor() const return const_cast(this)->hash_accessor(); } +std::vector +Operation::get_tuples_from_ids(const Mesh& m, PrimitiveType pt, const std::vector& ids) +{ + std::vector tuples(ids.size()); + for (long i = 0; i < ids.size(); ++i) { + tuples[i] = m.tuple_from_id(pt, ids[i]); + } + return tuples; +} + } // namespace wmtk::operations diff --git a/src/wmtk/operations/Operation.hpp b/src/wmtk/operations/Operation.hpp index e9d1465945..711624ea0d 100644 --- a/src/wmtk/operations/Operation.hpp +++ b/src/wmtk/operations/Operation.hpp @@ -57,6 +57,9 @@ class Operation static Accessor get_hash_accessor(Mesh& m); + + static std::vector + get_tuples_from_ids(const Mesh& m, PrimitiveType pt, const std::vector& ids); }; } // namespace operations diff --git a/src/wmtk/operations/tet_mesh/CMakeLists.txt b/src/wmtk/operations/tet_mesh/CMakeLists.txt index 3559535505..29164e0d97 100644 --- a/src/wmtk/operations/tet_mesh/CMakeLists.txt +++ b/src/wmtk/operations/tet_mesh/CMakeLists.txt @@ -5,6 +5,8 @@ set(SRC_FILES EdgeSplit.cpp EdgeCollapse.hpp EdgeCollapse.cpp + EdgeSwap.hpp + EdgeSwap.cpp TetSplit.hpp TetSplit.cpp TetSplitWithTags.hpp diff --git a/src/wmtk/operations/tet_mesh/EdgeCollapse.cpp b/src/wmtk/operations/tet_mesh/EdgeCollapse.cpp index fc5816290c..e63d2535f6 100644 --- a/src/wmtk/operations/tet_mesh/EdgeCollapse.cpp +++ b/src/wmtk/operations/tet_mesh/EdgeCollapse.cpp @@ -1,14 +1,19 @@ #include "EdgeCollapse.hpp" #include -#include #include +#include +#include #include +#include +#include +#include namespace wmtk::operations { void OperationSettings::create_invariants() { invariants = std::make_shared(m_mesh); + invariants->add(std::make_shared(m_mesh)); } namespace tet_mesh { @@ -27,6 +32,7 @@ bool EdgeCollapse::execute() { auto return_data = mesh().collapse_edge(input_tuple(), hash_accessor()); m_output_tuple = return_data.m_output_tuple; + m_deleted_tet_ids = return_data.simplex_ids_to_delete[3]; return true; } @@ -54,16 +60,21 @@ Tuple EdgeCollapse::return_tuple() const return m_output_tuple; } -std::vector EdgeCollapse::modified_triangles() const +std::vector EdgeCollapse::deleted_tet_ids() const +{ + return m_deleted_tet_ids; +} + +std::vector EdgeCollapse::modified_tetrahedra() const { Simplex v(PrimitiveType::Vertex, m_output_tuple); - auto sc = SimplicialComplex::open_star(mesh(), v); - auto faces = sc.get_simplices(PrimitiveType::Face); - std::vector ret; - for (const auto& face : faces) { - ret.emplace_back(face.tuple()); - } - return ret; + return simplex::top_dimension_cofaces_tuples(mesh(), v); + // auto sc = simplex::top_dimension_cofaces(mesh(), v); + // std::vector ret; + // for (const auto& tet : sc) { + // ret.emplace_back(tet.tuple()); + // } + // return ret; } } // namespace tet_mesh } // namespace wmtk::operations diff --git a/src/wmtk/operations/tet_mesh/EdgeCollapse.hpp b/src/wmtk/operations/tet_mesh/EdgeCollapse.hpp index da96da4209..fcc1cb62c6 100644 --- a/src/wmtk/operations/tet_mesh/EdgeCollapse.hpp +++ b/src/wmtk/operations/tet_mesh/EdgeCollapse.hpp @@ -40,13 +40,15 @@ class EdgeCollapse : public TetMeshOperation, private TupleOperation std::string name() const override; - std::vector modified_triangles() const; + std::vector modified_tetrahedra() const; std::vector modified_primitives() const override; std::vector unmodified_primitives() const override; Tuple return_tuple() const; + std::vector deleted_tet_ids() const; + static PrimitiveType primitive_type() { return PrimitiveType::Edge; } using TetMeshOperation::hash_accessor; @@ -56,6 +58,8 @@ class EdgeCollapse : public TetMeshOperation, private TupleOperation private: Tuple m_output_tuple; + + std::vector m_deleted_tet_ids; }; } // namespace tet_mesh diff --git a/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp b/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp index 35d5800ab9..781f9da83b 100644 --- a/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp +++ b/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp @@ -6,7 +6,6 @@ namespace wmtk::operations::tet_mesh { struct EdgeOperationData { - // // E --------------- C --------------- F // \-_ / | \ _-/ @@ -113,10 +112,11 @@ struct EdgeOperationData long operating_edge_id() const { return m_operating_edge_id; } - std::array, 4> simplex_ids_to_delete; std::vector cell_ids_to_update_hash; + std::vector m_new_tet_ids; + Tuple m_operating_tuple; Tuple m_output_tuple; @@ -128,10 +128,11 @@ struct EdgeOperationData long m_operating_face_id; long m_operating_tet_id; - long m_split_new_vid = -1; - std::array m_split_new_spine_eids; + long m_split_new_vid = -1; + std::array m_split_new_spine_eids; + // simplices required per-tet std::vector m_incident_tet_datas; }; -} +} // namespace wmtk::operations::tet_mesh diff --git a/src/wmtk/operations/tet_mesh/EdgeSplit.cpp b/src/wmtk/operations/tet_mesh/EdgeSplit.cpp index 286a791410..a03b1cba1d 100644 --- a/src/wmtk/operations/tet_mesh/EdgeSplit.cpp +++ b/src/wmtk/operations/tet_mesh/EdgeSplit.cpp @@ -27,6 +27,7 @@ bool EdgeSplit::execute() { auto return_data = mesh().split_edge(input_tuple(), hash_accessor()); m_output_tuple = return_data.m_output_tuple; + m_new_tet_ids = return_data.m_new_tet_ids; return true; } @@ -46,6 +47,11 @@ Tuple EdgeSplit::return_tuple() const return m_output_tuple; } +std::vector EdgeSplit::new_tet_ids() const +{ + return m_new_tet_ids; +} + std::vector EdgeSplit::modified_primitives() const { return {simplex::Simplex::vertex(new_vertex())}; diff --git a/src/wmtk/operations/tet_mesh/EdgeSplit.hpp b/src/wmtk/operations/tet_mesh/EdgeSplit.hpp index 907f9ebd02..e965796765 100644 --- a/src/wmtk/operations/tet_mesh/EdgeSplit.hpp +++ b/src/wmtk/operations/tet_mesh/EdgeSplit.hpp @@ -52,12 +52,16 @@ class EdgeSplit : public TetMeshOperation, private TupleOperation using TetMeshOperation::hash_accessor; + std::vector new_tet_ids() const; + protected: bool execute() override; private: Tuple m_output_tuple; + std::vector m_new_tet_ids; + const OperationSettings& m_settings; }; diff --git a/src/wmtk/operations/tet_mesh/EdgeSwap.cpp b/src/wmtk/operations/tet_mesh/EdgeSwap.cpp new file mode 100644 index 0000000000..06400816ae --- /dev/null +++ b/src/wmtk/operations/tet_mesh/EdgeSwap.cpp @@ -0,0 +1,106 @@ +#include "EdgeSwap.hpp" +#include +#include +#include + +// #include +#include "EdgeCollapse.hpp" +#include "EdgeSplit.hpp" + +namespace wmtk::operations { +void OperationSettings::create_invariants() +{ + invariants = std::make_shared(m_mesh); + invariants->add(std::make_shared(m_mesh)); + + collapse_settings.create_invariants(); + split_settings.create_invariants(); +} + +namespace tet_mesh { +EdgeSwap::EdgeSwap( + Mesh& m, + const Simplex& t, + int collapse_index, + const OperationSettings& settings) + : TetMeshOperation(m) + , TupleOperation(settings.invariants, t) + , m_collapse_index(collapse_index) + , m_settings{settings} +{} + +std::string EdgeSwap::name() const +{ + return "tet_mesh_edge_swap"; +} + +Tuple EdgeSwap::return_tuple() const +{ + return m_output_tuple; +} + +std::vector EdgeSwap::new_tets_after_swap() const +{ + return m_new_tets; +} + +bool EdgeSwap::execute() +{ + // Split the edge + Tuple split_ret; + + tet_mesh::EdgeSplit split_op(mesh(), input_simplex(), m_settings.split_settings); + if (!split_op()) { + return false; + } + split_ret = split_op.return_tuple(); + + + // get candidate edges to collapse, which are the edges generated by split + // the return tuple must be an interior edge, because we disallow swap on the boundary + assert(mesh().is_boundary_edge(split_ret)); + auto iter_tuple = split_ret; + std::vector candidate_edges; + while (true) { + candidate_edges.push_back(mesh().switch_edge(iter_tuple)); + iter_tuple = mesh().switch_tetrahedron(mesh().switch_face(iter_tuple)); + if (iter_tuple == split_ret) { + break; + } + } + + assert(m_collapse_index < candidate_edges.size()); + + Tuple coll_ret; + + tet_mesh::EdgeCollapse coll_op( + mesh(), + Simplex::edge(candidate_edges[m_collapse_index]), + m_settings.collapse_settings); + if (!coll_op()) { + return false; + } + + + // TODO: need to decide a convention for the output tuple + m_output_tuple = coll_ret; + // get new tets generated by swap = tets_generated_by_split - tets_deleted_by_collapse + auto tet_ids_generated_by_split = split_op.new_tet_ids(); + auto tet_ids_deleted_by_collapse = coll_op.deleted_tet_ids(); + std::vector tet_ids_generated_by_swap; + std::set_difference( + tet_ids_generated_by_split.begin(), + tet_ids_generated_by_split.end(), + tet_ids_deleted_by_collapse.begin(), + tet_ids_deleted_by_collapse.end(), + tet_ids_generated_by_swap.begin()); + + m_new_tets = get_tuples_from_ids(mesh(), PrimitiveType::Tetrahedron, tet_ids_generated_by_swap); + + return true; +} + +} // namespace tet_mesh + + +} // namespace wmtk::operations diff --git a/src/wmtk/operations/tet_mesh/EdgeSwap.hpp b/src/wmtk/operations/tet_mesh/EdgeSwap.hpp new file mode 100644 index 0000000000..cdef4c169a --- /dev/null +++ b/src/wmtk/operations/tet_mesh/EdgeSwap.hpp @@ -0,0 +1,73 @@ +#pragma once +#include +#include +#include "EdgeCollapse.hpp" +#include "EdgeSplit.hpp" +#include "TetMeshOperation.hpp" + +namespace wmtk::operations { + +namespace tet_mesh { +class EdgeSwap; +} + +template <> +struct OperationSettings : public OperationSettingsBase +{ + OperationSettings(TetMesh& m) + : m_mesh(m) + , collapse_settings(m) + , split_settings(m) + {} + + TetMesh& m_mesh; + + OperationSettings collapse_settings; + OperationSettings split_settings; + + void create_invariants(); +}; + +namespace tet_mesh { +/** + * Performs an edge swap, implemented as a combination of swap and collapse. + * + * When swapping an edge, one first split the edge (that splits all the tets incident to that edge), + * then collapse the edge with index collapse_index.) + * + * Edge swap cannot be performed on boundary edges. + * + */ + +class EdgeSwap : public TetMeshOperation, protected TupleOperation +{ +public: + EdgeSwap( + Mesh& m, + const Simplex& t, + int collapse_index, + const OperationSettings& settings); + + std::string name() const override; + Tuple return_tuple() const; + + static PrimitiveType primitive_type() { return PrimitiveType::Edge; } + + std::vector modified_primitives() const; + + std::vector unmodified_primitives() const override; + + std::vector new_tets_after_swap() const; + +protected: + bool execute() override; + +private: + Tuple m_output_tuple; + const OperationSettings& m_settings; + int m_collapse_index; + std::vector m_new_tets; +}; + +} // namespace tet_mesh +} // namespace wmtk::operations \ No newline at end of file From 9aaec2899318b59c99f3e9363f52675d1d79ca88 Mon Sep 17 00:00:00 2001 From: JcDai Date: Thu, 21 Dec 2023 17:58:17 -0500 Subject: [PATCH 3/4] add tests, add modified primitives for 3d swap --- src/wmtk/TetMeshOperationExecutor.cpp | 10 +++ src/wmtk/operations/tet_mesh/EdgeCollapse.cpp | 6 ++ src/wmtk/operations/tet_mesh/EdgeCollapse.hpp | 2 + .../operations/tet_mesh/EdgeOperationData.hpp | 3 + src/wmtk/operations/tet_mesh/EdgeSplit.cpp | 8 +++ src/wmtk/operations/tet_mesh/EdgeSplit.hpp | 6 ++ src/wmtk/operations/tet_mesh/EdgeSwap.cpp | 40 ++++++++++- src/wmtk/operations/tet_mesh/EdgeSwap.hpp | 4 +- tests/test_3d_operations.cpp | 71 ++++++++++++++++++- tests/tools/TetMesh_examples.cpp | 25 +++++++ tests/tools/TetMesh_examples.hpp | 31 ++++++++ 11 files changed, 202 insertions(+), 4 deletions(-) diff --git a/src/wmtk/TetMeshOperationExecutor.cpp b/src/wmtk/TetMeshOperationExecutor.cpp index 641a0601c4..3967567453 100644 --- a/src/wmtk/TetMeshOperationExecutor.cpp +++ b/src/wmtk/TetMeshOperationExecutor.cpp @@ -265,11 +265,16 @@ void TetMesh::TetMeshOperationExecutor::split_edge() const long v_new = new_vids[0]; m_split_new_vid = v_new; + m_new_vertex_ids.push_back(new_vids[0]); + // create new edges (spline) std::vector new_eids = this->request_simplex_indices(PrimitiveType::Edge, 2); assert(new_eids.size() == 2); std::copy(new_eids.begin(), new_eids.end(), m_split_new_spine_eids.begin()); + m_new_edge_ids.push_back(new_eids[0]); + m_new_edge_ids.push_back(new_eids[1]); + // get incident tets and faces(two cases: loop and boundary) // auto incident_tets_and_faces = get_incident_tets_and_faces(m_operating_tuple); // const auto& incident_tets = incident_tets_and_faces[0]; @@ -285,6 +290,10 @@ void TetMesh::TetMeshOperationExecutor::split_edge() std::vector new_fids = this->request_simplex_indices(PrimitiveType::Face, 2); std::vector splitting_eids = this->request_simplex_indices(PrimitiveType::Edge, 1); + m_new_face_ids.push_back(new_fids[0]); + m_new_face_ids.push_back(new_fids[1]); + m_new_edge_ids.push_back(splitting_eids[0]); + FaceSplitData fsd; fsd.fid_old = m_mesh.id_face(incident_faces[i]); fsd.fid_new_1 = new_fids[0]; @@ -307,6 +316,7 @@ void TetMesh::TetMeshOperationExecutor::split_edge() m_new_tet_ids.push_back(new_tids[0]); m_new_tet_ids.push_back(new_tids[1]); + m_new_face_ids.push_back(split_fids[0]); TetSplitData tsd; tsd.tid_old = m_mesh.id_tet(incident_tets[i]); diff --git a/src/wmtk/operations/tet_mesh/EdgeCollapse.cpp b/src/wmtk/operations/tet_mesh/EdgeCollapse.cpp index e63d2535f6..b67d964f7f 100644 --- a/src/wmtk/operations/tet_mesh/EdgeCollapse.cpp +++ b/src/wmtk/operations/tet_mesh/EdgeCollapse.cpp @@ -33,6 +33,7 @@ bool EdgeCollapse::execute() auto return_data = mesh().collapse_edge(input_tuple(), hash_accessor()); m_output_tuple = return_data.m_output_tuple; m_deleted_tet_ids = return_data.simplex_ids_to_delete[3]; + m_deleted_edge_ids = return_data.simplex_ids_to_delete[1]; return true; } @@ -65,6 +66,11 @@ std::vector EdgeCollapse::deleted_tet_ids() const return m_deleted_tet_ids; } +std::vector EdgeCollapse::deleted_edge_ids() const +{ + return m_deleted_edge_ids; +} + std::vector EdgeCollapse::modified_tetrahedra() const { Simplex v(PrimitiveType::Vertex, m_output_tuple); diff --git a/src/wmtk/operations/tet_mesh/EdgeCollapse.hpp b/src/wmtk/operations/tet_mesh/EdgeCollapse.hpp index fcc1cb62c6..254148aa00 100644 --- a/src/wmtk/operations/tet_mesh/EdgeCollapse.hpp +++ b/src/wmtk/operations/tet_mesh/EdgeCollapse.hpp @@ -48,6 +48,7 @@ class EdgeCollapse : public TetMeshOperation, private TupleOperation Tuple return_tuple() const; std::vector deleted_tet_ids() const; + std::vector deleted_edge_ids() const; static PrimitiveType primitive_type() { return PrimitiveType::Edge; } @@ -60,6 +61,7 @@ class EdgeCollapse : public TetMeshOperation, private TupleOperation Tuple m_output_tuple; std::vector m_deleted_tet_ids; + std::vector m_deleted_edge_ids; }; } // namespace tet_mesh diff --git a/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp b/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp index 781f9da83b..52e21a6e12 100644 --- a/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp +++ b/src/wmtk/operations/tet_mesh/EdgeOperationData.hpp @@ -116,6 +116,9 @@ struct EdgeOperationData std::vector cell_ids_to_update_hash; std::vector m_new_tet_ids; + std::vector m_new_face_ids; + std::vector m_new_edge_ids; + std::vector m_new_vertex_ids; Tuple m_operating_tuple; diff --git a/src/wmtk/operations/tet_mesh/EdgeSplit.cpp b/src/wmtk/operations/tet_mesh/EdgeSplit.cpp index a03b1cba1d..a72028b778 100644 --- a/src/wmtk/operations/tet_mesh/EdgeSplit.cpp +++ b/src/wmtk/operations/tet_mesh/EdgeSplit.cpp @@ -28,6 +28,9 @@ bool EdgeSplit::execute() auto return_data = mesh().split_edge(input_tuple(), hash_accessor()); m_output_tuple = return_data.m_output_tuple; m_new_tet_ids = return_data.m_new_tet_ids; + m_new_edge_ids = return_data.m_new_edge_ids; + m_new_face_ids = return_data.m_new_face_ids; + m_new_vertex_ids = return_data.m_new_vertex_ids; return true; } @@ -52,6 +55,11 @@ std::vector EdgeSplit::new_tet_ids() const return m_new_tet_ids; } +std::vector EdgeSplit::new_edge_ids() const +{ + return m_new_edge_ids; +} + std::vector EdgeSplit::modified_primitives() const { return {simplex::Simplex::vertex(new_vertex())}; diff --git a/src/wmtk/operations/tet_mesh/EdgeSplit.hpp b/src/wmtk/operations/tet_mesh/EdgeSplit.hpp index e965796765..20f2037d91 100644 --- a/src/wmtk/operations/tet_mesh/EdgeSplit.hpp +++ b/src/wmtk/operations/tet_mesh/EdgeSplit.hpp @@ -54,6 +54,8 @@ class EdgeSplit : public TetMeshOperation, private TupleOperation std::vector new_tet_ids() const; + std::vector new_edge_ids() const; + protected: bool execute() override; @@ -61,6 +63,10 @@ class EdgeSplit : public TetMeshOperation, private TupleOperation Tuple m_output_tuple; std::vector m_new_tet_ids; + std::vector m_new_face_ids; + std::vector m_new_edge_ids; + std::vector m_new_vertex_ids; + const OperationSettings& m_settings; }; diff --git a/src/wmtk/operations/tet_mesh/EdgeSwap.cpp b/src/wmtk/operations/tet_mesh/EdgeSwap.cpp index 06400816ae..7e0456e3e8 100644 --- a/src/wmtk/operations/tet_mesh/EdgeSwap.cpp +++ b/src/wmtk/operations/tet_mesh/EdgeSwap.cpp @@ -44,6 +44,11 @@ std::vector EdgeSwap::new_tets_after_swap() const return m_new_tets; } +std::vector EdgeSwap::new_edges_after_swap() const +{ + return m_new_edges; +} + bool EdgeSwap::execute() { // Split the edge @@ -58,7 +63,7 @@ bool EdgeSwap::execute() // get candidate edges to collapse, which are the edges generated by split // the return tuple must be an interior edge, because we disallow swap on the boundary - assert(mesh().is_boundary_edge(split_ret)); + assert(!mesh().is_boundary_edge(split_ret)); auto iter_tuple = split_ret; std::vector candidate_edges; while (true) { @@ -93,13 +98,44 @@ bool EdgeSwap::execute() tet_ids_generated_by_split.end(), tet_ids_deleted_by_collapse.begin(), tet_ids_deleted_by_collapse.end(), - tet_ids_generated_by_swap.begin()); + std::inserter(tet_ids_generated_by_swap, tet_ids_generated_by_swap.begin())); m_new_tets = get_tuples_from_ids(mesh(), PrimitiveType::Tetrahedron, tet_ids_generated_by_swap); + // get new edges for modified primitives + auto edge_ids_generated_by_split = split_op.new_edge_ids(); + auto edge_ids_deleted_by_collapse = coll_op.deleted_edge_ids(); + std::vector edge_ids_generated_by_swap; + std::set_difference( + edge_ids_generated_by_split.begin(), + edge_ids_generated_by_split.end(), + edge_ids_deleted_by_collapse.begin(), + edge_ids_deleted_by_collapse.end(), + std::inserter(edge_ids_generated_by_swap, edge_ids_generated_by_swap.begin())); + + m_new_edges = get_tuples_from_ids(mesh(), PrimitiveType::Edge, edge_ids_generated_by_swap); + return true; } +std::vector EdgeSwap::modified_primitives() const +{ + // TODO: place holder, need to change + const auto& edge_tuples = new_edges_after_swap(); + std::vector edges; + edges.reserve(edge_tuples.size()); + std::transform(edge_tuples.begin(), edge_tuples.end(), edges.begin(), [](const Tuple& t) { + return Simplex::edge(t); + }); + return edges; +} + +std::vector EdgeSwap::unmodified_primitives() const +{ + return {input_simplex()}; +} + + } // namespace tet_mesh diff --git a/src/wmtk/operations/tet_mesh/EdgeSwap.hpp b/src/wmtk/operations/tet_mesh/EdgeSwap.hpp index cdef4c169a..e664ebb8be 100644 --- a/src/wmtk/operations/tet_mesh/EdgeSwap.hpp +++ b/src/wmtk/operations/tet_mesh/EdgeSwap.hpp @@ -58,6 +58,7 @@ class EdgeSwap : public TetMeshOperation, protected TupleOperation std::vector unmodified_primitives() const override; std::vector new_tets_after_swap() const; + std::vector new_edges_after_swap() const; protected: bool execute() override; @@ -65,8 +66,9 @@ class EdgeSwap : public TetMeshOperation, protected TupleOperation private: Tuple m_output_tuple; const OperationSettings& m_settings; - int m_collapse_index; + int m_collapse_index = 0; std::vector m_new_tets; + std::vector m_new_edges; }; } // namespace tet_mesh diff --git a/tests/test_3d_operations.cpp b/tests/test_3d_operations.cpp index dc7cc07e02..784a286276 100644 --- a/tests/test_3d_operations.cpp +++ b/tests/test_3d_operations.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -112,7 +113,7 @@ TEST_CASE("tet_get_split_simplices_to_delete", "[operations][split][3d]") } } -TEST_CASE("tet_get_collapse_simplices_to_delete", "[operations][collapse][3D]") +TEST_CASE("tet_get_collapse_simplices_to_delete", "[operations][collapse][3d]") { SECTION("single_tet") { @@ -834,3 +835,71 @@ TEST_CASE("tet_split_with_tags", "[operations][split][3d][.]") CHECK(!op1()); } } + + +TEST_CASE("tetmesh_edge_swap", "[operations][swap][split][collapse][3d]") +{ + using namespace operations; + using namespace tet_mesh; + + SECTION("swap32-0") + { + DEBUG_TetMesh m = three_cycle_tets(); + OperationSettings settings(m); + settings.create_invariants(); + + const Tuple edge = m.edge_tuple_between_v1_v2(0, 1, 2, 0); + EdgeSwap op(m, Simplex::edge(edge), 0, settings); + REQUIRE(op()); + const auto& new_tets = op.new_tets_after_swap(); + CHECK(new_tets.size() == 2); + } + SECTION("swap32-1") + { + DEBUG_TetMesh m = three_cycle_tets(); + OperationSettings settings(m); + settings.create_invariants(); + + const Tuple edge = m.edge_tuple_between_v1_v2(0, 1, 2, 0); + EdgeSwap op(m, Simplex::edge(edge), 1, settings); + REQUIRE(op()); + const auto& new_tets = op.new_tets_after_swap(); + CHECK(new_tets.size() == 2); + } + SECTION("swap32-2") + { + DEBUG_TetMesh m = three_cycle_tets(); + OperationSettings settings(m); + settings.create_invariants(); + + const Tuple edge = m.edge_tuple_between_v1_v2(0, 1, 2, 0); + EdgeSwap op(m, Simplex::edge(edge), 2, settings); + REQUIRE(op()); + const auto& new_tets = op.new_tets_after_swap(); + CHECK(new_tets.size() == 2); + } + SECTION("swap44-0") + { + DEBUG_TetMesh m = four_cycle_tets(); + OperationSettings settings(m); + settings.create_invariants(); + + const Tuple edge = m.edge_tuple_between_v1_v2(0, 1, 2, 3); + EdgeSwap op(m, Simplex::edge(edge), 0, settings); + REQUIRE(op()); + const auto& new_tets = op.new_tets_after_swap(); + CHECK(new_tets.size() == 4); + } + SECTION("swap44-1") + { + DEBUG_TetMesh m = four_cycle_tets(); + OperationSettings settings(m); + settings.create_invariants(); + + const Tuple edge = m.edge_tuple_between_v1_v2(0, 1, 2, 3); + EdgeSwap op(m, Simplex::edge(edge), 1, settings); + REQUIRE(op()); + const auto& new_tets = op.new_tets_after_swap(); + CHECK(new_tets.size() == 4); + } +} \ No newline at end of file diff --git a/tests/tools/TetMesh_examples.cpp b/tests/tools/TetMesh_examples.cpp index 36fdcb11ac..1555f9f325 100644 --- a/tests/tools/TetMesh_examples.cpp +++ b/tests/tools/TetMesh_examples.cpp @@ -76,5 +76,30 @@ TetMesh six_cycle_tets() return m; } +TetMesh three_cycle_tets() +{ + TetMesh m; + RowVectors4l tets; + tets.resize(3, 4); + tets.row(0) << 0, 1, 2, 4; + tets.row(1) << 0, 1, 4, 3; + tets.row(2) << 0, 1, 3, 2; + m.initialize(tets); + return m; +} + +TetMesh four_cycle_tets() +{ + TetMesh m; + RowVectors4l tets; + tets.resize(4, 4); + tets.row(0) << 0, 1, 3, 4; + tets.row(1) << 0, 1, 4, 5; + tets.row(2) << 0, 1, 5, 2; + tets.row(3) << 0, 1, 2, 3; + m.initialize(tets); + return m; +} + } // namespace wmtk::tests_3d \ No newline at end of file diff --git a/tests/tools/TetMesh_examples.hpp b/tests/tools/TetMesh_examples.hpp index e039048903..e62bc84168 100644 --- a/tests/tools/TetMesh_examples.hpp +++ b/tests/tools/TetMesh_examples.hpp @@ -60,4 +60,35 @@ TetMesh three_incident_tets(); TetMesh six_cycle_tets(); +// +// 2 +// / / | +// / // | +// / // | +// / /_1 | +// 3 -------- 0- \ | +// ---__ \ \ | +// --__ \ \ | +// ---__\\ +// 4 + +TetMesh three_cycle_tets(); + +// 2 ---------- 3 +// |\\ //| +// | \ \ // | +// | \ \ // | +// | \ \1 | +// | 0/ | +// | / /\ \ | +// | / / \\ | +// | // \\ | +// |// \ | +// 5 ---------- 4 +// + + +TetMesh four_cycle_tets(); + + } // namespace wmtk::tests_3d From 540fa308f85fc16a1e6cef5ada1775b8516767b8 Mon Sep 17 00:00:00 2001 From: JcDai Date: Thu, 21 Dec 2023 18:17:08 -0500 Subject: [PATCH 4/4] add more checks to swap tests --- tests/test_3d_operations.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_3d_operations.cpp b/tests/test_3d_operations.cpp index 784a286276..c474ea97f6 100644 --- a/tests/test_3d_operations.cpp +++ b/tests/test_3d_operations.cpp @@ -853,6 +853,7 @@ TEST_CASE("tetmesh_edge_swap", "[operations][swap][split][collapse][3d]") REQUIRE(op()); const auto& new_tets = op.new_tets_after_swap(); CHECK(new_tets.size() == 2); + CHECK(m.get_all(PrimitiveType::Tetrahedron).size() == 2); } SECTION("swap32-1") { @@ -865,6 +866,7 @@ TEST_CASE("tetmesh_edge_swap", "[operations][swap][split][collapse][3d]") REQUIRE(op()); const auto& new_tets = op.new_tets_after_swap(); CHECK(new_tets.size() == 2); + CHECK(m.get_all(PrimitiveType::Tetrahedron).size() == 2); } SECTION("swap32-2") { @@ -877,6 +879,7 @@ TEST_CASE("tetmesh_edge_swap", "[operations][swap][split][collapse][3d]") REQUIRE(op()); const auto& new_tets = op.new_tets_after_swap(); CHECK(new_tets.size() == 2); + CHECK(m.get_all(PrimitiveType::Tetrahedron).size() == 2); } SECTION("swap44-0") { @@ -889,6 +892,7 @@ TEST_CASE("tetmesh_edge_swap", "[operations][swap][split][collapse][3d]") REQUIRE(op()); const auto& new_tets = op.new_tets_after_swap(); CHECK(new_tets.size() == 4); + CHECK(m.get_all(PrimitiveType::Tetrahedron).size() == 4); } SECTION("swap44-1") { @@ -901,5 +905,6 @@ TEST_CASE("tetmesh_edge_swap", "[operations][swap][split][collapse][3d]") REQUIRE(op()); const auto& new_tets = op.new_tets_after_swap(); CHECK(new_tets.size() == 4); + CHECK(m.get_all(PrimitiveType::Tetrahedron).size() == 4); } } \ No newline at end of file