From 10291d4c2016a0f44ababae2a06f9b03285beb26 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Wed, 11 Oct 2023 16:18:52 -0400 Subject: [PATCH 01/19] build the skeleton --- components/wmtk_components/CMakeLists.txt | 3 +- .../regular_space/CMakeLists.txt | 9 +++ .../regular_space/internal/RegularSpace.cpp | 76 +++++++++++++++++++ .../regular_space/internal/RegularSpace.hpp | 24 ++++++ .../internal/RegularSpaceOptions.hpp | 33 ++++++++ .../regular_space/regular_space.cpp | 15 ++++ .../regular_space/regular_space.hpp | 9 +++ 7 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 components/wmtk_components/regular_space/CMakeLists.txt create mode 100644 components/wmtk_components/regular_space/internal/RegularSpace.cpp create mode 100644 components/wmtk_components/regular_space/internal/RegularSpace.hpp create mode 100644 components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp create mode 100644 components/wmtk_components/regular_space/regular_space.cpp create mode 100644 components/wmtk_components/regular_space/regular_space.hpp diff --git a/components/wmtk_components/CMakeLists.txt b/components/wmtk_components/CMakeLists.txt index 793a6e97c6..2e943e7875 100644 --- a/components/wmtk_components/CMakeLists.txt +++ b/components/wmtk_components/CMakeLists.txt @@ -2,4 +2,5 @@ add_subdirectory(delaunay) add_subdirectory(input) add_subdirectory(isotropic_remeshing) add_subdirectory(mesh_info) -add_subdirectory(output) \ No newline at end of file +add_subdirectory(output) +add_subdirectory(regular_space) \ No newline at end of file diff --git a/components/wmtk_components/regular_space/CMakeLists.txt b/components/wmtk_components/regular_space/CMakeLists.txt new file mode 100644 index 0000000000..726302c34b --- /dev/null +++ b/components/wmtk_components/regular_space/CMakeLists.txt @@ -0,0 +1,9 @@ + +set(SRC_FILES + internal/RegularSpaceOptions.hpp + internal/RegularSpace.hpp + internal/RegularSpace.cpp + regular_space.hpp + regular_space.cpp + ) +target_sources(wildmeshing_components PRIVATE ${SRC_FILES}) diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.cpp b/components/wmtk_components/regular_space/internal/RegularSpace.cpp new file mode 100644 index 0000000000..055171f445 --- /dev/null +++ b/components/wmtk_components/regular_space/internal/RegularSpace.cpp @@ -0,0 +1,76 @@ +#include "RegularSpace.hpp" + +#include +#include +#include +#include +#include + +namespace wmtk::components::internal { + +RegularSpace::RegularSpace(TriMesh& mesh, const double length, const bool lock_boundary) + : m_mesh{mesh} + , m_length_min{(4. / 5.) * length} + , m_length_max{(4. / 3.) * length} + , m_lock_boundary{lock_boundary} + , m_position_handle{m_mesh.get_attribute_handle("position", PrimitiveType::Vertex)} + , m_scheduler(m_mesh) +{ + using namespace operations; + // split + { + OperationSettings split_settings; + split_settings.position = m_position_handle; + // thresholds are inverted because we continue splitting because we + // always split until we're under this length, which is the max + // required length for the op to happen + split_settings.min_squared_length = m_length_max * m_length_max; + split_settings.split_settings.split_boundary_edges = !m_lock_boundary; + split_settings.initialize_invariants(m_mesh); + + m_scheduler.add_operation_type("split", split_settings); + } + // collapse + { + OperationSettings op_settings; + op_settings.position = m_position_handle; + // thresholds are inverted because we continue collapsing because we + // always collapse until we're over this length, which is the minimum + // required length for the op to happen + op_settings.max_squared_length = m_length_min * m_length_min; + op_settings.collapse_settings.collapse_boundary_edges = !m_lock_boundary; + op_settings.collapse_towards_boundary = true; + + op_settings.initialize_invariants(m_mesh); + m_scheduler.add_operation_type("collapse", op_settings); + } + // flip + { + OperationSettings op_settings; + op_settings.must_improve_valence = true; + + m_scheduler.add_operation_type("swap", op_settings); + } + // smooth + { + OperationSettings op_settings; + op_settings.smooth_settings.position = m_position_handle; + op_settings.smooth_settings.smooth_boundary = !m_lock_boundary; + + m_scheduler.add_operation_type( + "smooth", + op_settings); + } +} + +void RegularSpace::process(const long iterations) +{ + for (long i = 0; i < iterations; ++i) { + m_scheduler.run_operation_on_all(PrimitiveType::Edge, "split"); + m_scheduler.run_operation_on_all(PrimitiveType::Edge, "collapse"); + m_scheduler.run_operation_on_all(PrimitiveType::Edge, "swap"); + m_scheduler.run_operation_on_all(PrimitiveType::Vertex, "smooth"); + } +} + +} // namespace wmtk::components::internal diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.hpp b/components/wmtk_components/regular_space/internal/RegularSpace.hpp new file mode 100644 index 0000000000..5c4bbad526 --- /dev/null +++ b/components/wmtk_components/regular_space/internal/RegularSpace.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace wmtk::components::internal { + +class RegularSpace +{ + TriMesh& m_mesh; + double m_length_min = std::numeric_limits::max(); + double m_length_max = std::numeric_limits::lowest(); + bool m_lock_boundary = true; + + MeshAttributeHandle m_position_handle; + Scheduler m_scheduler; + +public: + RegularSpace(TriMesh& mesh, const double length, const bool lock_boundary); + + void process(const long iterations); +}; + +} // namespace wmtk::components::internal diff --git a/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp b/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp new file mode 100644 index 0000000000..8cb68bb9b9 --- /dev/null +++ b/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +namespace wmtk { +namespace components { +namespace internal { + +struct RegularSpaceOptions +{ + std::string type; + std::string input; + std::string output; + double length_abs = -1; + double length_rel = -1; + long iterations = -1; + bool lock_boundary = true; +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( + RegularSpaceOptions, + type, + input, + output, + length_abs, + length_rel, + iterations, + lock_boundary); + +} // namespace internal +} // namespace components +} // namespace wmtk \ No newline at end of file diff --git a/components/wmtk_components/regular_space/regular_space.cpp b/components/wmtk_components/regular_space/regular_space.cpp new file mode 100644 index 0000000000..b2478251b1 --- /dev/null +++ b/components/wmtk_components/regular_space/regular_space.cpp @@ -0,0 +1,15 @@ +#include "regular_space.hpp" + +#include +#include +#include +#include + +#include "internal/RegularSpace.hpp" +#include "internal/RegularSpaceOptions.hpp" + +namespace wmtk { +namespace components { +void regular_space(const nlohmann::json& j, std::map& files) {} +} // namespace components +} // namespace wmtk diff --git a/components/wmtk_components/regular_space/regular_space.hpp b/components/wmtk_components/regular_space/regular_space.hpp new file mode 100644 index 0000000000..6610c68930 --- /dev/null +++ b/components/wmtk_components/regular_space/regular_space.hpp @@ -0,0 +1,9 @@ +#pragma once +#include +#include + +namespace wmtk::components { + +void regular_space(const nlohmann::json& j, std::map& files); + +} // namespace wmtk::components From f618dbe1fa1a621b236cb946aed616046b615612 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Wed, 11 Oct 2023 18:38:03 -0400 Subject: [PATCH 02/19] add Todo invariant and EdgeSplitWithTag operation --- .../regular_space/internal/RegularSpace.cpp | 63 +------------ .../regular_space/internal/RegularSpace.hpp | 5 +- .../internal/RegularSpaceOptions.hpp | 18 ++-- src/wmtk/invariants/CMakeLists.txt | 2 + src/wmtk/invariants/TodoInvariant.cpp | 14 +++ src/wmtk/invariants/TodoInvariant.hpp | 17 ++++ src/wmtk/operations/tri_mesh/CMakeLists.txt | 2 + .../operations/tri_mesh/EdgeSplitWithTag.cpp | 90 +++++++++++++++++++ .../operations/tri_mesh/EdgeSplitWithTag.hpp | 62 +++++++++++++ tests/components/CMakeLists.txt | 1 + .../test_component_regular_space.cpp | 22 +++++ 11 files changed, 224 insertions(+), 72 deletions(-) create mode 100644 src/wmtk/invariants/TodoInvariant.cpp create mode 100644 src/wmtk/invariants/TodoInvariant.hpp create mode 100644 src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp create mode 100644 src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp create mode 100644 tests/components/test_component_regular_space.cpp diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.cpp b/components/wmtk_components/regular_space/internal/RegularSpace.cpp index 055171f445..871a8e4878 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpace.cpp +++ b/components/wmtk_components/regular_space/internal/RegularSpace.cpp @@ -8,69 +8,12 @@ namespace wmtk::components::internal { -RegularSpace::RegularSpace(TriMesh& mesh, const double length, const bool lock_boundary) +RegularSpace::RegularSpace(TriMesh& mesh, const bool lock_boundary) : m_mesh{mesh} - , m_length_min{(4. / 5.) * length} - , m_length_max{(4. / 3.) * length} , m_lock_boundary{lock_boundary} - , m_position_handle{m_mesh.get_attribute_handle("position", PrimitiveType::Vertex)} , m_scheduler(m_mesh) -{ - using namespace operations; - // split - { - OperationSettings split_settings; - split_settings.position = m_position_handle; - // thresholds are inverted because we continue splitting because we - // always split until we're under this length, which is the max - // required length for the op to happen - split_settings.min_squared_length = m_length_max * m_length_max; - split_settings.split_settings.split_boundary_edges = !m_lock_boundary; - split_settings.initialize_invariants(m_mesh); +{} - m_scheduler.add_operation_type("split", split_settings); - } - // collapse - { - OperationSettings op_settings; - op_settings.position = m_position_handle; - // thresholds are inverted because we continue collapsing because we - // always collapse until we're over this length, which is the minimum - // required length for the op to happen - op_settings.max_squared_length = m_length_min * m_length_min; - op_settings.collapse_settings.collapse_boundary_edges = !m_lock_boundary; - op_settings.collapse_towards_boundary = true; - - op_settings.initialize_invariants(m_mesh); - m_scheduler.add_operation_type("collapse", op_settings); - } - // flip - { - OperationSettings op_settings; - op_settings.must_improve_valence = true; - - m_scheduler.add_operation_type("swap", op_settings); - } - // smooth - { - OperationSettings op_settings; - op_settings.smooth_settings.position = m_position_handle; - op_settings.smooth_settings.smooth_boundary = !m_lock_boundary; - - m_scheduler.add_operation_type( - "smooth", - op_settings); - } -} - -void RegularSpace::process(const long iterations) -{ - for (long i = 0; i < iterations; ++i) { - m_scheduler.run_operation_on_all(PrimitiveType::Edge, "split"); - m_scheduler.run_operation_on_all(PrimitiveType::Edge, "collapse"); - m_scheduler.run_operation_on_all(PrimitiveType::Edge, "swap"); - m_scheduler.run_operation_on_all(PrimitiveType::Vertex, "smooth"); - } -} +void RegularSpace::process(const long iterations) {} } // namespace wmtk::components::internal diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.hpp b/components/wmtk_components/regular_space/internal/RegularSpace.hpp index 5c4bbad526..ecb16464b8 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpace.hpp +++ b/components/wmtk_components/regular_space/internal/RegularSpace.hpp @@ -8,15 +8,14 @@ namespace wmtk::components::internal { class RegularSpace { TriMesh& m_mesh; - double m_length_min = std::numeric_limits::max(); - double m_length_max = std::numeric_limits::lowest(); bool m_lock_boundary = true; MeshAttributeHandle m_position_handle; + Scheduler m_scheduler; public: - RegularSpace(TriMesh& mesh, const double length, const bool lock_boundary); + RegularSpace(TriMesh& mesh, const bool lock_boundary); void process(const long iterations); }; diff --git a/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp b/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp index 8cb68bb9b9..0edadaffb4 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp +++ b/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp @@ -9,12 +9,12 @@ namespace internal { struct RegularSpaceOptions { - std::string type; - std::string input; - std::string output; - double length_abs = -1; - double length_rel = -1; - long iterations = -1; + std::string type; // regular space + std::string input; // mesh input dir + std::string output; // mesh output dir + int demension; // 0-vertex 1-edge 2-face 3-tet + std::map tags_value; + long split_value = -1; bool lock_boundary = true; }; @@ -23,9 +23,9 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( type, input, output, - length_abs, - length_rel, - iterations, + demension, + tags_value, + split_value, lock_boundary); } // namespace internal diff --git a/src/wmtk/invariants/CMakeLists.txt b/src/wmtk/invariants/CMakeLists.txt index 2c62749a9f..4435fdcf8a 100644 --- a/src/wmtk/invariants/CMakeLists.txt +++ b/src/wmtk/invariants/CMakeLists.txt @@ -21,5 +21,7 @@ set(SRC_FILES MaxEdgeLengthInvariant.cpp MinEdgeLengthInvariant.hpp MinEdgeLengthInvariant.cpp + TodoInvariant.hpp + TodoInvariant.cpp ) target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) diff --git a/src/wmtk/invariants/TodoInvariant.cpp b/src/wmtk/invariants/TodoInvariant.cpp new file mode 100644 index 0000000000..85cfe0e356 --- /dev/null +++ b/src/wmtk/invariants/TodoInvariant.cpp @@ -0,0 +1,14 @@ +#include "TodoInvariant.hpp" +#include + +namespace wmtk { +TodoInvariant::TodoInvariant(const Mesh& m, const MeshAttributeHandle& todo_handle) + : MeshInvariant(m) + , m_todo_handle(todo_handle) +{} +bool TodoInvariant::before(const Tuple& t) const +{ + ConstAccessor split_todo_accessor = mesh().create_accessor(m_todo_handle); + return split_todo_accessor.const_vector_attribute(t)(0) == 1; +} +} // namespace wmtk \ No newline at end of file diff --git a/src/wmtk/invariants/TodoInvariant.hpp b/src/wmtk/invariants/TodoInvariant.hpp new file mode 100644 index 0000000000..c3b2326db1 --- /dev/null +++ b/src/wmtk/invariants/TodoInvariant.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include "MeshInvariant.hpp" + +namespace wmtk { +class TodoInvariant : public MeshInvariant +{ +public: + // NOTE: this takes in the threshold squared rather than the threshold itself + TodoInvariant(const Mesh& m, const MeshAttributeHandle& todo_handle); + bool before(const Tuple& t) const override; + +private: + const MeshAttributeHandle m_todo_handle; +}; +} // namespace wmtk \ No newline at end of file diff --git a/src/wmtk/operations/tri_mesh/CMakeLists.txt b/src/wmtk/operations/tri_mesh/CMakeLists.txt index b31f5c3020..4339e25e43 100644 --- a/src/wmtk/operations/tri_mesh/CMakeLists.txt +++ b/src/wmtk/operations/tri_mesh/CMakeLists.txt @@ -11,6 +11,8 @@ set(SRC_FILES EdgeCollapseToMidpoint.cpp EdgeSwap.hpp EdgeSwap.cpp + EdgeSplitWithTag.hpp + EdgeSplitWithTag.cpp VertexAttributesUpdateBase.hpp VertexAttributesUpdateBase.cpp VertexLaplacianSmooth.hpp diff --git a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp new file mode 100644 index 0000000000..8ca9cccf2e --- /dev/null +++ b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp @@ -0,0 +1,90 @@ +#include "EdgeSplitWithTag.hpp" +#include + +#include +#include +#include "EdgeSplit.hpp" + +namespace wmtk::operations { + + +void OperationSettings::initialize_invariants(const TriMesh& m) +{ + split_settings.initialize_invariants(m); + split_settings.invariants.add(std::make_shared(m, split_todo)); +} + +bool OperationSettings::are_invariants_initialized() const +{ + return split_settings.are_invariants_initialized() && + find_invariants_in_collection_by_type(split_settings.invariants); +} +namespace tri_mesh { +EdgeSplitWithTag::EdgeSplitWithTag( + Mesh& m, + const Tuple& t, + const OperationSettings& settings) + : TriMeshOperation(m) + , TupleOperation(settings.split_settings.invariants, t) + , m_pos_accessor{m.create_accessor(settings.position)} + , m_vertex_tag_accessor{m.create_accessor(settings.vertex_tag)} + , m_edge_tag_accessor{m.create_accessor(settings.edge_tag)} + , m_split_todo_accessor{m.create_accessor(settings.split_todo)} + , m_settings{settings} +{} +std::string EdgeSplitWithTag::name() const +{ + return "edge_split_with_tag"; +} +Tuple EdgeSplitWithTag::return_tuple() const +{ + return m_output_tuple; +} +bool EdgeSplitWithTag::before() const +{ + return TupleOperation::before(); +} +bool EdgeSplitWithTag::execute() +{ + Eigen::Vector3d p0 = m_pos_accessor.const_vector_attribute(input_tuple()); + Eigen::Vector3d p1 = m_pos_accessor.const_vector_attribute(mesh().switch_vertex(input_tuple())); + long et = m_edge_tag_accessor.scalar_attribute(input_tuple()); + long vt0 = m_vertex_tag_accessor.scalar_attribute(input_tuple()); + long vt1 = m_vertex_tag_accessor.scalar_attribute(mesh().switch_vertex(input_tuple())); + + { + EdgeSplit split_op(mesh(), input_tuple(), m_settings.split_settings); + if (!split_op()) { + return false; + } + m_output_tuple = split_op.return_tuple(); + } + m_pos_accessor.vector_attribute(m_output_tuple) = 0.5 * (p0 + p1); + // two split edge should be the split edge value, and the split vertex should be the split + // vertex value + m_vertex_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.split_vertex_tag_value; + m_edge_tag_accessor.scalar_attribute(mesh().switch_edge(m_output_tuple)) = + m_settings.split_edge_tag_value; + m_edge_tag_accessor.scalar_attribute(mesh().switch_edge(mesh().switch_face(m_output_tuple))) = + m_settings.split_edge_tag_value; + + // if the embedding tag value is needed, then assign two edges connect to the original edges + // with the embedding tag value, otherwise assign them with their neighbour's vertex's tag value + if (m_settings.need_embedding_tag_value) { + m_edge_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.embedding_tag_value; + m_edge_tag_accessor.scalar_attribute( + mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple)))) = + m_settings.embedding_tag_value; + } else { + m_edge_tag_accessor.scalar_attribute(m_output_tuple) = + m_vertex_tag_accessor.scalar_attribute(mesh().switch_vertex(m_output_tuple)); + m_edge_tag_accessor.scalar_attribute( + mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple)))) = + m_vertex_tag_accessor.scalar_attribute(mesh().switch_vertex( + mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple))))); + } + + return true; +} +} // namespace tri_mesh +} // namespace wmtk::operations \ No newline at end of file diff --git a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp new file mode 100644 index 0000000000..a672950f1d --- /dev/null +++ b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp @@ -0,0 +1,62 @@ +#pragma once +#include +#include +#include "EdgeSplit.hpp" + +namespace wmtk::operations { +namespace tri_mesh { +class EdgeSplitWithTag; +} + +enum { TAGS_DIFFERENT, TAGS_SAME }; + +template <> +struct OperationSettings +{ + OperationSettings split_settings; + // handle to vertex position + MeshAttributeHandle position; + MeshAttributeHandle vertex_tag; + MeshAttributeHandle edge_tag; + MeshAttributeHandle split_todo; + long split_vertex_tag_value; + long split_edge_tag_value; + long embedding_tag_value; + bool need_embedding_tag_value; + // too short edges get ignored + double min_squared_length = -1; + + void initialize_invariants(const TriMesh& m); + + // debug functionality to make sure operations are constructed properly + bool are_invariants_initialized() const; +}; + +namespace tri_mesh { +class EdgeSplitWithTag : public TriMeshOperation, private TupleOperation +{ +public: + EdgeSplitWithTag(Mesh& m, const Tuple& t, const OperationSettings& settings); + + std::string name() const override; + + Tuple return_tuple() const; + + static PrimitiveType primitive_type() { return PrimitiveType::Edge; } + +protected: + bool before() const override; + bool execute() override; + +private: + Tuple m_output_tuple; + Accessor m_pos_accessor; + Accessor m_vertex_tag_accessor; + Accessor m_edge_tag_accessor; + Accessor m_split_todo_accessor; + + const OperationSettings& m_settings; +}; + +} // namespace tri_mesh +} // namespace wmtk::operations \ No newline at end of file diff --git a/tests/components/CMakeLists.txt b/tests/components/CMakeLists.txt index 2eaf989711..dafebe9ec1 100644 --- a/tests/components/CMakeLists.txt +++ b/tests/components/CMakeLists.txt @@ -5,6 +5,7 @@ set(TEST_SOURCES test_component_mesh_info.cpp test_component_output.cpp test_component_isotropic_remeshing.cpp + test_component_regular_space.cpp ) target_sources(wmtk_tests PRIVATE ${TEST_SOURCES}) diff --git a/tests/components/test_component_regular_space.cpp b/tests/components/test_component_regular_space.cpp new file mode 100644 index 0000000000..80545afe28 --- /dev/null +++ b/tests/components/test_component_regular_space.cpp @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +using json = nlohmann::json; + +const std::filesystem::path data_dir = WMTK_DATA_DIR; + +TEST_CASE("component_regular_space", "[components][regular_space][.]") +{ + std::map files; + std::map tags_value; + + json regular_space_jason = { + {"type", "regular space"}, + {"input", "inputdir"}, /*input dir*/ + {"output", "outputdir"}, /*output dir*/ + {"demension", 1}, /*0 for vertex, 1 for edge, 2 for face, 3 for tet*/ + {"tags_value", tags_value}, + {"split_tag_value"}}; +} From b44c7f1172b4e21c3bb2cd194cddce42d761d660 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Thu, 12 Oct 2023 16:57:41 -0400 Subject: [PATCH 03/19] add FaceSplit basic operation and FaceSplitWithTag --- src/wmtk/operations/tri_mesh/CMakeLists.txt | 4 + src/wmtk/operations/tri_mesh/FaceSplit.cpp | 154 ++++++++++++++++++ src/wmtk/operations/tri_mesh/FaceSplit.hpp | 44 +++++ .../operations/tri_mesh/FaceSplitWithTag.cpp | 85 ++++++++++ .../operations/tri_mesh/FaceSplitWithTag.hpp | 59 +++++++ tests/test_2d_operations.cpp | 2 +- 6 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 src/wmtk/operations/tri_mesh/FaceSplit.cpp create mode 100644 src/wmtk/operations/tri_mesh/FaceSplit.hpp create mode 100644 src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp create mode 100644 src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp diff --git a/src/wmtk/operations/tri_mesh/CMakeLists.txt b/src/wmtk/operations/tri_mesh/CMakeLists.txt index 4339e25e43..528b1826c3 100644 --- a/src/wmtk/operations/tri_mesh/CMakeLists.txt +++ b/src/wmtk/operations/tri_mesh/CMakeLists.txt @@ -1,6 +1,10 @@ set(SRC_FILES TriMeshOperation.hpp TriMeshOperation.cpp + FaceSplit.hpp + FaceSplit.cpp + FaceSplitWithTag.hpp + FaceSplitWithTag.cpp EdgeSplit.hpp EdgeSplit.cpp EdgeSplitAtMidpoint.hpp diff --git a/src/wmtk/operations/tri_mesh/FaceSplit.cpp b/src/wmtk/operations/tri_mesh/FaceSplit.cpp new file mode 100644 index 0000000000..dd70e679b8 --- /dev/null +++ b/src/wmtk/operations/tri_mesh/FaceSplit.cpp @@ -0,0 +1,154 @@ +#include "FaceSplit.hpp" +#include +#include +#include +#include +#include +#include "EdgeCollapse.hpp" +#include "EdgeSplit.hpp" + +namespace wmtk::operations { +void OperationSettings::initialize_invariants(const TriMesh& m) +{ + invariants = basic_invariant_collection(m); +} + +bool OperationSettings::are_invariants_initialized() const +{ + return find_invariants_in_collection_by_type(invariants); +} +namespace tri_mesh { + +FaceSplit::FaceSplit(Mesh& m, const Tuple& t, const OperationSettings& settings) + : TriMeshOperation(m) + , TupleOperation(settings.invariants, t) + , m_pos_accessor{m.create_accessor(settings.position)} + , m_settings{settings} +{} + +std::string FaceSplit::name() const +{ + return "face_split_with_tag"; +} + +bool FaceSplit::before() const +{ + if (!mesh().is_valid_slow(input_tuple())) { + return false; + } + + return true; +} + +Tuple FaceSplit::return_tuple() const +{ + return m_output_tuple; +} + +bool FaceSplit::execute() +{ + Eigen::Vector3d p0 = m_pos_accessor.const_vector_attribute(input_tuple()); + Eigen::Vector3d p1 = m_pos_accessor.const_vector_attribute( + mesh().switch_edge(mesh().switch_vertex(input_tuple()))); + Eigen::Vector3d p2 = m_pos_accessor.const_vector_attribute(mesh().switch_vertex(input_tuple())); + // input + // p1 + // / \ + // / f \ + // / \ + // p0-->--p2 + // \ / + // \ / + // \ / + + Tuple split_ret; + { + OperationSettings op_settings; + op_settings.initialize_invariants(mesh()); + tri_mesh::EdgeSplit split_op(mesh(), input_tuple(), op_settings); + if (!split_op()) { + return false; + } + split_ret = split_op.return_tuple(); + } + + // after split + // /|\ + // / | \ + // / | f\ + // ---X--> + // \ | / + // \ | / + // \|/ + + // switch edge - switch face + // /|\ + // / v \ + // /f | \ + // ---X--- + // \ | / + // \ | / + // \|/ + const Tuple second_split_input_tuple = mesh().switch_vertex(mesh().switch_edge(split_ret)); + Tuple second_split_ret; + { + OperationSettings op_settings; + op_settings.initialize_invariants(mesh()); + tri_mesh::EdgeSplit split_op(mesh(), second_split_input_tuple, op_settings); + if (!split_op()) { + return false; + } + second_split_ret = split_op.return_tuple(); + } + // after split + // + // /|\ + // / | \ + // / X \ + // / /|\ \ + // /__/_v_\__\ + // \ | / + // \ | / + // \ | / + // \|/ + + + // collapse the split ret + // /|\ + // / | \ + // / /|\ \ + // / / | \ \ + // |/__X__\> + // \ | / + // \ | / + // \ | / + // \|/ + const Tuple coll_input_tuple = mesh().switch_edge(mesh().switch_vertex(second_split_ret)); + OperationSettings collapse_settings; + + collapse_settings.initialize_invariants(mesh()); + tri_mesh::EdgeCollapse coll_op(mesh(), coll_input_tuple, collapse_settings); + if (!coll_op()) { + return false; + } + const Tuple& coll_ret = coll_op.return_tuple(); + // collapse output + // /| \ + // / | \ + // / * f \ + // / / \ \ + // / / > \ + // |/_ _ _ _ \| + // \ / + // \ / + // \ / + // \ / + + // return new vertex's tuple + m_output_tuple = coll_ret; + return true; +} + + +} // namespace tri_mesh +} // namespace wmtk::operations \ No newline at end of file diff --git a/src/wmtk/operations/tri_mesh/FaceSplit.hpp b/src/wmtk/operations/tri_mesh/FaceSplit.hpp new file mode 100644 index 0000000000..6f54eb78e1 --- /dev/null +++ b/src/wmtk/operations/tri_mesh/FaceSplit.hpp @@ -0,0 +1,44 @@ +#pragma once +#include +#include +#include +#include "TriMeshOperation.hpp" + +namespace wmtk::operations { +namespace tri_mesh { +class FaceSplit; +} + +template <> +struct OperationSettings +{ + MeshAttributeHandle position; + InvariantCollection invariants; + void initialize_invariants(const TriMesh& m); + // debug functionality to make sure operations are constructed properly + bool are_invariants_initialized() const; +}; + +namespace tri_mesh { +class FaceSplit : public TriMeshOperation, private TupleOperation +{ +public: + FaceSplit(Mesh& m, const Tuple& t, const OperationSettings& settings); + + std::string name() const override; + Tuple return_tuple() const; + + static PrimitiveType primitive_type() { return PrimitiveType::Face; } + +protected: + bool execute() override; + bool before() const override; + +private: + Tuple m_output_tuple; + Accessor m_pos_accessor; + const OperationSettings& m_settings; +}; + +} // namespace tri_mesh +} // namespace wmtk::operations \ No newline at end of file diff --git a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp new file mode 100644 index 0000000000..4294fde59a --- /dev/null +++ b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp @@ -0,0 +1,85 @@ +#include "FaceSplitWithTag.hpp" +#include +#include + +#include + +namespace wmtk::operations { + + +void OperationSettings::initialize_invariants(const TriMesh& m) +{ + face_split_settings.initialize_invariants(m); + face_split_settings.invariants.add(std::make_shared(m, split_todo)); +} + +bool OperationSettings::are_invariants_initialized() const +{ + return face_split_settings.are_invariants_initialized() && + find_invariants_in_collection_by_type(face_split_settings.invariants); +} + +namespace tri_mesh { +FaceSplitWithTag::FaceSplitWithTag( + Mesh& m, + const Tuple& t, + const OperationSettings& settings) + : TriMeshOperation(m) + , TupleOperation(settings.face_split_settings.invariants, t) + , m_pos_accessor{m.create_accessor(settings.position)} + , m_vertex_tag_accessor{m.create_accessor(settings.vertex_tag)} + , m_edge_tag_accessor{m.create_accessor(settings.edge_tag)} + , m_split_todo_accessor{m.create_accessor(settings.split_todo)} + , m_settings{settings} +{ + p0 = m_pos_accessor.vector_attribute(input_tuple()); + p1 = m_pos_accessor.vector_attribute(mesh().switch_vertex(input_tuple())); + p2 = m_pos_accessor.vector_attribute(mesh().switch_vertex(mesh().switch_vertex(input_tuple()))); +} +std::string FaceSplitWithTag::name() const +{ + return "tri_mesh_split_edge_at_midpoint"; +} +Tuple FaceSplitWithTag::return_tuple() const +{ + return m_output_tuple; +} +bool FaceSplitWithTag::before() const +{ + return TupleOperation::before(); +} +bool FaceSplitWithTag::execute() +{ + { + FaceSplit split_op(mesh(), input_tuple(), m_settings.face_split_settings); + if (!split_op()) { + return false; + } + m_output_tuple = split_op.return_tuple(); + } + + m_pos_accessor.vector_attribute(m_output_tuple) = (p0 + p1 + p2) / 3.0; + m_vertex_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.split_vertex_tag_value; + + if (m_settings.need_embedding_tag_value) { + m_edge_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.embedding_tag_value; + m_edge_tag_accessor.scalar_attribute(mesh().switch_edge(m_output_tuple)) = + m_settings.embedding_tag_value; + m_edge_tag_accessor.scalar_attribute(mesh().switch_edge( + mesh().switch_face(m_output_tuple))) = m_settings.embedding_tag_value; + } else { + m_edge_tag_accessor.scalar_attribute(m_output_tuple) = + m_vertex_tag_accessor.const_scalar_attribute(mesh().switch_vertex(m_output_tuple)); + m_edge_tag_accessor.scalar_attribute(mesh().switch_edge(m_output_tuple)) = + m_vertex_tag_accessor.const_scalar_attribute( + mesh().switch_vertex(mesh().switch_edge(m_output_tuple))); + m_edge_tag_accessor.scalar_attribute( + mesh().switch_edge(mesh().switch_face(m_output_tuple))) = + m_vertex_tag_accessor.const_scalar_attribute( + mesh().switch_vertex(mesh().switch_edge(mesh().switch_face(m_output_tuple)))); + } + + return true; +} +} // namespace tri_mesh +} // namespace wmtk::operations diff --git a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp new file mode 100644 index 0000000000..2e79a02a24 --- /dev/null +++ b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp @@ -0,0 +1,59 @@ +#pragma once +#include +#include +#include "FaceSplit.hpp" + +namespace wmtk::operations { +namespace tri_mesh { +class FaceSplitWithTag; +} + +template <> +struct OperationSettings +{ + OperationSettings face_split_settings; + MeshAttributeHandle position; + MeshAttributeHandle vertex_tag; + MeshAttributeHandle edge_tag; + MeshAttributeHandle split_todo; + long split_vertex_tag_value; + long embedding_tag_value; + bool need_embedding_tag_value; + void initialize_invariants(const TriMesh& m); + // debug functionality to make sure operations are constructed properly + bool are_invariants_initialized() const; +}; + +namespace tri_mesh { +class FaceSplitWithTag : public TriMeshOperation, private TupleOperation +{ +public: + FaceSplitWithTag(Mesh& m, const Tuple& t, const OperationSettings& settings); + + std::string name() const override; + + Tuple return_tuple() const; + + static PrimitiveType primitive_type() { return PrimitiveType::Edge; } + +protected: + bool before() const override; + bool execute() override; + +private: + Tuple m_output_tuple; + + Accessor m_pos_accessor; + Accessor m_vertex_tag_accessor; + Accessor m_edge_tag_accessor; + Accessor m_split_todo_accessor; + + const OperationSettings& m_settings; + + Eigen::Vector3d p0; + Eigen::Vector3d p1; + Eigen::Vector3d p2; +}; + +} // namespace tri_mesh +} // namespace wmtk::operations diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index bc9d48dbb3..1582088d77 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1169,4 +1169,4 @@ TEST_CASE("swap_edge", "[operations][swap][2D]") REQUIRE(!success); REQUIRE(m.is_connectivity_valid()); } -} +} \ No newline at end of file From 8c07bffa0abad973949425601757bc99fa74d736 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Thu, 12 Oct 2023 19:30:46 -0400 Subject: [PATCH 04/19] fixed bug in Edge SplitWithTag, FaceSplitWithTag --- src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp | 7 +++++++ src/wmtk/operations/tri_mesh/FaceSplit.cpp | 6 +----- src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp | 4 ++++ tests/test_2d_operations.cpp | 8 ++++++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp index 8ca9cccf2e..5f2d0c9ab0 100644 --- a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp +++ b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp @@ -60,6 +60,13 @@ bool EdgeSplitWithTag::execute() m_output_tuple = split_op.return_tuple(); } m_pos_accessor.vector_attribute(m_output_tuple) = 0.5 * (p0 + p1); + m_split_todo_accessor.scalar_attribute(m_output_tuple) = 0; + m_split_todo_accessor.scalar_attribute(mesh().switch_edge(m_output_tuple)) = 0; + m_split_todo_accessor.scalar_attribute(mesh().switch_edge(mesh().switch_face(m_output_tuple))) = + 0; + m_split_todo_accessor.scalar_attribute( + mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple)))) = 0; + // two split edge should be the split edge value, and the split vertex should be the split // vertex value m_vertex_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.split_vertex_tag_value; diff --git a/src/wmtk/operations/tri_mesh/FaceSplit.cpp b/src/wmtk/operations/tri_mesh/FaceSplit.cpp index dd70e679b8..54295eedd5 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplit.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplit.cpp @@ -33,11 +33,7 @@ std::string FaceSplit::name() const bool FaceSplit::before() const { - if (!mesh().is_valid_slow(input_tuple())) { - return false; - } - - return true; + return TupleOperation::before(); } Tuple FaceSplit::return_tuple() const diff --git a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp index 4294fde59a..4439ae258a 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp @@ -60,6 +60,10 @@ bool FaceSplitWithTag::execute() m_pos_accessor.vector_attribute(m_output_tuple) = (p0 + p1 + p2) / 3.0; m_vertex_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.split_vertex_tag_value; + m_split_todo_accessor.scalar_attribute(m_output_tuple) = 0; + m_split_todo_accessor.scalar_attribute(mesh().switch_face(m_output_tuple)) = 0; + m_split_todo_accessor.scalar_attribute(mesh().switch_face(mesh().switch_edge(m_output_tuple))) = + 0; if (m_settings.need_embedding_tag_value) { m_edge_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.embedding_tag_value; diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 1582088d77..73b1631658 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1169,4 +1169,12 @@ TEST_CASE("swap_edge", "[operations][swap][2D]") REQUIRE(!success); REQUIRE(m.is_connectivity_valid()); } +} + +TEST_CASE("split_face", "[operations][split][2D]") +{ + SECTION("check_the_output_position") {} + SECTION("without_boundary") {} + SECTION("with_boundary") {} + SECTION("split_single_triangle") {} } \ No newline at end of file From 59490ace4a2dad5c7692ddc0b2e6d3ac13692df2 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Sat, 14 Oct 2023 22:18:29 -0400 Subject: [PATCH 05/19] test for split face --- src/wmtk/operations/tri_mesh/FaceSplit.cpp | 8 +----- src/wmtk/operations/tri_mesh/FaceSplit.hpp | 13 +++++++-- tests/test_2d_operations.cpp | 33 +++++++++++++++++++--- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/wmtk/operations/tri_mesh/FaceSplit.cpp b/src/wmtk/operations/tri_mesh/FaceSplit.cpp index 54295eedd5..f7edd2a256 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplit.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplit.cpp @@ -22,7 +22,6 @@ namespace tri_mesh { FaceSplit::FaceSplit(Mesh& m, const Tuple& t, const OperationSettings& settings) : TriMeshOperation(m) , TupleOperation(settings.invariants, t) - , m_pos_accessor{m.create_accessor(settings.position)} , m_settings{settings} {} @@ -43,10 +42,6 @@ Tuple FaceSplit::return_tuple() const bool FaceSplit::execute() { - Eigen::Vector3d p0 = m_pos_accessor.const_vector_attribute(input_tuple()); - Eigen::Vector3d p1 = m_pos_accessor.const_vector_attribute( - mesh().switch_edge(mesh().switch_vertex(input_tuple()))); - Eigen::Vector3d p2 = m_pos_accessor.const_vector_attribute(mesh().switch_vertex(input_tuple())); // input // p1 // / \ @@ -108,7 +103,6 @@ bool FaceSplit::execute() // \ | / // \|/ - // collapse the split ret // /|\ // / | \ @@ -141,7 +135,7 @@ bool FaceSplit::execute() // \ / // return new vertex's tuple - m_output_tuple = coll_ret; + m_output_tuple = mesh().switch_vertex(coll_ret); return true; } diff --git a/src/wmtk/operations/tri_mesh/FaceSplit.hpp b/src/wmtk/operations/tri_mesh/FaceSplit.hpp index 6f54eb78e1..8c04fede40 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplit.hpp +++ b/src/wmtk/operations/tri_mesh/FaceSplit.hpp @@ -12,7 +12,6 @@ class FaceSplit; template <> struct OperationSettings { - MeshAttributeHandle position; InvariantCollection invariants; void initialize_invariants(const TriMesh& m); // debug functionality to make sure operations are constructed properly @@ -26,6 +25,17 @@ class FaceSplit : public TriMeshOperation, private TupleOperation FaceSplit(Mesh& m, const Tuple& t, const OperationSettings& settings); std::string name() const override; + + // the return tuple is the new vertex, arrow to the original vertex + // the new vertex's position is equal to the P's. + // / | \ + // / | \ + // / _*_ \ + // / _< f \_ \ + // |/_______\P + // \ / + // \ / + // \ / Tuple return_tuple() const; static PrimitiveType primitive_type() { return PrimitiveType::Face; } @@ -36,7 +46,6 @@ class FaceSplit : public TriMeshOperation, private TupleOperation private: Tuple m_output_tuple; - Accessor m_pos_accessor; const OperationSettings& m_settings; }; diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 73b1631658..9361743503 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "tools/DEBUG_TriMesh.hpp" #include "tools/TriMesh_examples.hpp" @@ -1173,8 +1174,32 @@ TEST_CASE("swap_edge", "[operations][swap][2D]") TEST_CASE("split_face", "[operations][split][2D]") { - SECTION("check_the_output_position") {} - SECTION("without_boundary") {} - SECTION("with_boundary") {} - SECTION("split_single_triangle") {} + using namespace operations; + SECTION("split_single_triangle") + { + // this case also test the on boundary case + /* V.row(0) << 0, 0, 0; + V.row(1) << 1, 0, 0; + V.row(2) << 0.5, 0.866, 0;*/ + DEBUG_TriMesh m = single_triangle_with_position(); + Tuple f = m.face_tuple_from_vids(0, 1, 2); + OperationSettings settings; + settings.initialize_invariants(m); + wmtk::operations::tri_mesh::FaceSplit face_split_op(m, f, settings); + bool is_success = face_split_op(); + Tuple ret = face_split_op.return_tuple(); + wmtk::attribute::MeshAttributeHandle handle = + m.get_attribute_handle(std::string("position"), PV); + Eigen::Vector3d p_ret = (m.create_accessor(handle)).vector_attribute(ret); + REQUIRE(is_success); + REQUIRE(m.get_all(PV).size() == 4); + REQUIRE(!m.is_boundary_vertex(ret)); + REQUIRE(!m.is_boundary_edge(ret)); + REQUIRE(!m.is_boundary_edge(m.switch_edge(ret))); + REQUIRE(m.id(ret, PV) == 4); + REQUIRE(m.id(m.switch_vertex(ret), PV) == 0); + REQUIRE(m.id(m.switch_vertex(m.switch_edge(ret)), PV) == 1); + REQUIRE(p_ret.x() == 1 && p_ret.y() == 0 && p_ret.z() == 0); + } + SECTION("not_on_boundary") {} } \ No newline at end of file From 12762173cfac298d024fe6a9dabc0f1d92f83a81 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Sat, 14 Oct 2023 22:24:55 -0400 Subject: [PATCH 06/19] remove the && operator in the REQUIRE function --- tests/test_2d_operations.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 9361743503..0df3a63dde 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1177,7 +1177,6 @@ TEST_CASE("split_face", "[operations][split][2D]") using namespace operations; SECTION("split_single_triangle") { - // this case also test the on boundary case /* V.row(0) << 0, 0, 0; V.row(1) << 1, 0, 0; V.row(2) << 0.5, 0.866, 0;*/ @@ -1199,7 +1198,10 @@ TEST_CASE("split_face", "[operations][split][2D]") REQUIRE(m.id(ret, PV) == 4); REQUIRE(m.id(m.switch_vertex(ret), PV) == 0); REQUIRE(m.id(m.switch_vertex(m.switch_edge(ret)), PV) == 1); - REQUIRE(p_ret.x() == 1 && p_ret.y() == 0 && p_ret.z() == 0); + REQUIRE(p_ret.x() == 1); + REQUIRE(p_ret.y() == 0); + REQUIRE(p_ret.z() == 0); } - SECTION("not_on_boundary") {} + SECTION("without_boundary") {} + SECTION("with_boundary") {} } \ No newline at end of file From 5dce9a14fd6e77547e265d36ff0b24189b192b46 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Sat, 14 Oct 2023 22:41:12 -0400 Subject: [PATCH 07/19] correct the comments and remove unnecessary code --- src/wmtk/operations/tri_mesh/FaceSplit.hpp | 4 ++-- tests/test_2d_operations.cpp | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/wmtk/operations/tri_mesh/FaceSplit.hpp b/src/wmtk/operations/tri_mesh/FaceSplit.hpp index 8c04fede40..2e9f19a518 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplit.hpp +++ b/src/wmtk/operations/tri_mesh/FaceSplit.hpp @@ -27,12 +27,12 @@ class FaceSplit : public TriMeshOperation, private TupleOperation std::string name() const override; // the return tuple is the new vertex, arrow to the original vertex - // the new vertex's position is equal to the P's. + // this operation never set the position of the new vertex. // / | \ // / | \ // / _*_ \ // / _< f \_ \ - // |/_______\P + // |/_______\| // \ / // \ / // \ / diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 0df3a63dde..a172bc0b8c 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1187,9 +1187,6 @@ TEST_CASE("split_face", "[operations][split][2D]") wmtk::operations::tri_mesh::FaceSplit face_split_op(m, f, settings); bool is_success = face_split_op(); Tuple ret = face_split_op.return_tuple(); - wmtk::attribute::MeshAttributeHandle handle = - m.get_attribute_handle(std::string("position"), PV); - Eigen::Vector3d p_ret = (m.create_accessor(handle)).vector_attribute(ret); REQUIRE(is_success); REQUIRE(m.get_all(PV).size() == 4); REQUIRE(!m.is_boundary_vertex(ret)); @@ -1198,9 +1195,6 @@ TEST_CASE("split_face", "[operations][split][2D]") REQUIRE(m.id(ret, PV) == 4); REQUIRE(m.id(m.switch_vertex(ret), PV) == 0); REQUIRE(m.id(m.switch_vertex(m.switch_edge(ret)), PV) == 1); - REQUIRE(p_ret.x() == 1); - REQUIRE(p_ret.y() == 0); - REQUIRE(p_ret.z() == 0); } SECTION("without_boundary") {} SECTION("with_boundary") {} From 6ad532a87f026cc7b22b06f5ef9f4488247d5df2 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Sun, 15 Oct 2023 15:09:03 -0400 Subject: [PATCH 08/19] test for the split edge with tag --- .../internal/RegularSpaceOptions.hpp | 6 +- .../test_component_regular_space.cpp | 2 +- tests/test_2d_operations.cpp | 217 +++++++++++++++++- 3 files changed, 213 insertions(+), 12 deletions(-) diff --git a/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp b/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp index 0edadaffb4..df456900ef 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp +++ b/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp @@ -13,7 +13,8 @@ struct RegularSpaceOptions std::string input; // mesh input dir std::string output; // mesh output dir int demension; // 0-vertex 1-edge 2-face 3-tet - std::map tags_value; + long input_value; + long embedding_value; long split_value = -1; bool lock_boundary = true; }; @@ -24,7 +25,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( input, output, demension, - tags_value, + input_value, + embedding_value, split_value, lock_boundary); diff --git a/tests/components/test_component_regular_space.cpp b/tests/components/test_component_regular_space.cpp index 80545afe28..3a1e7188d0 100644 --- a/tests/components/test_component_regular_space.cpp +++ b/tests/components/test_component_regular_space.cpp @@ -19,4 +19,4 @@ TEST_CASE("component_regular_space", "[components][regular_space][.]") {"demension", 1}, /*0 for vertex, 1 for edge, 2 for face, 3 for tet*/ {"tags_value", tags_value}, {"split_tag_value"}}; -} +} \ No newline at end of file diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index a172bc0b8c..19d60f317f 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -6,9 +6,11 @@ #include #include #include +#include #include #include #include +#include #include "tools/DEBUG_TriMesh.hpp" #include "tools/TriMesh_examples.hpp" @@ -1177,25 +1179,222 @@ TEST_CASE("split_face", "[operations][split][2D]") using namespace operations; SECTION("split_single_triangle") { - /* V.row(0) << 0, 0, 0; - V.row(1) << 1, 0, 0; - V.row(2) << 0.5, 0.866, 0;*/ - DEBUG_TriMesh m = single_triangle_with_position(); - Tuple f = m.face_tuple_from_vids(0, 1, 2); + // 0 + // / \ + // 2 1 + // / 0 \ + // / \ + // 1 ----0---- 2 + // + // this case covered the on boundary case + DEBUG_TriMesh m = single_triangle(); + Tuple f = m.edge_tuple_between_v1_v2(1, 2, 0); + spdlog::info("{}", m.id(f, PV)); + spdlog::info("{}", m.id(m.switch_vertex(f), PV)); + spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f)), PV)); OperationSettings settings; settings.initialize_invariants(m); wmtk::operations::tri_mesh::FaceSplit face_split_op(m, f, settings); bool is_success = face_split_op(); Tuple ret = face_split_op.return_tuple(); + spdlog::info("{}", m.id(ret, PV)); + spdlog::info("{}", m.id(m.switch_vertex(ret), PV)); + spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(ret)), PV)); REQUIRE(is_success); REQUIRE(m.get_all(PV).size() == 4); REQUIRE(!m.is_boundary_vertex(ret)); REQUIRE(!m.is_boundary_edge(ret)); REQUIRE(!m.is_boundary_edge(m.switch_edge(ret))); REQUIRE(m.id(ret, PV) == 4); - REQUIRE(m.id(m.switch_vertex(ret), PV) == 0); - REQUIRE(m.id(m.switch_vertex(m.switch_edge(ret)), PV) == 1); + REQUIRE(m.id(m.switch_vertex(ret), PV) == 1); + REQUIRE(m.id(m.switch_vertex(m.switch_edge(ret)), PV) == 2); + REQUIRE(SimplicialComplex::vertex_one_ring(m, ret).size() == 3); + } + SECTION("split in quad") + { + // 3--1--- 0 + // | / \ . + // 2 f1 /2 1 + // | 0/ f0 \ . + // | / \ . + // 1 ----0---- 2 + // + DEBUG_TriMesh m = interior_edge(); + Tuple f = m.edge_tuple_between_v1_v2(1, 0, 1); + spdlog::info("{}", m.id(f, PV)); + spdlog::info("{}", m.id(m.switch_vertex(f), PV)); + spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f)), PV)); + Tuple split_ret; + { + OperationSettings op_settings; + op_settings.initialize_invariants(m); + tri_mesh::EdgeSplit split_op(m, f, op_settings); + split_op(); + split_ret = split_op.return_tuple(); + } + spdlog::info("{}", m.id(split_ret, PV)); + spdlog::info("{}", m.id(m.switch_vertex(split_ret), PV)); + spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(split_ret)), PV)); + const Tuple coll_input_tuple = m.switch_face(m.switch_edge(split_ret)); + OperationSettings collapse_settings; + collapse_settings.initialize_invariants(m); + tri_mesh::EdgeCollapse coll_op(m, coll_input_tuple, collapse_settings); + coll_op(); + const Tuple& coll_ret = coll_op.return_tuple(); + auto ret = m.switch_vertex(m.switch_edge(coll_ret)); + spdlog::info("{} {}", m.id(ret, PV), m.id(m.switch_vertex(ret), PV)); + + // DEBUG_TriMesh m = quad(); + // Tuple f = m.edge_tuple_between_v1_v2(1, 0, 1); + // OperationSettings settings; + // settings.initialize_invariants(m); + // wmtk::operations::tri_mesh::FaceSplit op(m, f, settings); + // spdlog::info("{}", m.id(f, PV)); + // spdlog::info("{}", m.id(m.switch_vertex(f), PV)); + // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f)), PV)); + // REQUIRE(op()); + // spdlog::info("{}", m.id(op.return_tuple(), PV)); + // spdlog::info("{}", m.id(m.switch_vertex(op.return_tuple()), PV)); + // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(op.return_tuple())), PV)); + // spdlog::info("{}", SimplicialComplex::vertex_one_ring(m, op.return_tuple()).size()); + // for (auto t : m.get_all(PV)) { + // spdlog::info("{}: {}", m.id(t, PV), SimplicialComplex::vertex_one_ring(m, t).size()); + // } + } + SECTION("split in diamond") + { + // 0---1---2 + // / \ / \ / \ . + // 3---4---5---6 + // \ / \ / \ / + // 7---8---9 + DEBUG_TriMesh m = edge_region_with_position(); + + // auto e = m.edge_tuple_between_v1_v2(9, 6, 9); + // OperationSettings collapse_settings; + // collapse_settings.initialize_invariants(m); + // wmtk::operations::tri_mesh::EdgeCollapse co(m, e, collapse_settings); + // spdlog::info("{}", m.id(e, PV)); + // spdlog::info("{}", m.id(m.switch_vertex(e), PV)); + // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(e)), PV)); + // REQUIRE(co()); + // spdlog::info("{}", m.id(co.return_tuple(), PV)); + // spdlog::info("{}", m.id(m.switch_vertex(co.return_tuple()), PV)); + // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(co.return_tuple())), PV)); + + Tuple f0 = m.edge_tuple_between_v1_v2(3, 4, 0); // on boundary + Tuple f1 = m.edge_tuple_between_v1_v2(8, 9, 8); // out boundary + Tuple f2 = m.edge_tuple_between_v1_v2(4, 8, 7); // overlap of f0 and f1 + OperationSettings settings; + settings.initialize_invariants(m); + wmtk::operations::tri_mesh::FaceSplit op0(m, f0, settings); + wmtk::operations::tri_mesh::FaceSplit op1(m, f1, settings); + wmtk::operations::tri_mesh::FaceSplit op2(m, f2, settings); + + spdlog::info("{}", m.id(f0, PV)); + spdlog::info("{}", m.id(m.switch_vertex(f0), PV)); + spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f0)), PV)); + REQUIRE(op0()); + spdlog::info("{}", m.id(op0.return_tuple(), PV)); + spdlog::info("{}", m.id(m.switch_vertex(op0.return_tuple()), PV)); + spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(op0.return_tuple())), PV)); + + auto handle = m.get_attribute_handle(std::string("position"), PV); + auto acc = m.create_accessor(handle); + REQUIRE(op1()); + REQUIRE(!op2()); + spdlog::info("{}", m.get_all(PV).size()); + for (auto v : m.get_all(PV)) { + spdlog::info("{}", m.id(v, PV)); + } + } +} + + +TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") +{ + // 3--1--- 0 + // | / \ . + // 2 f1 /2 1 + // | 0/ f0 \ . + // | / \ . + // 1 ----0---- 2 + // \ / + // \ f2 / + // \ / + // \ / + // 4 + using namespace operations; + + Eigen::MatrixXd V(5, 3); + V << 0, 0, 0, -1, -1, 0, 1, -1, 0, -1, 1, 0, 1, -1, 0; + + SECTION("should all fail") + { + DEBUG_TriMesh m = interior_edge(); + OperationSettings settings; + wmtk::MeshAttributeHandle edge_handle = + m.register_attribute(std::string("edge_tag"), PE, 1); + wmtk::MeshAttributeHandle vertex_handle = + m.register_attribute(std::string("vertex_tag"), PV, 1); + wmtk::MeshAttributeHandle todo_handle = + m.register_attribute(std::string("todo_tag"), PE, 1); + wmtk::mesh_utils::set_matrix_attribute(V, "position", PrimitiveType::Vertex, m); + settings.edge_tag = edge_handle; + settings.vertex_tag = vertex_handle; + settings.embedding_tag_value = -1; + settings.need_embedding_tag_value = true; + settings.position = m.get_attribute_handle(std::string("position"), PV); + settings.split_settings.split_boundary_edges = true; + settings.split_edge_tag_value = -2; + settings.split_vertex_tag_value = -3; + settings.split_todo = todo_handle; + settings.initialize_invariants(m); + for (Tuple t : m.get_all(PV)) { + wmtk::operations::tri_mesh::EdgeSplitWithTag op(m, t, settings); + REQUIRE(!op()); + } + } + + SECTION("check the embedding value and the operations should only success once") + { + DEBUG_TriMesh m = interior_edge(); + OperationSettings settings; + wmtk::MeshAttributeHandle edge_handle = + m.register_attribute(std::string("edge_tag"), PE, 1); + wmtk::MeshAttributeHandle vertex_handle = + m.register_attribute(std::string("vertex_tag"), PV, 1); + wmtk::MeshAttributeHandle todo_handle = + m.register_attribute(std::string("todo_tag"), PE, 1); + wmtk::mesh_utils::set_matrix_attribute(V, "position", PrimitiveType::Vertex, m); + settings.edge_tag = edge_handle; + settings.vertex_tag = vertex_handle; + settings.embedding_tag_value = -1; + settings.need_embedding_tag_value = true; + settings.position = m.get_attribute_handle(std::string("position"), PV); + settings.split_settings.split_boundary_edges = true; + settings.split_edge_tag_value = -2; + settings.split_vertex_tag_value = -3; + settings.split_todo = todo_handle; + settings.initialize_invariants(m); + std::vector edges = m.get_all(PE); + wmtk::Accessor acc = m.create_accessor(todo_handle); + wmtk::Accessor acc_e = m.create_accessor(edge_handle); + wmtk::Accessor acc_v = m.create_accessor(vertex_handle); + Tuple e0 = m.edge_tuple_between_v1_v2(1, 0, 1); + Tuple e1 = m.edge_tuple_between_v1_v2(1, 2, 0); + acc.scalar_attribute(e0) = 1; + acc.scalar_attribute(e1) = 1; + wmtk::operations::tri_mesh::EdgeSplitWithTag op0(m, e0, settings); + REQUIRE(op0()); + REQUIRE(acc_e.scalar_attribute(op0.return_tuple()) == -1); + REQUIRE(acc_e.scalar_attribute(m.switch_edge(op0.return_tuple())) == -2); + REQUIRE( + acc_e.scalar_attribute( + m.switch_edge(m.switch_face(m.switch_edge(op0.return_tuple())))) == -1); + REQUIRE(acc_e.scalar_attribute(m.switch_edge(m.switch_face(op0.return_tuple()))) == -2); + REQUIRE(acc_v.scalar_attribute(op0.return_tuple()) == -3); + wmtk::operations::tri_mesh::EdgeSplitWithTag op1(m, e1, settings); + REQUIRE(!op1()); } - SECTION("without_boundary") {} - SECTION("with_boundary") {} } \ No newline at end of file From b1cf846f14787b9e983e01147d1f8a7ba474903c Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Sun, 15 Oct 2023 15:23:40 -0400 Subject: [PATCH 09/19] check if operations is valid when todotag is 1 --- tests/test_2d_operations.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 19d60f317f..a3331f01c2 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1356,7 +1356,7 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") } } - SECTION("check the embedding value and the operations should only success once") + SECTION("check the embedding value and the operations should only success twice") { DEBUG_TriMesh m = interior_edge(); OperationSettings settings; @@ -1387,6 +1387,14 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") acc.scalar_attribute(e1) = 1; wmtk::operations::tri_mesh::EdgeSplitWithTag op0(m, e0, settings); REQUIRE(op0()); + // todo marks should be removed + REQUIRE(acc.scalar_attribute(op0.return_tuple()) == 0); + REQUIRE(acc.scalar_attribute(m.switch_edge(op0.return_tuple())) == 0); + REQUIRE( + acc.scalar_attribute(m.switch_edge(m.switch_face(m.switch_edge(op0.return_tuple())))) == + 0); + REQUIRE(acc.scalar_attribute(m.switch_edge(m.switch_face(op0.return_tuple()))) == 0); + // new tag value should be marked REQUIRE(acc_e.scalar_attribute(op0.return_tuple()) == -1); REQUIRE(acc_e.scalar_attribute(m.switch_edge(op0.return_tuple())) == -2); REQUIRE( @@ -1394,7 +1402,13 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") m.switch_edge(m.switch_face(m.switch_edge(op0.return_tuple())))) == -1); REQUIRE(acc_e.scalar_attribute(m.switch_edge(m.switch_face(op0.return_tuple()))) == -2); REQUIRE(acc_v.scalar_attribute(op0.return_tuple()) == -3); - wmtk::operations::tri_mesh::EdgeSplitWithTag op1(m, e1, settings); - REQUIRE(!op1()); + int success_num = 0; + for (Tuple t : m.get_all(PE)) { + wmtk::operations::tri_mesh::EdgeSplitWithTag op(m, t, settings); + if (op()) { + success_num++; + } + } + REQUIRE(success_num == 1); } } \ No newline at end of file From 298698d784ce72ca505967fa3a2ae3011c5a4dee Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Sun, 15 Oct 2023 19:59:16 -0400 Subject: [PATCH 10/19] RegularSpace 2d and 1d finished --- .../regular_space/internal/RegularSpace.cpp | 202 +++++++++++++++++- .../regular_space/internal/RegularSpace.hpp | 25 ++- .../operations/tri_mesh/FaceSplitWithTag.cpp | 3 + 3 files changed, 222 insertions(+), 8 deletions(-) diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.cpp b/components/wmtk_components/regular_space/internal/RegularSpace.cpp index 871a8e4878..65a4ceef56 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpace.cpp +++ b/components/wmtk_components/regular_space/internal/RegularSpace.cpp @@ -3,17 +3,209 @@ #include #include #include +#include #include +#include #include namespace wmtk::components::internal { -RegularSpace::RegularSpace(TriMesh& mesh, const bool lock_boundary) - : m_mesh{mesh} - , m_lock_boundary{lock_boundary} - , m_scheduler(m_mesh) +RegularSpace::RegularSpace( + TriMesh& mesh, + MeshAttributeHandle position_handle, + MeshAttributeHandle vertex_tag, + MeshAttributeHandle edge_tag, + long input_tag_value, + long embedding_tag_value, + long split_tag_value, + int m_dimension = 2, + const bool lock_boundary = true) + : m_mesh(mesh) + , m_position_handle(position_handle) + , m_vertex_tag(vertex_tag) + , m_edge_tag(edge_tag) + , m_input_tag_value(input_tag_value) + , m_embedding_tag_value(embedding_tag_value) + , m_split_tag_value(split_tag_value) + , m_scheduler(mesh) + , m_lock_boundary(lock_boundary) {} -void RegularSpace::process(const long iterations) {} +void RegularSpace::process() +{ + switch (m_dimension) { + case 1: process_in_1d(); break; + case 2: process_in_2d(); break; + case 3: throw std::runtime_error("3 dimension has not been implemented!"); break; + default: throw std::runtime_error("settings went wrong!"); break; + } +} + +void RegularSpace::process_in_1d() +{ + using namespace operations; + + wmtk::MeshAttributeHandle todo_edgesplit_same_handle = m_mesh.register_attribute( + std::string("todo_edgesplit_same_tag"), + wmtk::PrimitiveType::Edge, + 1); + wmtk::Accessor acc_vertex_tag = m_mesh.create_accessor(m_vertex_tag); + wmtk::Accessor acc_pos = m_mesh.create_accessor(m_position_handle); + wmtk::Accessor acc_todo_edgesplit_same_tag = + m_mesh.create_accessor(todo_edgesplit_same_handle); + + // edge split + { + // compute the todo list for the split edge with the same ends + const std::vector& edges = m_mesh.get_all(wmtk::PrimitiveType::Edge); + for (const Tuple& edge : edges) { + long vt0, vt1; + vt0 = acc_vertex_tag.scalar_attribute(edge); + vt1 = acc_vertex_tag.scalar_attribute(m_mesh.switch_vertex(edge)); + if (vt0 == m_input_tag_value && vt1 == m_input_tag_value) { + acc_todo_edgesplit_same_tag.scalar_attribute(edge) = 1; + } + } + // using scheduler to do edge splitting + OperationSettings settings_split_same; + settings_split_same.edge_tag = m_edge_tag; + settings_split_same.vertex_tag = m_vertex_tag; + settings_split_same.embedding_tag_value = m_embedding_tag_value; + settings_split_same.need_embedding_tag_value = true; + settings_split_same.position = m_position_handle; + settings_split_same.split_settings.split_boundary_edges = true; + settings_split_same.split_edge_tag_value = m_embedding_tag_value; + settings_split_same.split_vertex_tag_value = m_split_tag_value; + settings_split_same.split_todo = todo_edgesplit_same_handle; + settings_split_same.initialize_invariants(m_mesh); + m_scheduler.add_operation_type( + "edge_split", + settings_split_same); + while (true) { + m_scheduler.run_operation_on_all(PrimitiveType::Edge, "edge_split"); + if (m_scheduler.number_of_successful_operations() == 0) { + break; + } + } + } +} + +void RegularSpace::process_in_2d() +{ + using namespace operations; + + wmtk::MeshAttributeHandle todo_facesplit_handle = m_mesh.register_attribute( + std::string("todo_facesplit_tag"), + wmtk::PrimitiveType::Edge, + 1); + wmtk::MeshAttributeHandle todo_edgesplit_same_handle = m_mesh.register_attribute( + std::string("todo_edgesplit_same_tag"), + wmtk::PrimitiveType::Edge, + 1); + // wmtk::MeshAttributeHandle todo_edgesplit_diff_handle = m_mesh.register_attribute( + // std::string("todo_edgesplit_diff_tag"), + // wmtk::PrimitiveType::Edge, + // 1); + wmtk::Accessor acc_vertex_tag = m_mesh.create_accessor(m_vertex_tag); + wmtk::Accessor acc_edge_tag = m_mesh.create_accessor(m_edge_tag); + wmtk::Accessor acc_pos = m_mesh.create_accessor(m_position_handle); + wmtk::Accessor acc_todo_face_tag = m_mesh.create_accessor(todo_facesplit_handle); + wmtk::Accessor acc_todo_edgesplit_same_tag = + m_mesh.create_accessor(todo_edgesplit_same_handle); + // wmtk::Accessor acc_todo_edgesplit_diff_tag = + // m_mesh.create_accessor(todo_edgesplit_diff_handle); + + // face split + { + const std::vector& faces = m_mesh.get_all(wmtk::PrimitiveType::Face); + for (const Tuple& face : faces) { + long vt0, vt1, vt2, et0, et1, et2; + vt0 = acc_vertex_tag.scalar_attribute(face); + vt1 = acc_vertex_tag.scalar_attribute(m_mesh.switch_vertex(face)); + vt2 = acc_vertex_tag.scalar_attribute(m_mesh.switch_vertex(m_mesh.switch_edge(face))); + et0 = acc_edge_tag.scalar_attribute(face); + et1 = acc_edge_tag.scalar_attribute(m_mesh.switch_vertex(face)); + et2 = acc_edge_tag.scalar_attribute(m_mesh.switch_vertex(m_mesh.switch_edge(face))); + if (vt0 == m_input_tag_value && vt1 == m_input_tag_value && vt2 == m_input_tag_value && + et0 == m_input_tag_value && et1 == m_input_tag_value && et2 == m_input_tag_value) { + acc_todo_face_tag.scalar_attribute(face) = 1; + } + } + // using scheduler to do face splitting + OperationSettings settings_split_face; + settings_split_face.edge_tag = m_edge_tag; + settings_split_face.embedding_tag_value = m_embedding_tag_value; + settings_split_face.need_embedding_tag_value = true; + settings_split_face.position = m_position_handle; + settings_split_face.split_todo = todo_facesplit_handle; + settings_split_face.split_vertex_tag_value = m_split_tag_value; + settings_split_face.vertex_tag = m_vertex_tag; + settings_split_face.face_split_settings.initialize_invariants(m_mesh); + m_scheduler.add_operation_type( + "facesplit", + settings_split_face); + while (true) { + m_scheduler.run_operation_on_all(PrimitiveType::Edge, "facesplit"); + if (m_scheduler.number_of_successful_operations() == 0) { + break; + } + } + } + + // edge split + { + // compute the todo list for the split edge with the same ends + const std::vector& edges = m_mesh.get_all(wmtk::PrimitiveType::Edge); + for (const Tuple& edge : edges) { + long vt0, vt1, et0; + vt0 = acc_vertex_tag.scalar_attribute(edge); + vt1 = acc_vertex_tag.scalar_attribute(m_mesh.switch_vertex(edge)); + et0 = acc_edge_tag.scalar_attribute(edge); + if (vt0 == m_input_tag_value && vt1 == m_input_tag_value && + et0 == m_embedding_tag_value) { + acc_todo_edgesplit_same_tag.scalar_attribute(edge) = 1; + } + } + // using scheduler to do edge splitting + OperationSettings settings_split_same; + settings_split_same.edge_tag = m_edge_tag; + settings_split_same.vertex_tag = m_vertex_tag; + settings_split_same.embedding_tag_value = m_embedding_tag_value; + settings_split_same.need_embedding_tag_value = true; + settings_split_same.position = m_position_handle; + settings_split_same.split_settings.split_boundary_edges = true; + settings_split_same.split_edge_tag_value = m_embedding_tag_value; + settings_split_same.split_vertex_tag_value = m_split_tag_value; + settings_split_same.split_todo = todo_edgesplit_same_handle; + settings_split_same.initialize_invariants(m_mesh); + m_scheduler.add_operation_type( + "edge_split", + settings_split_same); + while (true) { + m_scheduler.run_operation_on_all(PrimitiveType::Edge, "edge_split"); + if (m_scheduler.number_of_successful_operations() == 0) { + break; + } + } + } + + // compute the todo list for the split edge with the different ends + // { + // const std::vector& edges = m_mesh.get_all(wmtk::PrimitiveType::Edge); + // for (const Tuple& edge : edges) { + // long vt0, vt1; + // vt0 = acc_vertex_tag.scalar_attribute(edge); + // vt1 = acc_vertex_tag.scalar_attribute(m_mesh.switch_vertex(edge)); + // if ((vt0 == m_input_tag_value && vt1 == m_embedding_tag_value) || + // (vt1 == m_input_tag_value && vt0 == m_embedding_tag_value)) { + // acc_todo_edgesplit_same_tag.scalar_attribute(edge) = 1; + // } + // } + // } + // using scheduler to do edge splitting + // ... +} + +void RegularSpace::process_in_3d() {} } // namespace wmtk::components::internal diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.hpp b/components/wmtk_components/regular_space/internal/RegularSpace.hpp index ecb16464b8..65a9c02fa7 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpace.hpp +++ b/components/wmtk_components/regular_space/internal/RegularSpace.hpp @@ -11,13 +11,32 @@ class RegularSpace bool m_lock_boundary = true; MeshAttributeHandle m_position_handle; + MeshAttributeHandle m_vertex_tag; + MeshAttributeHandle m_edge_tag; + long m_input_tag_value; + long m_embedding_tag_value; + long m_split_tag_value; + int m_dimension; Scheduler m_scheduler; public: - RegularSpace(TriMesh& mesh, const bool lock_boundary); - - void process(const long iterations); + RegularSpace( + TriMesh& mesh, + MeshAttributeHandle position_handle, + MeshAttributeHandle vertex_tag, + MeshAttributeHandle edge_tag, + long input_tag_value, + long embedding_tag_value, + long split_tag_value, + int m_dimension = 2, + const bool lock_boundary = true); + + void process_in_1d(); + void process_in_2d(); + void process_in_3d(); + + void process(); }; } // namespace wmtk::components::internal diff --git a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp index 4439ae258a..271238f380 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp @@ -50,6 +50,9 @@ bool FaceSplitWithTag::before() const } bool FaceSplitWithTag::execute() { + p0 = m_pos_accessor.vector_attribute(input_tuple()); + p1 = m_pos_accessor.vector_attribute(mesh().switch_vertex(input_tuple())); + p2 = m_pos_accessor.vector_attribute(mesh().switch_vertex(mesh().switch_edge(input_tuple()))); { FaceSplit split_op(mesh(), input_tuple(), m_settings.face_split_settings); if (!split_op()) { From 30eeed419e32d20bac2d48d50136af22a969f536 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Mon, 16 Oct 2023 16:41:00 -0400 Subject: [PATCH 11/19] added RegularSpace API --- .../regular_space/internal/RegularSpace.cpp | 27 +++-- .../regular_space/internal/RegularSpace.hpp | 26 ++-- .../internal/RegularSpaceOptions.hpp | 6 + .../regular_space/regular_space.cpp | 69 ++++++++++- src/wmtk/invariants/TodoInvariant.cpp | 2 +- .../operations/tri_mesh/EdgeSplitWithTag.cpp | 29 ++--- .../operations/tri_mesh/EdgeSplitWithTag.hpp | 1 + .../test_component_regular_space.cpp | 113 +++++++++++++++++- tests/test_2d_operation_construction.cpp | 2 +- tests/test_2d_operations.cpp | 60 +++++++++- 10 files changed, 291 insertions(+), 44 deletions(-) diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.cpp b/components/wmtk_components/regular_space/internal/RegularSpace.cpp index 65a4ceef56..ab4adebaa7 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpace.cpp +++ b/components/wmtk_components/regular_space/internal/RegularSpace.cpp @@ -12,14 +12,14 @@ namespace wmtk::components::internal { RegularSpace::RegularSpace( TriMesh& mesh, - MeshAttributeHandle position_handle, - MeshAttributeHandle vertex_tag, - MeshAttributeHandle edge_tag, - long input_tag_value, - long embedding_tag_value, - long split_tag_value, - int m_dimension = 2, - const bool lock_boundary = true) + MeshAttributeHandle& position_handle, + MeshAttributeHandle& vertex_tag, + MeshAttributeHandle& edge_tag, + const long input_tag_value, + const long embedding_tag_value, + const long split_tag_value, + const int dimension, + const bool lock_boundary) : m_mesh(mesh) , m_position_handle(position_handle) , m_vertex_tag(vertex_tag) @@ -27,6 +27,7 @@ RegularSpace::RegularSpace( , m_input_tag_value(input_tag_value) , m_embedding_tag_value(embedding_tag_value) , m_split_tag_value(split_tag_value) + , m_dimension(dimension) , m_scheduler(mesh) , m_lock_boundary(lock_boundary) {} @@ -34,14 +35,14 @@ RegularSpace::RegularSpace( void RegularSpace::process() { switch (m_dimension) { + case 0: process_in_0d(); break; case 1: process_in_1d(); break; - case 2: process_in_2d(); break; - case 3: throw std::runtime_error("3 dimension has not been implemented!"); break; + case 2: throw std::runtime_error("2 dimension has not been implemented!"); break; default: throw std::runtime_error("settings went wrong!"); break; } } -void RegularSpace::process_in_1d() +void RegularSpace::process_in_0d() { using namespace operations; @@ -90,7 +91,7 @@ void RegularSpace::process_in_1d() } } -void RegularSpace::process_in_2d() +void RegularSpace::process_in_1d() { using namespace operations; @@ -206,6 +207,6 @@ void RegularSpace::process_in_2d() // ... } -void RegularSpace::process_in_3d() {} +void RegularSpace::process_in_2d() {} } // namespace wmtk::components::internal diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.hpp b/components/wmtk_components/regular_space/internal/RegularSpace.hpp index 65a9c02fa7..2506202c8a 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpace.hpp +++ b/components/wmtk_components/regular_space/internal/RegularSpace.hpp @@ -8,7 +8,7 @@ namespace wmtk::components::internal { class RegularSpace { TriMesh& m_mesh; - bool m_lock_boundary = true; + bool m_lock_boundary; MeshAttributeHandle m_position_handle; MeshAttributeHandle m_vertex_tag; @@ -20,22 +20,24 @@ class RegularSpace Scheduler m_scheduler; + void process_in_0d(); + void process_in_1d(); + // we don't need this function I thought, since we can't convert TriMesh to the Mesh. That's + // said TetMesh can't be passes into this class as a TriMesh object. + void process_in_2d(); + public: RegularSpace( TriMesh& mesh, - MeshAttributeHandle position_handle, - MeshAttributeHandle vertex_tag, - MeshAttributeHandle edge_tag, - long input_tag_value, - long embedding_tag_value, - long split_tag_value, - int m_dimension = 2, + MeshAttributeHandle& position_handle, + MeshAttributeHandle& vertex_tag, + MeshAttributeHandle& edge_tag, + const long input_tag_value, + const long embedding_tag_value, + const long split_tag_value, + const int dimension = 1, const bool lock_boundary = true); - void process_in_1d(); - void process_in_2d(); - void process_in_3d(); - void process(); }; diff --git a/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp b/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp index df456900ef..527ff4bf4f 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp +++ b/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp @@ -12,6 +12,9 @@ struct RegularSpaceOptions std::string type; // regular space std::string input; // mesh input dir std::string output; // mesh output dir + std::string pos_handle_name; + std::string vertex_tag_handle_name; + std::string edge_tag_handle_name; int demension; // 0-vertex 1-edge 2-face 3-tet long input_value; long embedding_value; @@ -24,6 +27,9 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( type, input, output, + pos_handle_name, + vertex_tag_handle_name, + edge_tag_handle_name, demension, input_value, embedding_value, diff --git a/components/wmtk_components/regular_space/regular_space.cpp b/components/wmtk_components/regular_space/regular_space.cpp index b2478251b1..2d334c93ea 100644 --- a/components/wmtk_components/regular_space/regular_space.cpp +++ b/components/wmtk_components/regular_space/regular_space.cpp @@ -10,6 +10,73 @@ namespace wmtk { namespace components { -void regular_space(const nlohmann::json& j, std::map& files) {} +void regular_space(const nlohmann::json& j, std::map& files) +{ + using namespace internal; + + RegularSpaceOptions options = j.get(); + + // input + TriMesh mesh; + { + const std::filesystem::path& file = files[options.input]; + MeshReader reader(file); + reader.read(mesh); + } + + int dim = options.demension; + + switch (dim) { + case 0: { + MeshAttributeHandle pos_handle = + mesh.get_attribute_handle(options.pos_handle_name, PrimitiveType::Vertex); + MeshAttributeHandle vertex_tag_handle = + mesh.get_attribute_handle(options.vertex_tag_handle_name, PrimitiveType::Vertex); + MeshAttributeHandle edge_tag_handle = + mesh.register_attribute(std::string("dummy"), PrimitiveType::Edge, 1); + RegularSpace rs( + mesh, + pos_handle, + vertex_tag_handle, + edge_tag_handle, + options.input_value, + options.embedding_value, + options.split_value); + rs.process(); + } break; + case 1: { + MeshAttributeHandle pos_handle = + mesh.get_attribute_handle(options.pos_handle_name, PrimitiveType::Vertex); + MeshAttributeHandle vertex_tag_handle = + mesh.get_attribute_handle(options.vertex_tag_handle_name, PrimitiveType::Vertex); + MeshAttributeHandle edge_tag_handle = + mesh.get_attribute_handle(options.edge_tag_handle_name, PrimitiveType::Edge); + RegularSpace rs( + mesh, + pos_handle, + vertex_tag_handle, + edge_tag_handle, + options.input_value, + options.embedding_value, + options.split_value); + rs.process(); + } break; + case 2: { + throw std::runtime_error("Dimension 2 (face) case has not been implemented!"); + } break; + default: throw std::runtime_error("Only dimension 0,1,2 are supported!"); break; + } + + // output + { + const std::filesystem::path cache_dir = "cache"; + const std::filesystem::path cached_mesh_file = cache_dir / (options.output + ".hdf5"); + + HDF5Writer writer(cached_mesh_file); + mesh.serialize(writer); + + files[options.output] = cached_mesh_file; + } +} } // namespace components } // namespace wmtk diff --git a/src/wmtk/invariants/TodoInvariant.cpp b/src/wmtk/invariants/TodoInvariant.cpp index 85cfe0e356..ba91f0e0a4 100644 --- a/src/wmtk/invariants/TodoInvariant.cpp +++ b/src/wmtk/invariants/TodoInvariant.cpp @@ -9,6 +9,6 @@ TodoInvariant::TodoInvariant(const Mesh& m, const MeshAttributeHandle& tod bool TodoInvariant::before(const Tuple& t) const { ConstAccessor split_todo_accessor = mesh().create_accessor(m_todo_handle); - return split_todo_accessor.const_vector_attribute(t)(0) == 1; + return split_todo_accessor.const_scalar_attribute(t) == 1; } } // namespace wmtk \ No newline at end of file diff --git a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp index 5f2d0c9ab0..76afa2c8d4 100644 --- a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp +++ b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp @@ -51,7 +51,6 @@ bool EdgeSplitWithTag::execute() long et = m_edge_tag_accessor.scalar_attribute(input_tuple()); long vt0 = m_vertex_tag_accessor.scalar_attribute(input_tuple()); long vt1 = m_vertex_tag_accessor.scalar_attribute(mesh().switch_vertex(input_tuple())); - { EdgeSplit split_op(mesh(), input_tuple(), m_settings.split_settings); if (!split_op()) { @@ -61,34 +60,36 @@ bool EdgeSplitWithTag::execute() } m_pos_accessor.vector_attribute(m_output_tuple) = 0.5 * (p0 + p1); m_split_todo_accessor.scalar_attribute(m_output_tuple) = 0; - m_split_todo_accessor.scalar_attribute(mesh().switch_edge(m_output_tuple)) = 0; - m_split_todo_accessor.scalar_attribute(mesh().switch_edge(mesh().switch_face(m_output_tuple))) = - 0; m_split_todo_accessor.scalar_attribute( mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple)))) = 0; - // two split edge should be the split edge value, and the split vertex should be the split // vertex value m_vertex_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.split_vertex_tag_value; m_edge_tag_accessor.scalar_attribute(mesh().switch_edge(m_output_tuple)) = m_settings.split_edge_tag_value; - m_edge_tag_accessor.scalar_attribute(mesh().switch_edge(mesh().switch_face(m_output_tuple))) = - m_settings.split_edge_tag_value; + if (!mesh().is_boundary_edge(m_output_tuple)) { + m_edge_tag_accessor.scalar_attribute(mesh().switch_edge( + mesh().switch_face(m_output_tuple))) = m_settings.split_edge_tag_value; + } // if the embedding tag value is needed, then assign two edges connect to the original edges // with the embedding tag value, otherwise assign them with their neighbour's vertex's tag value if (m_settings.need_embedding_tag_value) { m_edge_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.embedding_tag_value; - m_edge_tag_accessor.scalar_attribute( - mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple)))) = - m_settings.embedding_tag_value; + if (!mesh().is_boundary_edge(mesh().switch_edge(m_output_tuple))) { + m_edge_tag_accessor.scalar_attribute( + mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple)))) = + m_settings.embedding_tag_value; + } } else { m_edge_tag_accessor.scalar_attribute(m_output_tuple) = m_vertex_tag_accessor.scalar_attribute(mesh().switch_vertex(m_output_tuple)); - m_edge_tag_accessor.scalar_attribute( - mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple)))) = - m_vertex_tag_accessor.scalar_attribute(mesh().switch_vertex( - mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple))))); + if (!mesh().is_boundary_edge(mesh().switch_edge(m_output_tuple))) { + m_edge_tag_accessor.scalar_attribute( + mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple)))) = + m_vertex_tag_accessor.scalar_attribute(mesh().switch_vertex( + mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple))))); + } } return true; diff --git a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp index a672950f1d..88ccde959d 100644 --- a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp +++ b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp @@ -14,6 +14,7 @@ template <> struct OperationSettings { OperationSettings split_settings; + InvariantCollection invariants; // handle to vertex position MeshAttributeHandle position; MeshAttributeHandle vertex_tag; diff --git a/tests/components/test_component_regular_space.cpp b/tests/components/test_component_regular_space.cpp index 3a1e7188d0..136dba6e97 100644 --- a/tests/components/test_component_regular_space.cpp +++ b/tests/components/test_component_regular_space.cpp @@ -1,13 +1,62 @@ #include #include +#include +#include +#include +#include +#include #include +#include #include using json = nlohmann::json; +using namespace wmtk; const std::filesystem::path data_dir = WMTK_DATA_DIR; -TEST_CASE("component_regular_space", "[components][regular_space][.]") +TriMesh hex_plus_two() +{ + // 0---1---2 + // / \ / \ / \ . + // 3---4---5---6 + // \ / \ / . + // 7---8 + TriMesh m; + RowVectors3l tris; + tris.resize(8, 3); + tris.row(0) << 3, 4, 0; + tris.row(1) << 4, 1, 0; + tris.row(2) << 4, 5, 1; + tris.row(3) << 5, 2, 1; + tris.row(4) << 5, 6, 2; + tris.row(5) << 3, 7, 4; + tris.row(6) << 7, 8, 4; + tris.row(7) << 4, 8, 5; + m.initialize(tris); + return m; +} + +TriMesh hex_plus_two_with_position() +{ + TriMesh m = hex_plus_two(); + + Eigen::MatrixXd V; + V.resize(9, 3); + V.row(0) << 0.5, 1, 0; + V.row(1) << 1.5, 1, 0; + V.row(2) << 2.5, 1, 0; + V.row(3) << 0, 0, 0; + V.row(4) << 1, 0, 0; + V.row(5) << 2, 0, 0; + V.row(6) << 3, 0, 0; + V.row(7) << 0.5, -1, 0; + V.row(8) << 1.5, -1, 0; + + mesh_utils::set_matrix_attribute(V, "position", PrimitiveType::Vertex, m); + return m; +} + +TEST_CASE("file reading", "[components][regular_space][.]") { std::map files; std::map tags_value; @@ -19,4 +68,66 @@ TEST_CASE("component_regular_space", "[components][regular_space][.]") {"demension", 1}, /*0 for vertex, 1 for edge, 2 for face, 3 for tet*/ {"tags_value", tags_value}, {"split_tag_value"}}; +} + +TEST_CASE("1d case", "[components][regular_space][scheduler]") +{ + long input_value = 1; + long embedding_value = 0; + long split_value = 2; + + TriMesh m = hex_plus_two_with_position(); + MeshAttributeHandle pos_handle = + m.get_attribute_handle(std::string("position"), wmtk::PrimitiveType::Vertex); + MeshAttributeHandle vertex_tag_handle = m.register_attribute( + std::string("vertex_tag"), + wmtk::PrimitiveType::Vertex, + 1, + false, + embedding_value); + MeshAttributeHandle edge_tag_handle = m.register_attribute( + std::string("edge_tag"), + wmtk::PrimitiveType::Edge, + 1, + false, + embedding_value); + + // 0---1---2 + // / \ / \ / \ . + // 3---4---5---6 + // \ / \ / . + // 7---8 + // set 0 1 4 5 6 + const std::vector& vs = m.get_all(wmtk::PrimitiveType::Vertex); + Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); + acc_vertex_tag.scalar_attribute(vs[0]) = input_value; + acc_vertex_tag.scalar_attribute(vs[1]) = input_value; + acc_vertex_tag.scalar_attribute(vs[4]) = input_value; + acc_vertex_tag.scalar_attribute(vs[5]) = input_value; + acc_vertex_tag.scalar_attribute(vs[6]) = input_value; + + components::internal::RegularSpace rs( + m, + pos_handle, + vertex_tag_handle, + edge_tag_handle, + input_value, + embedding_value, + split_value, + 0); + rs.process(); + ParaviewWriter writer1(data_dir / "my_result", "position", m, true, true, true, false); + m.serialize(writer1); + + // Accessor acc_todo = m.create_accessor( + // m.get_attribute_handle(std::string("todo_edgesplit_same_tag"), + // PrimitiveType::Edge)); + // int todo_num = 0; + // for (const Tuple& t : m.get_all(PrimitiveType::Edge)) { + // spdlog::info("{}", acc_todo.scalar_attribute(t)); + // if (acc_todo.scalar_attribute(t) == 1) { + // todo_num++; + // } + // } + // spdlog::info("{}", todo_num); } \ No newline at end of file diff --git a/tests/test_2d_operation_construction.cpp b/tests/test_2d_operation_construction.cpp index 1fbae22455..93d6800940 100644 --- a/tests/test_2d_operation_construction.cpp +++ b/tests/test_2d_operation_construction.cpp @@ -226,4 +226,4 @@ TEST_CASE("get per face data") REQUIRE(ear2.eid > -1); } } -*/ +*/ \ No newline at end of file diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index a3331f01c2..6e2c858597 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1411,4 +1411,62 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") } REQUIRE(success_num == 1); } -} \ No newline at end of file +} + +// TEST_CASE("attribute_after_split", "[attribute]") +// { +// // can directly run this code in test_2d_operations.cpp + +// // 2 +// // / \ +// // / \ +// // / 0 \ +// // / \ +// // 0 --------- 1 + +// const std::filesystem::path data_dir = WMTK_DATA_DIR; +// using namespace wmtk; +// DEBUG_TriMesh m = single_triangle_with_position(); +// wmtk::MeshAttributeHandle attribute_handle = m.register_attribute( +// std::string("test_attribute"), +// PE, +// 1); // default value is 0 +// wmtk::MeshAttributeHandle pos_handle = +// m.get_attribute_handle(std::string("position"), PV); +// Accessor acc_attribute = m.create_accessor(attribute_handle); +// Accessor acc_pos = m.create_accessor(pos_handle); +// Eigen::Vector3d p0 = acc_pos.vector_attribute(m.edge_tuple_between_v1_v2(0, 1, 0)); +// Eigen::Vector3d p1 = +// acc_pos.vector_attribute(m.switch_vertex(m.edge_tuple_between_v1_v2(0, 1, 0))); + +// // set edge(0,1)'s tag as 1 +// acc_attribute.scalar_attribute(m.edge_tuple_between_v1_v2(0, 1, 0)) = 1; + +// wmtk::operations::OperationSettings op_settings; +// op_settings.split_boundary_edges = true; +// op_settings.initialize_invariants(m); +// operations::tri_mesh::EdgeSplit op(m, m.edge_tuple_between_v1_v2(0, 1, 0), op_settings); +// REQUIRE(op()); + +// // 2 +// // /|\ +// // / | \ +// // / | \ +// // / | \ +// // 0 ----3---- 1 + +// spdlog::info( +// "output edge: {},{}", +// m.id(op.return_tuple(), PV), +// m.id(m.switch_vertex(op.return_tuple()), PV)); +// acc_pos.vector_attribute(op.return_tuple()) = (p0 + p1) * 0.5; + +// // since all default value is 0, there should be no 1 value in this triangle +// for (const Tuple& t : m.get_all(PE)) { +// REQUIRE(acc_attribute.scalar_attribute(t) != 1); +// } + +// // then see the my_result.hdf edge file, edge(0,2) is tagged... +// ParaviewWriter writer1(data_dir / "my_result", "position", m, true, true, true, false); +// m.serialize(writer1); +// } \ No newline at end of file From 4561fceae71117816a89023eb5cad3ecf13d99f7 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Tue, 17 Oct 2023 12:52:35 -0400 Subject: [PATCH 12/19] add midsplit operations and some document --- .../regular_space/internal/RegularSpace.cpp | 10 +- .../regular_space/internal/RegularSpace.hpp | 35 ++++- .../internal/RegularSpaceOptions.hpp | 8 +- .../regular_space/regular_space.cpp | 14 +- src/wmtk/invariants/TodoInvariant.hpp | 5 +- src/wmtk/operations/tri_mesh/CMakeLists.txt | 2 + .../operations/tri_mesh/EdgeSplitWithTag.cpp | 27 ++-- .../operations/tri_mesh/EdgeSplitWithTag.hpp | 29 +++- src/wmtk/operations/tri_mesh/FaceSplit.hpp | 23 +-- .../tri_mesh/FaceSplitAtMidPoint.cpp | 62 ++++++++ .../tri_mesh/FaceSplitAtMidPoint.hpp | 53 +++++++ .../operations/tri_mesh/FaceSplitWithTag.cpp | 29 ++-- .../operations/tri_mesh/FaceSplitWithTag.hpp | 9 +- .../test_component_regular_space.cpp | 84 +++-------- tests/test_2d_operations.cpp | 139 ++++++------------ 15 files changed, 292 insertions(+), 237 deletions(-) create mode 100644 src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp create mode 100644 src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.cpp b/components/wmtk_components/regular_space/internal/RegularSpace.cpp index ab4adebaa7..b10ab9ae60 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpace.cpp +++ b/components/wmtk_components/regular_space/internal/RegularSpace.cpp @@ -73,8 +73,9 @@ void RegularSpace::process_in_0d() settings_split_same.vertex_tag = m_vertex_tag; settings_split_same.embedding_tag_value = m_embedding_tag_value; settings_split_same.need_embedding_tag_value = true; - settings_split_same.position = m_position_handle; - settings_split_same.split_settings.split_boundary_edges = true; + // settings_split_same.position = m_position_handle; + settings_split_same.split_with_tag_settings.split_settings.split_boundary_edges = true; + settings_split_same.split_with_tag_settings.position = m_position_handle; settings_split_same.split_edge_tag_value = m_embedding_tag_value; settings_split_same.split_vertex_tag_value = m_split_tag_value; settings_split_same.split_todo = todo_edgesplit_same_handle; @@ -173,8 +174,9 @@ void RegularSpace::process_in_1d() settings_split_same.vertex_tag = m_vertex_tag; settings_split_same.embedding_tag_value = m_embedding_tag_value; settings_split_same.need_embedding_tag_value = true; - settings_split_same.position = m_position_handle; - settings_split_same.split_settings.split_boundary_edges = true; + // settings_split_same.position = m_position_handle; + settings_split_same.split_with_tag_settings.split_settings.split_boundary_edges = true; + settings_split_same.split_with_tag_settings.position = m_position_handle; settings_split_same.split_edge_tag_value = m_embedding_tag_value; settings_split_same.split_vertex_tag_value = m_split_tag_value; settings_split_same.split_todo = todo_edgesplit_same_handle; diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.hpp b/components/wmtk_components/regular_space/internal/RegularSpace.hpp index 2506202c8a..9c219d3b7d 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpace.hpp +++ b/components/wmtk_components/regular_space/internal/RegularSpace.hpp @@ -5,22 +5,43 @@ namespace wmtk::components::internal { +/* + * This class is used to seperate mesh and make sure there are no direct connection + * between independent simplicity collection + */ class RegularSpace { TriMesh& m_mesh; bool m_lock_boundary; - MeshAttributeHandle m_position_handle; - MeshAttributeHandle m_vertex_tag; - MeshAttributeHandle m_edge_tag; - long m_input_tag_value; - long m_embedding_tag_value; - long m_split_tag_value; - int m_dimension; + MeshAttributeHandle m_position_handle; // record position + MeshAttributeHandle m_vertex_tag; // record vertex tag value + MeshAttributeHandle m_edge_tag; // record edge vertex tag value + long m_input_tag_value; // the value used to those simplicity you want to seperate + long m_embedding_tag_value; // the scalffold simplicities' tag value + long m_split_tag_value; // when you split a simplicity, you will set m_split_tag_value to the + // new simplicity + int m_dimension; // operate dimension, 0 for vertex, 1 for edge, 2 for face, 3 for tet Scheduler m_scheduler; + /* + * seperate edges end with two ends with the same attribute(m_input_tag_value) + * + * If you have serveral vertices in a mesh, you don't want + * those specific vertices with the same attribute directly connect with each + * other, you should use process_in_0d + */ void process_in_0d(); + /* + * seperate the face if there the three vertices and edges all tagged with the input_value + * seperate the edge end with two vertices tagged with input_value but the edge itself is not + * marked as the input_value + * + * If you have serveral segments in a mesh, you don't want + * those specific segments with the same attribute directly connect with each + * other, you should use process_in_1d + */ void process_in_1d(); // we don't need this function I thought, since we can't convert TriMesh to the Mesh. That's // said TetMesh can't be passes into this class as a TriMesh object. diff --git a/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp b/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp index 527ff4bf4f..570ee73aef 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp +++ b/components/wmtk_components/regular_space/internal/RegularSpaceOptions.hpp @@ -12,10 +12,10 @@ struct RegularSpaceOptions std::string type; // regular space std::string input; // mesh input dir std::string output; // mesh output dir - std::string pos_handle_name; + std::string pos_attribute_name; std::string vertex_tag_handle_name; std::string edge_tag_handle_name; - int demension; // 0-vertex 1-edge 2-face 3-tet + int dimension; // 0-vertex 1-edge 2-face 3-tet long input_value; long embedding_value; long split_value = -1; @@ -27,10 +27,10 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( type, input, output, - pos_handle_name, + pos_attribute_name, vertex_tag_handle_name, edge_tag_handle_name, - demension, + dimension, input_value, embedding_value, split_value, diff --git a/components/wmtk_components/regular_space/regular_space.cpp b/components/wmtk_components/regular_space/regular_space.cpp index 2d334c93ea..d873df1b44 100644 --- a/components/wmtk_components/regular_space/regular_space.cpp +++ b/components/wmtk_components/regular_space/regular_space.cpp @@ -24,14 +24,14 @@ void regular_space(const nlohmann::json& j, std::map pos_handle = + mesh.get_attribute_handle(options.pos_attribute_name, PrimitiveType::Vertex); + MeshAttributeHandle vertex_tag_handle = + mesh.get_attribute_handle(options.vertex_tag_handle_name, PrimitiveType::Vertex); switch (dim) { case 0: { - MeshAttributeHandle pos_handle = - mesh.get_attribute_handle(options.pos_handle_name, PrimitiveType::Vertex); - MeshAttributeHandle vertex_tag_handle = - mesh.get_attribute_handle(options.vertex_tag_handle_name, PrimitiveType::Vertex); MeshAttributeHandle edge_tag_handle = mesh.register_attribute(std::string("dummy"), PrimitiveType::Edge, 1); RegularSpace rs( @@ -45,10 +45,6 @@ void regular_space(const nlohmann::json& j, std::map pos_handle = - mesh.get_attribute_handle(options.pos_handle_name, PrimitiveType::Vertex); - MeshAttributeHandle vertex_tag_handle = - mesh.get_attribute_handle(options.vertex_tag_handle_name, PrimitiveType::Vertex); MeshAttributeHandle edge_tag_handle = mesh.get_attribute_handle(options.edge_tag_handle_name, PrimitiveType::Edge); RegularSpace rs( diff --git a/src/wmtk/invariants/TodoInvariant.hpp b/src/wmtk/invariants/TodoInvariant.hpp index c3b2326db1..75f4debf4b 100644 --- a/src/wmtk/invariants/TodoInvariant.hpp +++ b/src/wmtk/invariants/TodoInvariant.hpp @@ -6,8 +6,11 @@ namespace wmtk { class TodoInvariant : public MeshInvariant { + /** + * Invariant for todo-list in scheduler. Recording which simplicity still need to be operated. + * If the todo_tag tagged as 1 then return true, otherwise return false + */ public: - // NOTE: this takes in the threshold squared rather than the threshold itself TodoInvariant(const Mesh& m, const MeshAttributeHandle& todo_handle); bool before(const Tuple& t) const override; diff --git a/src/wmtk/operations/tri_mesh/CMakeLists.txt b/src/wmtk/operations/tri_mesh/CMakeLists.txt index 528b1826c3..4245f4a8d8 100644 --- a/src/wmtk/operations/tri_mesh/CMakeLists.txt +++ b/src/wmtk/operations/tri_mesh/CMakeLists.txt @@ -23,5 +23,7 @@ set(SRC_FILES VertexLaplacianSmooth.cpp VertexTangentialLaplacianSmooth.hpp VertexTangentialLaplacianSmooth.cpp + FaceSplitAtMidPoint.hpp + FaceSplitAtMidPoint.cpp ) target_sources(wildmeshing_toolkit PRIVATE ${SRC_FILES}) diff --git a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp index 76afa2c8d4..5977db8277 100644 --- a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp +++ b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp @@ -10,14 +10,16 @@ namespace wmtk::operations { void OperationSettings::initialize_invariants(const TriMesh& m) { - split_settings.initialize_invariants(m); - split_settings.invariants.add(std::make_shared(m, split_todo)); + split_with_tag_settings.split_settings.initialize_invariants(m); + split_with_tag_settings.split_settings.invariants.add( + std::make_shared(m, split_todo)); } bool OperationSettings::are_invariants_initialized() const { - return split_settings.are_invariants_initialized() && - find_invariants_in_collection_by_type(split_settings.invariants); + return split_with_tag_settings.split_settings.are_invariants_initialized() && + find_invariants_in_collection_by_type( + split_with_tag_settings.split_settings.invariants); } namespace tri_mesh { EdgeSplitWithTag::EdgeSplitWithTag( @@ -25,8 +27,8 @@ EdgeSplitWithTag::EdgeSplitWithTag( const Tuple& t, const OperationSettings& settings) : TriMeshOperation(m) - , TupleOperation(settings.split_settings.invariants, t) - , m_pos_accessor{m.create_accessor(settings.position)} + , TupleOperation(settings.split_with_tag_settings.split_settings.invariants, t) + //, m_pos_accessor{m.create_accessor(settings.position)} , m_vertex_tag_accessor{m.create_accessor(settings.vertex_tag)} , m_edge_tag_accessor{m.create_accessor(settings.edge_tag)} , m_split_todo_accessor{m.create_accessor(settings.split_todo)} @@ -40,25 +42,22 @@ Tuple EdgeSplitWithTag::return_tuple() const { return m_output_tuple; } -bool EdgeSplitWithTag::before() const -{ - return TupleOperation::before(); -} bool EdgeSplitWithTag::execute() { - Eigen::Vector3d p0 = m_pos_accessor.const_vector_attribute(input_tuple()); - Eigen::Vector3d p1 = m_pos_accessor.const_vector_attribute(mesh().switch_vertex(input_tuple())); + // Eigen::Vector3d p0 = m_pos_accessor.const_vector_attribute(input_tuple()); + // Eigen::Vector3d p1 = + // m_pos_accessor.const_vector_attribute(mesh().switch_vertex(input_tuple())); long et = m_edge_tag_accessor.scalar_attribute(input_tuple()); long vt0 = m_vertex_tag_accessor.scalar_attribute(input_tuple()); long vt1 = m_vertex_tag_accessor.scalar_attribute(mesh().switch_vertex(input_tuple())); { - EdgeSplit split_op(mesh(), input_tuple(), m_settings.split_settings); + EdgeSplitAtMidpoint split_op(mesh(), input_tuple(), m_settings.split_with_tag_settings); if (!split_op()) { return false; } m_output_tuple = split_op.return_tuple(); } - m_pos_accessor.vector_attribute(m_output_tuple) = 0.5 * (p0 + p1); + // m_pos_accessor.vector_attribute(m_output_tuple) = 0.5 * (p0 + p1); m_split_todo_accessor.scalar_attribute(m_output_tuple) = 0; m_split_todo_accessor.scalar_attribute( mesh().switch_edge(mesh().switch_face(mesh().switch_edge(m_output_tuple)))) = 0; diff --git a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp index 88ccde959d..603ebb0aed 100644 --- a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp +++ b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.hpp @@ -1,7 +1,7 @@ #pragma once #include #include -#include "EdgeSplit.hpp" +#include "EdgeSplitAtMidpoint.hpp" namespace wmtk::operations { namespace tri_mesh { @@ -13,17 +13,37 @@ enum { TAGS_DIFFERENT, TAGS_SAME }; template <> struct OperationSettings { - OperationSettings split_settings; + OperationSettings split_with_tag_settings; InvariantCollection invariants; // handle to vertex position - MeshAttributeHandle position; + // MeshAttributeHandle position; + // handle to vertex attribute MeshAttributeHandle vertex_tag; + // handle to edge attribute MeshAttributeHandle edge_tag; + + // a todo-list attribute, only do splitting when split_todo tag is 1 MeshAttributeHandle split_todo; + + // /\ /|\ + // / \ / 3 \ + // / f \ / |f \ + // X- - - > v0-0-X-2->v1 + // \ / \ | / + // \ / \ 1 / + // \/ \|/ + // after splitting, the new edges' attributes should be tagged as split_vertex_tag_value + // edges 1 and 3 will be tagged as the split_edge_tag_value + // the new vertex X will be tagged as the split_vertex_tag_value + // the edges 0 and 2's attribute after splitting depends on the need_embedding_tag_value + // if need_embedding_tag_value is true, 0 and 2's attribute will be the embedding_tag_value, + // otherwise, their attributes will same to their old neighbour's attribute + // edge0's = v0's and edge2's = v1's long split_vertex_tag_value; long split_edge_tag_value; long embedding_tag_value; bool need_embedding_tag_value; + // too short edges get ignored double min_squared_length = -1; @@ -46,12 +66,11 @@ class EdgeSplitWithTag : public TriMeshOperation, private TupleOperation static PrimitiveType primitive_type() { return PrimitiveType::Edge; } protected: - bool before() const override; bool execute() override; private: Tuple m_output_tuple; - Accessor m_pos_accessor; + // Accessor m_pos_accessor; Accessor m_vertex_tag_accessor; Accessor m_edge_tag_accessor; Accessor m_split_todo_accessor; diff --git a/src/wmtk/operations/tri_mesh/FaceSplit.hpp b/src/wmtk/operations/tri_mesh/FaceSplit.hpp index 2e9f19a518..959d0077be 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplit.hpp +++ b/src/wmtk/operations/tri_mesh/FaceSplit.hpp @@ -19,23 +19,24 @@ struct OperationSettings }; namespace tri_mesh { +/** + * The return tuple is the new vertex, pointing to the original vertex. + * This operation does not set vertex positions. + * / | \ + * / | \ + * / _*_ \ + * / _< f \_ \ + * |/_______\| + * \ / + * \ / + * \ / + **/ class FaceSplit : public TriMeshOperation, private TupleOperation { public: FaceSplit(Mesh& m, const Tuple& t, const OperationSettings& settings); std::string name() const override; - - // the return tuple is the new vertex, arrow to the original vertex - // this operation never set the position of the new vertex. - // / | \ - // / | \ - // / _*_ \ - // / _< f \_ \ - // |/_______\| - // \ / - // \ / - // \ / Tuple return_tuple() const; static PrimitiveType primitive_type() { return PrimitiveType::Face; } diff --git a/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp new file mode 100644 index 0000000000..7cec062994 --- /dev/null +++ b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp @@ -0,0 +1,62 @@ +#include "FaceSplitAtMidPoint.hpp" +#include + +#include +#include +#include "EdgeSplit.hpp" + +namespace wmtk::operations { + + +void OperationSettings::initialize_invariants(const TriMesh& m) +{ + split_settings.initialize_invariants(m); +} + +bool OperationSettings::are_invariants_initialized() const +{ + return split_settings.are_invariants_initialized(); +} +namespace tri_mesh { +FaceSplitAtMidPoint::FaceSplitAtMidPoint( + Mesh& m, + const Tuple& t, + const OperationSettings& settings) + : TriMeshOperation(m) + , TupleOperation(settings.split_settings.invariants, t) + , m_pos_accessor{m.create_accessor(settings.position)} + , m_settings{settings} +{} +std::string FaceSplitAtMidPoint::name() const +{ + return "tri_mesh_split_edge_at_midpoint"; +} +Tuple FaceSplitAtMidPoint::return_tuple() const +{ + return m_output_tuple; +} +bool FaceSplitAtMidPoint::before() const +{ + return TupleOperation::before(); +} +bool FaceSplitAtMidPoint::execute() +{ + { + FaceSplit split_op(mesh(), input_tuple(), m_settings.split_settings); + if (!split_op()) { + return false; + } + m_output_tuple = split_op.return_tuple(); + } + + const Eigen::Vector3d p0 = m_pos_accessor.vector_attribute(input_tuple()); + const Eigen::Vector3d p1 = m_pos_accessor.vector_attribute(mesh().switch_vertex(input_tuple())); + const Eigen::Vector3d p2 = + m_pos_accessor.vector_attribute(mesh().switch_edge(mesh().switch_vertex(input_tuple()))); + + m_pos_accessor.vector_attribute(m_output_tuple) = (p0 + p1 + p2) / 3.0; + + return true; +} +} // namespace tri_mesh +} // namespace wmtk::operations diff --git a/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp new file mode 100644 index 0000000000..d1d89d9c35 --- /dev/null +++ b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp @@ -0,0 +1,53 @@ +#pragma once +#include +#include +#include "FaceSplit.hpp" + +namespace wmtk::operations { +namespace tri_mesh { +class FaceSplitAtMidPoint; +} + +template <> +struct OperationSettings +{ + OperationSettings split_settings; + // handle to vertex position + MeshAttributeHandle position; + // too short edges get ignored + double min_squared_length = -1; + + void initialize_invariants(const TriMesh& m); + + // debug functionality to make sure operations are constructed properly + bool are_invariants_initialized() const; +}; + +namespace tri_mesh { +class FaceSplitAtMidPoint : public TriMeshOperation, private TupleOperation +{ +public: + FaceSplitAtMidPoint( + Mesh& m, + const Tuple& t, + const OperationSettings& settings); + + std::string name() const override; + + Tuple return_tuple() const; + + static PrimitiveType primitive_type() { return PrimitiveType::Edge; } + +protected: + bool before() const override; + bool execute() override; + +private: + Tuple m_output_tuple; + Accessor m_pos_accessor; + + const OperationSettings& m_settings; +}; + +} // namespace tri_mesh +} // namespace wmtk::operations diff --git a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp index 271238f380..06298147e0 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp @@ -9,14 +9,16 @@ namespace wmtk::operations { void OperationSettings::initialize_invariants(const TriMesh& m) { - face_split_settings.initialize_invariants(m); - face_split_settings.invariants.add(std::make_shared(m, split_todo)); + face_split_settings.split_settings.initialize_invariants(m); + face_split_settings.split_settings.invariants.add( + std::make_shared(m, split_todo)); } bool OperationSettings::are_invariants_initialized() const { return face_split_settings.are_invariants_initialized() && - find_invariants_in_collection_by_type(face_split_settings.invariants); + find_invariants_in_collection_by_type( + face_split_settings.split_settings.invariants); } namespace tri_mesh { @@ -25,17 +27,13 @@ FaceSplitWithTag::FaceSplitWithTag( const Tuple& t, const OperationSettings& settings) : TriMeshOperation(m) - , TupleOperation(settings.face_split_settings.invariants, t) + , TupleOperation(settings.face_split_settings.split_settings.invariants, t) , m_pos_accessor{m.create_accessor(settings.position)} , m_vertex_tag_accessor{m.create_accessor(settings.vertex_tag)} , m_edge_tag_accessor{m.create_accessor(settings.edge_tag)} , m_split_todo_accessor{m.create_accessor(settings.split_todo)} , m_settings{settings} -{ - p0 = m_pos_accessor.vector_attribute(input_tuple()); - p1 = m_pos_accessor.vector_attribute(mesh().switch_vertex(input_tuple())); - p2 = m_pos_accessor.vector_attribute(mesh().switch_vertex(mesh().switch_vertex(input_tuple()))); -} +{} std::string FaceSplitWithTag::name() const { return "tri_mesh_split_edge_at_midpoint"; @@ -44,17 +42,14 @@ Tuple FaceSplitWithTag::return_tuple() const { return m_output_tuple; } -bool FaceSplitWithTag::before() const -{ - return TupleOperation::before(); -} bool FaceSplitWithTag::execute() { - p0 = m_pos_accessor.vector_attribute(input_tuple()); - p1 = m_pos_accessor.vector_attribute(mesh().switch_vertex(input_tuple())); - p2 = m_pos_accessor.vector_attribute(mesh().switch_vertex(mesh().switch_edge(input_tuple()))); + const Eigen::Vector3d p0 = m_pos_accessor.vector_attribute(input_tuple()); + const Eigen::Vector3d p1 = m_pos_accessor.vector_attribute(mesh().switch_vertex(input_tuple())); + const Eigen::Vector3d p2 = + m_pos_accessor.vector_attribute(mesh().switch_vertex(mesh().switch_edge(input_tuple()))); { - FaceSplit split_op(mesh(), input_tuple(), m_settings.face_split_settings); + FaceSplitAtMidPoint split_op(mesh(), input_tuple(), m_settings.face_split_settings); if (!split_op()) { return false; } diff --git a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp index 2e79a02a24..163fef4f86 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp @@ -1,7 +1,7 @@ #pragma once #include #include -#include "FaceSplit.hpp" +#include "FaceSplitAtMidPoint.hpp" namespace wmtk::operations { namespace tri_mesh { @@ -11,7 +11,7 @@ class FaceSplitWithTag; template <> struct OperationSettings { - OperationSettings face_split_settings; + OperationSettings face_split_settings; MeshAttributeHandle position; MeshAttributeHandle vertex_tag; MeshAttributeHandle edge_tag; @@ -37,7 +37,6 @@ class FaceSplitWithTag : public TriMeshOperation, private TupleOperation static PrimitiveType primitive_type() { return PrimitiveType::Edge; } protected: - bool before() const override; bool execute() override; private: @@ -49,10 +48,6 @@ class FaceSplitWithTag : public TriMeshOperation, private TupleOperation Accessor m_split_todo_accessor; const OperationSettings& m_settings; - - Eigen::Vector3d p0; - Eigen::Vector3d p1; - Eigen::Vector3d p2; }; } // namespace tri_mesh diff --git a/tests/components/test_component_regular_space.cpp b/tests/components/test_component_regular_space.cpp index 136dba6e97..20df4b1d58 100644 --- a/tests/components/test_component_regular_space.cpp +++ b/tests/components/test_component_regular_space.cpp @@ -8,55 +8,14 @@ #include #include #include +#include "wmtk/../../tests/tools/TriMesh_examples.hpp" using json = nlohmann::json; using namespace wmtk; const std::filesystem::path data_dir = WMTK_DATA_DIR; -TriMesh hex_plus_two() -{ - // 0---1---2 - // / \ / \ / \ . - // 3---4---5---6 - // \ / \ / . - // 7---8 - TriMesh m; - RowVectors3l tris; - tris.resize(8, 3); - tris.row(0) << 3, 4, 0; - tris.row(1) << 4, 1, 0; - tris.row(2) << 4, 5, 1; - tris.row(3) << 5, 2, 1; - tris.row(4) << 5, 6, 2; - tris.row(5) << 3, 7, 4; - tris.row(6) << 7, 8, 4; - tris.row(7) << 4, 8, 5; - m.initialize(tris); - return m; -} - -TriMesh hex_plus_two_with_position() -{ - TriMesh m = hex_plus_two(); - - Eigen::MatrixXd V; - V.resize(9, 3); - V.row(0) << 0.5, 1, 0; - V.row(1) << 1.5, 1, 0; - V.row(2) << 2.5, 1, 0; - V.row(3) << 0, 0, 0; - V.row(4) << 1, 0, 0; - V.row(5) << 2, 0, 0; - V.row(6) << 3, 0, 0; - V.row(7) << 0.5, -1, 0; - V.row(8) << 1.5, -1, 0; - - mesh_utils::set_matrix_attribute(V, "position", PrimitiveType::Vertex, m); - return m; -} - -TEST_CASE("file reading", "[components][regular_space][.]") +TEST_CASE("regular_space_file_reading", "[components][regular_space][.]") { std::map files; std::map tags_value; @@ -68,25 +27,29 @@ TEST_CASE("file reading", "[components][regular_space][.]") {"demension", 1}, /*0 for vertex, 1 for edge, 2 for face, 3 for tet*/ {"tags_value", tags_value}, {"split_tag_value"}}; + + // TODO + // upload embedding result .hdf5 file and use regular_space API + REQUIRE(false); } TEST_CASE("1d case", "[components][regular_space][scheduler]") { - long input_value = 1; - long embedding_value = 0; - long split_value = 2; + const long input_value = 1; + const long embedding_value = 0; + const long split_value = 2; - TriMesh m = hex_plus_two_with_position(); + TriMesh m = wmtk::tests::hex_plus_two_with_position(); MeshAttributeHandle pos_handle = - m.get_attribute_handle(std::string("position"), wmtk::PrimitiveType::Vertex); + m.get_attribute_handle("position", wmtk::PrimitiveType::Vertex); MeshAttributeHandle vertex_tag_handle = m.register_attribute( - std::string("vertex_tag"), + "vertex_tag", wmtk::PrimitiveType::Vertex, 1, false, embedding_value); MeshAttributeHandle edge_tag_handle = m.register_attribute( - std::string("edge_tag"), + "edge_tag", wmtk::PrimitiveType::Edge, 1, false, @@ -119,15 +82,14 @@ TEST_CASE("1d case", "[components][regular_space][scheduler]") ParaviewWriter writer1(data_dir / "my_result", "position", m, true, true, true, false); m.serialize(writer1); - // Accessor acc_todo = m.create_accessor( - // m.get_attribute_handle(std::string("todo_edgesplit_same_tag"), - // PrimitiveType::Edge)); - // int todo_num = 0; - // for (const Tuple& t : m.get_all(PrimitiveType::Edge)) { - // spdlog::info("{}", acc_todo.scalar_attribute(t)); - // if (acc_todo.scalar_attribute(t) == 1) { - // todo_num++; - // } - // } - // spdlog::info("{}", todo_num); + Accessor acc_todo = m.create_accessor( + m.get_attribute_handle(std::string("todo_edgesplit_same_tag"), PrimitiveType::Edge)); + int todo_num = 0; + for (const Tuple& t : m.get_all(PrimitiveType::Edge)) { + spdlog::info("{}", acc_todo.scalar_attribute(t)); + if (acc_todo.scalar_attribute(t) == 1) { + todo_num++; + } + } + CHECK(todo_num == 0); } \ No newline at end of file diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 6e2c858597..2627aee88f 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1200,15 +1200,15 @@ TEST_CASE("split_face", "[operations][split][2D]") spdlog::info("{}", m.id(ret, PV)); spdlog::info("{}", m.id(m.switch_vertex(ret), PV)); spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(ret)), PV)); - REQUIRE(is_success); - REQUIRE(m.get_all(PV).size() == 4); - REQUIRE(!m.is_boundary_vertex(ret)); - REQUIRE(!m.is_boundary_edge(ret)); - REQUIRE(!m.is_boundary_edge(m.switch_edge(ret))); - REQUIRE(m.id(ret, PV) == 4); - REQUIRE(m.id(m.switch_vertex(ret), PV) == 1); - REQUIRE(m.id(m.switch_vertex(m.switch_edge(ret)), PV) == 2); - REQUIRE(SimplicialComplex::vertex_one_ring(m, ret).size() == 3); + CHECK(is_success); + CHECK(m.get_all(PV).size() == 4); + CHECK(!m.is_boundary_vertex(ret)); + CHECK(!m.is_boundary_edge(ret)); + CHECK(!m.is_boundary_edge(m.switch_edge(ret))); + CHECK(m.id(ret, PV) == 4); + CHECK(m.id(m.switch_vertex(ret), PV) == 1); + CHECK(m.id(m.switch_vertex(m.switch_edge(ret)), PV) == 2); + CHECK(SimplicialComplex::vertex_one_ring(m, ret).size() == 3); } SECTION("split in quad") { @@ -1221,9 +1221,9 @@ TEST_CASE("split_face", "[operations][split][2D]") // DEBUG_TriMesh m = interior_edge(); Tuple f = m.edge_tuple_between_v1_v2(1, 0, 1); - spdlog::info("{}", m.id(f, PV)); - spdlog::info("{}", m.id(m.switch_vertex(f), PV)); - spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f)), PV)); + // spdlog::info("{}", m.id(f, PV)); + // spdlog::info("{}", m.id(m.switch_vertex(f), PV)); + // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f)), PV)); Tuple split_ret; { OperationSettings op_settings; @@ -1232,17 +1232,18 @@ TEST_CASE("split_face", "[operations][split][2D]") split_op(); split_ret = split_op.return_tuple(); } - spdlog::info("{}", m.id(split_ret, PV)); - spdlog::info("{}", m.id(m.switch_vertex(split_ret), PV)); - spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(split_ret)), PV)); + // spdlog::info("{}", m.id(split_ret, PV)); + // spdlog::info("{}", m.id(m.switch_vertex(split_ret), PV)); + // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(split_ret)), PV)); const Tuple coll_input_tuple = m.switch_face(m.switch_edge(split_ret)); OperationSettings collapse_settings; collapse_settings.initialize_invariants(m); tri_mesh::EdgeCollapse coll_op(m, coll_input_tuple, collapse_settings); - coll_op(); - const Tuple& coll_ret = coll_op.return_tuple(); - auto ret = m.switch_vertex(m.switch_edge(coll_ret)); - spdlog::info("{} {}", m.id(ret, PV), m.id(m.switch_vertex(ret), PV)); + CHECK(coll_op()); + + // const Tuple& coll_ret = coll_op.return_tuple(); + // auto ret = m.switch_vertex(m.switch_edge(coll_ret)); + // spdlog::info("{} {}", m.id(ret, PV), m.id(m.switch_vertex(ret), PV)); // DEBUG_TriMesh m = quad(); // Tuple f = m.edge_tuple_between_v1_v2(1, 0, 1); @@ -1294,15 +1295,15 @@ TEST_CASE("split_face", "[operations][split][2D]") spdlog::info("{}", m.id(f0, PV)); spdlog::info("{}", m.id(m.switch_vertex(f0), PV)); spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f0)), PV)); - REQUIRE(op0()); + CHECK(op0()); spdlog::info("{}", m.id(op0.return_tuple(), PV)); spdlog::info("{}", m.id(m.switch_vertex(op0.return_tuple()), PV)); spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(op0.return_tuple())), PV)); auto handle = m.get_attribute_handle(std::string("position"), PV); auto acc = m.create_accessor(handle); - REQUIRE(op1()); - REQUIRE(!op2()); + CHECK(op1()); + CHECK(!op2()); spdlog::info("{}", m.get_all(PV).size()); for (auto v : m.get_all(PV)) { spdlog::info("{}", m.id(v, PV)); @@ -1344,15 +1345,16 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") settings.vertex_tag = vertex_handle; settings.embedding_tag_value = -1; settings.need_embedding_tag_value = true; - settings.position = m.get_attribute_handle(std::string("position"), PV); - settings.split_settings.split_boundary_edges = true; + settings.split_with_tag_settings.position = + m.get_attribute_handle(std::string("position"), PV); + settings.split_with_tag_settings.split_settings.split_boundary_edges = true; settings.split_edge_tag_value = -2; settings.split_vertex_tag_value = -3; settings.split_todo = todo_handle; settings.initialize_invariants(m); for (Tuple t : m.get_all(PV)) { wmtk::operations::tri_mesh::EdgeSplitWithTag op(m, t, settings); - REQUIRE(!op()); + CHECK(!op()); } } @@ -1371,8 +1373,9 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") settings.vertex_tag = vertex_handle; settings.embedding_tag_value = -1; settings.need_embedding_tag_value = true; - settings.position = m.get_attribute_handle(std::string("position"), PV); - settings.split_settings.split_boundary_edges = true; + settings.split_with_tag_settings.position = + m.get_attribute_handle(std::string("position"), PV); + settings.split_with_tag_settings.split_settings.split_boundary_edges = true; settings.split_edge_tag_value = -2; settings.split_vertex_tag_value = -3; settings.split_todo = todo_handle; @@ -1386,22 +1389,22 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") acc.scalar_attribute(e0) = 1; acc.scalar_attribute(e1) = 1; wmtk::operations::tri_mesh::EdgeSplitWithTag op0(m, e0, settings); - REQUIRE(op0()); + CHECK(op0()); // todo marks should be removed - REQUIRE(acc.scalar_attribute(op0.return_tuple()) == 0); - REQUIRE(acc.scalar_attribute(m.switch_edge(op0.return_tuple())) == 0); - REQUIRE( + CHECK(acc.scalar_attribute(op0.return_tuple()) == 0); + CHECK(acc.scalar_attribute(m.switch_edge(op0.return_tuple())) == 0); + CHECK( acc.scalar_attribute(m.switch_edge(m.switch_face(m.switch_edge(op0.return_tuple())))) == 0); - REQUIRE(acc.scalar_attribute(m.switch_edge(m.switch_face(op0.return_tuple()))) == 0); + CHECK(acc.scalar_attribute(m.switch_edge(m.switch_face(op0.return_tuple()))) == 0); // new tag value should be marked - REQUIRE(acc_e.scalar_attribute(op0.return_tuple()) == -1); - REQUIRE(acc_e.scalar_attribute(m.switch_edge(op0.return_tuple())) == -2); - REQUIRE( + CHECK(acc_e.scalar_attribute(op0.return_tuple()) == -1); + CHECK(acc_e.scalar_attribute(m.switch_edge(op0.return_tuple())) == -2); + CHECK( acc_e.scalar_attribute( m.switch_edge(m.switch_face(m.switch_edge(op0.return_tuple())))) == -1); - REQUIRE(acc_e.scalar_attribute(m.switch_edge(m.switch_face(op0.return_tuple()))) == -2); - REQUIRE(acc_v.scalar_attribute(op0.return_tuple()) == -3); + CHECK(acc_e.scalar_attribute(m.switch_edge(m.switch_face(op0.return_tuple()))) == -2); + CHECK(acc_v.scalar_attribute(op0.return_tuple()) == -3); int success_num = 0; for (Tuple t : m.get_all(PE)) { wmtk::operations::tri_mesh::EdgeSplitWithTag op(m, t, settings); @@ -1409,64 +1412,6 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") success_num++; } } - REQUIRE(success_num == 1); + CHECK(success_num == 1); } -} - -// TEST_CASE("attribute_after_split", "[attribute]") -// { -// // can directly run this code in test_2d_operations.cpp - -// // 2 -// // / \ -// // / \ -// // / 0 \ -// // / \ -// // 0 --------- 1 - -// const std::filesystem::path data_dir = WMTK_DATA_DIR; -// using namespace wmtk; -// DEBUG_TriMesh m = single_triangle_with_position(); -// wmtk::MeshAttributeHandle attribute_handle = m.register_attribute( -// std::string("test_attribute"), -// PE, -// 1); // default value is 0 -// wmtk::MeshAttributeHandle pos_handle = -// m.get_attribute_handle(std::string("position"), PV); -// Accessor acc_attribute = m.create_accessor(attribute_handle); -// Accessor acc_pos = m.create_accessor(pos_handle); -// Eigen::Vector3d p0 = acc_pos.vector_attribute(m.edge_tuple_between_v1_v2(0, 1, 0)); -// Eigen::Vector3d p1 = -// acc_pos.vector_attribute(m.switch_vertex(m.edge_tuple_between_v1_v2(0, 1, 0))); - -// // set edge(0,1)'s tag as 1 -// acc_attribute.scalar_attribute(m.edge_tuple_between_v1_v2(0, 1, 0)) = 1; - -// wmtk::operations::OperationSettings op_settings; -// op_settings.split_boundary_edges = true; -// op_settings.initialize_invariants(m); -// operations::tri_mesh::EdgeSplit op(m, m.edge_tuple_between_v1_v2(0, 1, 0), op_settings); -// REQUIRE(op()); - -// // 2 -// // /|\ -// // / | \ -// // / | \ -// // / | \ -// // 0 ----3---- 1 - -// spdlog::info( -// "output edge: {},{}", -// m.id(op.return_tuple(), PV), -// m.id(m.switch_vertex(op.return_tuple()), PV)); -// acc_pos.vector_attribute(op.return_tuple()) = (p0 + p1) * 0.5; - -// // since all default value is 0, there should be no 1 value in this triangle -// for (const Tuple& t : m.get_all(PE)) { -// REQUIRE(acc_attribute.scalar_attribute(t) != 1); -// } - -// // then see the my_result.hdf edge file, edge(0,2) is tagged... -// ParaviewWriter writer1(data_dir / "my_result", "position", m, true, true, true, false); -// m.serialize(writer1); -// } \ No newline at end of file +} \ No newline at end of file From a1ede377fa546c41510607f0944807c044021e7c Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Tue, 17 Oct 2023 16:07:54 -0400 Subject: [PATCH 13/19] test facesplit --- src/wmtk/operations/tri_mesh/FaceSplit.cpp | 39 +++++---- tests/test_2d_operations.cpp | 93 +++++----------------- 2 files changed, 38 insertions(+), 94 deletions(-) diff --git a/src/wmtk/operations/tri_mesh/FaceSplit.cpp b/src/wmtk/operations/tri_mesh/FaceSplit.cpp index f7edd2a256..b8aa9c597e 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplit.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplit.cpp @@ -93,21 +93,21 @@ bool FaceSplit::execute() } // after split // - // /|\ - // / | \ - // / X \ - // / /|\ \ - // /__/_v_\__\ + // /|\ + // / | \ + // / X \ + // / /|\ \ + // /__/_v_\__\ // \ | / // \ | / // \ | / // \|/ // collapse the split ret - // /|\ - // / | \ - // / /|\ \ - // / / | \ \ + // /|\ + // / | \ + // / /|\ \ + // / / | \ \ // |/__X__\> // \ | / // \ | / @@ -123,19 +123,18 @@ bool FaceSplit::execute() } const Tuple& coll_ret = coll_op.return_tuple(); // collapse output - // /| \ - // / | \ - // / * f \ - // / / \ \ - // / / > \ + // /| \ + // / | \ + // / * \ + // / / \ \ + // / / f > \ // |/_ _ _ _ \| - // \ / - // \ / - // \ / - // \ / - + // \ / + // \ / + // \ / + // \ / // return new vertex's tuple - m_output_tuple = mesh().switch_vertex(coll_ret); + m_output_tuple = mesh().switch_edge(mesh().switch_vertex(coll_ret)); return true; } diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index a009662907..09eb580614 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1206,17 +1206,17 @@ TEST_CASE("split_face", "[operations][split][2D]") // this case covered the on boundary case DEBUG_TriMesh m = single_triangle(); Tuple f = m.edge_tuple_between_v1_v2(1, 2, 0); - spdlog::info("{}", m.id(f, PV)); - spdlog::info("{}", m.id(m.switch_vertex(f), PV)); - spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f)), PV)); + // spdlog::info("{}", m.id(f, PV)); + // spdlog::info("{}", m.id(m.switch_vertex(f), PV)); + // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f)), PV)); OperationSettings settings; settings.initialize_invariants(m); - wmtk::operations::tri_mesh::FaceSplit face_split_op(m, f, settings); - bool is_success = face_split_op(); - Tuple ret = face_split_op.return_tuple(); - spdlog::info("{}", m.id(ret, PV)); - spdlog::info("{}", m.id(m.switch_vertex(ret), PV)); - spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(ret)), PV)); + wmtk::operations::tri_mesh::FaceSplit op(m, f, settings); + bool is_success = op(); + Tuple ret = op.return_tuple(); + // spdlog::info("{}", m.id(ret, PV)); + // spdlog::info("{}", m.id(m.switch_vertex(ret), PV)); + // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(ret)), PV)); CHECK(is_success); CHECK(m.get_all(PV).size() == 4); CHECK(!m.is_boundary_vertex(ret)); @@ -1236,48 +1236,17 @@ TEST_CASE("split_face", "[operations][split][2D]") // | / \ . // 1 ----0---- 2 // - DEBUG_TriMesh m = interior_edge(); + DEBUG_TriMesh m = quad(); Tuple f = m.edge_tuple_between_v1_v2(1, 0, 1); - // spdlog::info("{}", m.id(f, PV)); - // spdlog::info("{}", m.id(m.switch_vertex(f), PV)); - // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f)), PV)); - Tuple split_ret; - { - OperationSettings op_settings; - op_settings.initialize_invariants(m); - tri_mesh::EdgeSplit split_op(m, f, op_settings); - split_op(); - split_ret = split_op.return_tuple(); - } - // spdlog::info("{}", m.id(split_ret, PV)); - // spdlog::info("{}", m.id(m.switch_vertex(split_ret), PV)); - // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(split_ret)), PV)); - const Tuple coll_input_tuple = m.switch_face(m.switch_edge(split_ret)); - OperationSettings collapse_settings; - collapse_settings.initialize_invariants(m); - tri_mesh::EdgeCollapse coll_op(m, coll_input_tuple, collapse_settings); - CHECK(coll_op()); - - // const Tuple& coll_ret = coll_op.return_tuple(); - // auto ret = m.switch_vertex(m.switch_edge(coll_ret)); - // spdlog::info("{} {}", m.id(ret, PV), m.id(m.switch_vertex(ret), PV)); - - // DEBUG_TriMesh m = quad(); - // Tuple f = m.edge_tuple_between_v1_v2(1, 0, 1); - // OperationSettings settings; - // settings.initialize_invariants(m); - // wmtk::operations::tri_mesh::FaceSplit op(m, f, settings); - // spdlog::info("{}", m.id(f, PV)); - // spdlog::info("{}", m.id(m.switch_vertex(f), PV)); - // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f)), PV)); - // REQUIRE(op()); - // spdlog::info("{}", m.id(op.return_tuple(), PV)); - // spdlog::info("{}", m.id(m.switch_vertex(op.return_tuple()), PV)); - // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(op.return_tuple())), PV)); - // spdlog::info("{}", SimplicialComplex::vertex_one_ring(m, op.return_tuple()).size()); - // for (auto t : m.get_all(PV)) { - // spdlog::info("{}: {}", m.id(t, PV), SimplicialComplex::vertex_one_ring(m, t).size()); - // } + OperationSettings settings; + settings.initialize_invariants(m); + wmtk::operations::tri_mesh::FaceSplit op(m, f, settings); + bool is_success = op(); + CHECK(is_success); + CHECK(m.get_all(PV).size() == 5); + CHECK(m.id(op.return_tuple(), PV) == 5); + CHECK(m.id(m.switch_vertex(op.return_tuple()), PV) == 1); + CHECK(m.id(m.switch_vertex(m.switch_edge(op.return_tuple())), PV) == 0); } SECTION("split in diamond") { @@ -1288,18 +1257,6 @@ TEST_CASE("split_face", "[operations][split][2D]") // 7---8---9 DEBUG_TriMesh m = edge_region_with_position(); - // auto e = m.edge_tuple_between_v1_v2(9, 6, 9); - // OperationSettings collapse_settings; - // collapse_settings.initialize_invariants(m); - // wmtk::operations::tri_mesh::EdgeCollapse co(m, e, collapse_settings); - // spdlog::info("{}", m.id(e, PV)); - // spdlog::info("{}", m.id(m.switch_vertex(e), PV)); - // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(e)), PV)); - // REQUIRE(co()); - // spdlog::info("{}", m.id(co.return_tuple(), PV)); - // spdlog::info("{}", m.id(m.switch_vertex(co.return_tuple()), PV)); - // spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(co.return_tuple())), PV)); - Tuple f0 = m.edge_tuple_between_v1_v2(3, 4, 0); // on boundary Tuple f1 = m.edge_tuple_between_v1_v2(8, 9, 8); // out boundary Tuple f2 = m.edge_tuple_between_v1_v2(4, 8, 7); // overlap of f0 and f1 @@ -1308,23 +1265,11 @@ TEST_CASE("split_face", "[operations][split][2D]") wmtk::operations::tri_mesh::FaceSplit op0(m, f0, settings); wmtk::operations::tri_mesh::FaceSplit op1(m, f1, settings); wmtk::operations::tri_mesh::FaceSplit op2(m, f2, settings); - - spdlog::info("{}", m.id(f0, PV)); - spdlog::info("{}", m.id(m.switch_vertex(f0), PV)); - spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(f0)), PV)); CHECK(op0()); - spdlog::info("{}", m.id(op0.return_tuple(), PV)); - spdlog::info("{}", m.id(m.switch_vertex(op0.return_tuple()), PV)); - spdlog::info("{}", m.id(m.switch_vertex(m.switch_edge(op0.return_tuple())), PV)); - auto handle = m.get_attribute_handle(std::string("position"), PV); auto acc = m.create_accessor(handle); CHECK(op1()); CHECK(!op2()); - spdlog::info("{}", m.get_all(PV).size()); - for (auto v : m.get_all(PV)) { - spdlog::info("{}", m.id(v, PV)); - } } } From a49a86c60224cba405c8176454401a4c30677e99 Mon Sep 17 00:00:00 2001 From: Zhouyuan Chen <75082718+Zhouyuan-Chen@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:33:54 -0400 Subject: [PATCH 14/19] Update wmtk_data.cmake --- cmake/recipes/wmtk_data.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/recipes/wmtk_data.cmake b/cmake/recipes/wmtk_data.cmake index 04f82803b9..61f3816090 100644 --- a/cmake/recipes/wmtk_data.cmake +++ b/cmake/recipes/wmtk_data.cmake @@ -16,7 +16,7 @@ ExternalProject_Add( SOURCE_DIR ${WMTK_DATA_ROOT} GIT_REPOSITORY https://github.com/wildmeshing/data.git - GIT_TAG 1a8d9824a39b2ee77cafea9fd2cf79dc6bb611bd + GIT_TAG 5750f41b8d25345cd8b88ee59a1ee2619e6ce4f1 CONFIGURE_COMMAND "" BUILD_COMMAND "" From 5017f4a71c16e66af0ac1ada7d4ae51afdaeae1b Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Wed, 18 Oct 2023 18:45:15 -0400 Subject: [PATCH 15/19] fixed bugs and add more tests for regular space --- .../regular_space/internal/RegularSpace.cpp | 18 +- src/wmtk/invariants/TodoInvariant.cpp | 2 +- .../operations/tri_mesh/EdgeSplitWithTag.cpp | 2 +- .../tri_mesh/FaceSplitAtMidPoint.cpp | 12 +- .../tri_mesh/FaceSplitAtMidPoint.hpp | 2 +- .../operations/tri_mesh/FaceSplitWithTag.cpp | 27 ++- .../operations/tri_mesh/FaceSplitWithTag.hpp | 4 +- .../test_component_regular_space.cpp | 228 ++++++++++++++---- tests/test_2d_operations.cpp | 175 +++++++++++++- 9 files changed, 380 insertions(+), 90 deletions(-) diff --git a/components/wmtk_components/regular_space/internal/RegularSpace.cpp b/components/wmtk_components/regular_space/internal/RegularSpace.cpp index b10ab9ae60..5acbe6c343 100644 --- a/components/wmtk_components/regular_space/internal/RegularSpace.cpp +++ b/components/wmtk_components/regular_space/internal/RegularSpace.cpp @@ -37,7 +37,7 @@ void RegularSpace::process() switch (m_dimension) { case 0: process_in_0d(); break; case 1: process_in_1d(); break; - case 2: throw std::runtime_error("2 dimension has not been implemented!"); break; + case 2: process_in_2d(); break; default: throw std::runtime_error("settings went wrong!"); break; } } @@ -98,7 +98,7 @@ void RegularSpace::process_in_1d() wmtk::MeshAttributeHandle todo_facesplit_handle = m_mesh.register_attribute( std::string("todo_facesplit_tag"), - wmtk::PrimitiveType::Edge, + wmtk::PrimitiveType::Face, 1); wmtk::MeshAttributeHandle todo_edgesplit_same_handle = m_mesh.register_attribute( std::string("todo_edgesplit_same_tag"), @@ -126,7 +126,7 @@ void RegularSpace::process_in_1d() vt1 = acc_vertex_tag.scalar_attribute(m_mesh.switch_vertex(face)); vt2 = acc_vertex_tag.scalar_attribute(m_mesh.switch_vertex(m_mesh.switch_edge(face))); et0 = acc_edge_tag.scalar_attribute(face); - et1 = acc_edge_tag.scalar_attribute(m_mesh.switch_vertex(face)); + et1 = acc_edge_tag.scalar_attribute(m_mesh.switch_edge(face)); et2 = acc_edge_tag.scalar_attribute(m_mesh.switch_vertex(m_mesh.switch_edge(face))); if (vt0 == m_input_tag_value && vt1 == m_input_tag_value && vt2 == m_input_tag_value && et0 == m_input_tag_value && et1 == m_input_tag_value && et2 == m_input_tag_value) { @@ -138,20 +138,21 @@ void RegularSpace::process_in_1d() settings_split_face.edge_tag = m_edge_tag; settings_split_face.embedding_tag_value = m_embedding_tag_value; settings_split_face.need_embedding_tag_value = true; - settings_split_face.position = m_position_handle; + settings_split_face.face_split_settings.position = m_position_handle; settings_split_face.split_todo = todo_facesplit_handle; settings_split_face.split_vertex_tag_value = m_split_tag_value; settings_split_face.vertex_tag = m_vertex_tag; - settings_split_face.face_split_settings.initialize_invariants(m_mesh); + settings_split_face.initialize_invariants(m_mesh); m_scheduler.add_operation_type( "facesplit", settings_split_face); while (true) { - m_scheduler.run_operation_on_all(PrimitiveType::Edge, "facesplit"); + m_scheduler.run_operation_on_all(PrimitiveType::Face, "facesplit"); if (m_scheduler.number_of_successful_operations() == 0) { break; } } + m_scheduler.run_operation_on_all(PrimitiveType::Face, "facesplit"); } // edge split @@ -209,6 +210,9 @@ void RegularSpace::process_in_1d() // ... } -void RegularSpace::process_in_2d() {} +void RegularSpace::process_in_2d() +{ + throw std::runtime_error("2 dimension has not been implemented!"); +} } // namespace wmtk::components::internal diff --git a/src/wmtk/invariants/TodoInvariant.cpp b/src/wmtk/invariants/TodoInvariant.cpp index ba91f0e0a4..4a52fa1eb8 100644 --- a/src/wmtk/invariants/TodoInvariant.cpp +++ b/src/wmtk/invariants/TodoInvariant.cpp @@ -8,7 +8,7 @@ TodoInvariant::TodoInvariant(const Mesh& m, const MeshAttributeHandle& tod {} bool TodoInvariant::before(const Tuple& t) const { - ConstAccessor split_todo_accessor = mesh().create_accessor(m_todo_handle); + ConstAccessor split_todo_accessor = mesh().create_accessor(m_todo_handle); return split_todo_accessor.const_scalar_attribute(t) == 1; } } // namespace wmtk \ No newline at end of file diff --git a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp index 5977db8277..fa6212f1ef 100644 --- a/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp +++ b/src/wmtk/operations/tri_mesh/EdgeSplitWithTag.cpp @@ -36,7 +36,7 @@ EdgeSplitWithTag::EdgeSplitWithTag( {} std::string EdgeSplitWithTag::name() const { - return "edge_split_with_tag"; + return "tri_mesh_edge_split_with_tag"; } Tuple EdgeSplitWithTag::return_tuple() const { diff --git a/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp index 7cec062994..07c5ffc1fa 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp @@ -29,7 +29,7 @@ FaceSplitAtMidPoint::FaceSplitAtMidPoint( {} std::string FaceSplitAtMidPoint::name() const { - return "tri_mesh_split_edge_at_midpoint"; + return "tri_mesh_split_face_at_midpoint"; } Tuple FaceSplitAtMidPoint::return_tuple() const { @@ -41,6 +41,11 @@ bool FaceSplitAtMidPoint::before() const } bool FaceSplitAtMidPoint::execute() { + const Eigen::Vector3d p0 = m_pos_accessor.vector_attribute(input_tuple()); + const Eigen::Vector3d p1 = m_pos_accessor.vector_attribute(mesh().switch_vertex(input_tuple())); + const Eigen::Vector3d p2 = + m_pos_accessor.vector_attribute(mesh().switch_vertex(mesh().switch_edge(input_tuple()))); + { FaceSplit split_op(mesh(), input_tuple(), m_settings.split_settings); if (!split_op()) { @@ -49,11 +54,6 @@ bool FaceSplitAtMidPoint::execute() m_output_tuple = split_op.return_tuple(); } - const Eigen::Vector3d p0 = m_pos_accessor.vector_attribute(input_tuple()); - const Eigen::Vector3d p1 = m_pos_accessor.vector_attribute(mesh().switch_vertex(input_tuple())); - const Eigen::Vector3d p2 = - m_pos_accessor.vector_attribute(mesh().switch_edge(mesh().switch_vertex(input_tuple()))); - m_pos_accessor.vector_attribute(m_output_tuple) = (p0 + p1 + p2) / 3.0; return true; diff --git a/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp index d1d89d9c35..417d07e37f 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp @@ -36,7 +36,7 @@ class FaceSplitAtMidPoint : public TriMeshOperation, private TupleOperation Tuple return_tuple() const; - static PrimitiveType primitive_type() { return PrimitiveType::Edge; } + static PrimitiveType primitive_type() { return PrimitiveType::Face; } protected: bool before() const override; diff --git a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp index 06298147e0..5851977c21 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp @@ -28,7 +28,6 @@ FaceSplitWithTag::FaceSplitWithTag( const OperationSettings& settings) : TriMeshOperation(m) , TupleOperation(settings.face_split_settings.split_settings.invariants, t) - , m_pos_accessor{m.create_accessor(settings.position)} , m_vertex_tag_accessor{m.create_accessor(settings.vertex_tag)} , m_edge_tag_accessor{m.create_accessor(settings.edge_tag)} , m_split_todo_accessor{m.create_accessor(settings.split_todo)} @@ -36,7 +35,7 @@ FaceSplitWithTag::FaceSplitWithTag( {} std::string FaceSplitWithTag::name() const { - return "tri_mesh_split_edge_at_midpoint"; + return "tri_mesh_split_face_with_tag"; } Tuple FaceSplitWithTag::return_tuple() const { @@ -44,10 +43,13 @@ Tuple FaceSplitWithTag::return_tuple() const } bool FaceSplitWithTag::execute() { - const Eigen::Vector3d p0 = m_pos_accessor.vector_attribute(input_tuple()); - const Eigen::Vector3d p1 = m_pos_accessor.vector_attribute(mesh().switch_vertex(input_tuple())); - const Eigen::Vector3d p2 = - m_pos_accessor.vector_attribute(mesh().switch_vertex(mesh().switch_edge(input_tuple()))); + // record ord tag for the three edges + long t0, t1, t2; + t0 = m_edge_tag_accessor.scalar_attribute(input_tuple()); + t1 = m_edge_tag_accessor.scalar_attribute(mesh().switch_edge(input_tuple())); + t2 = m_edge_tag_accessor.scalar_attribute( + mesh().switch_edge(mesh().switch_vertex(input_tuple()))); + { FaceSplitAtMidPoint split_op(mesh(), input_tuple(), m_settings.face_split_settings); if (!split_op()) { @@ -56,12 +58,7 @@ bool FaceSplitWithTag::execute() m_output_tuple = split_op.return_tuple(); } - m_pos_accessor.vector_attribute(m_output_tuple) = (p0 + p1 + p2) / 3.0; m_vertex_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.split_vertex_tag_value; - m_split_todo_accessor.scalar_attribute(m_output_tuple) = 0; - m_split_todo_accessor.scalar_attribute(mesh().switch_face(m_output_tuple)) = 0; - m_split_todo_accessor.scalar_attribute(mesh().switch_face(mesh().switch_edge(m_output_tuple))) = - 0; if (m_settings.need_embedding_tag_value) { m_edge_tag_accessor.scalar_attribute(m_output_tuple) = m_settings.embedding_tag_value; @@ -81,6 +78,14 @@ bool FaceSplitWithTag::execute() mesh().switch_vertex(mesh().switch_edge(mesh().switch_face(m_output_tuple)))); } + // set three edges' tags back + m_edge_tag_accessor.scalar_attribute(mesh().switch_edge(mesh().switch_vertex(m_output_tuple))) = + t0; + m_edge_tag_accessor.scalar_attribute( + mesh().switch_edge(mesh().switch_vertex(mesh().switch_face(m_output_tuple)))) = t1; + m_edge_tag_accessor.scalar_attribute(mesh().switch_edge( + mesh().switch_vertex(mesh().switch_face(mesh().switch_edge(m_output_tuple))))) = t2; + return true; } } // namespace tri_mesh diff --git a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp index 163fef4f86..f411b40b16 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp @@ -12,7 +12,6 @@ template <> struct OperationSettings { OperationSettings face_split_settings; - MeshAttributeHandle position; MeshAttributeHandle vertex_tag; MeshAttributeHandle edge_tag; MeshAttributeHandle split_todo; @@ -34,7 +33,7 @@ class FaceSplitWithTag : public TriMeshOperation, private TupleOperation Tuple return_tuple() const; - static PrimitiveType primitive_type() { return PrimitiveType::Edge; } + static PrimitiveType primitive_type() { return PrimitiveType::Face; } protected: bool execute() override; @@ -42,7 +41,6 @@ class FaceSplitWithTag : public TriMeshOperation, private TupleOperation private: Tuple m_output_tuple; - Accessor m_pos_accessor; Accessor m_vertex_tag_accessor; Accessor m_edge_tag_accessor; Accessor m_split_todo_accessor; diff --git a/tests/components/test_component_regular_space.cpp b/tests/components/test_component_regular_space.cpp index 20df4b1d58..9fb5c7ef65 100644 --- a/tests/components/test_component_regular_space.cpp +++ b/tests/components/test_component_regular_space.cpp @@ -8,6 +8,7 @@ #include #include #include +#include "wmtk/../../tests/tools/DEBUG_TriMesh.hpp" #include "wmtk/../../tests/tools/TriMesh_examples.hpp" using json = nlohmann::json; @@ -33,63 +34,184 @@ TEST_CASE("regular_space_file_reading", "[components][regular_space][.]") REQUIRE(false); } -TEST_CASE("1d case", "[components][regular_space][scheduler]") +TEST_CASE("regular_space_component", "[components][regular_space][scheduler]") { - const long input_value = 1; const long embedding_value = 0; + const long input_value = 1; const long split_value = 2; - TriMesh m = wmtk::tests::hex_plus_two_with_position(); - MeshAttributeHandle pos_handle = - m.get_attribute_handle("position", wmtk::PrimitiveType::Vertex); - MeshAttributeHandle vertex_tag_handle = m.register_attribute( - "vertex_tag", - wmtk::PrimitiveType::Vertex, - 1, - false, - embedding_value); - MeshAttributeHandle edge_tag_handle = m.register_attribute( - "edge_tag", - wmtk::PrimitiveType::Edge, - 1, - false, - embedding_value); - - // 0---1---2 - // / \ / \ / \ . - // 3---4---5---6 - // \ / \ / . - // 7---8 - // set 0 1 4 5 6 - const std::vector& vs = m.get_all(wmtk::PrimitiveType::Vertex); - Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); - acc_vertex_tag.scalar_attribute(vs[0]) = input_value; - acc_vertex_tag.scalar_attribute(vs[1]) = input_value; - acc_vertex_tag.scalar_attribute(vs[4]) = input_value; - acc_vertex_tag.scalar_attribute(vs[5]) = input_value; - acc_vertex_tag.scalar_attribute(vs[6]) = input_value; - - components::internal::RegularSpace rs( - m, - pos_handle, - vertex_tag_handle, - edge_tag_handle, - input_value, - embedding_value, - split_value, - 0); - rs.process(); - ParaviewWriter writer1(data_dir / "my_result", "position", m, true, true, true, false); - m.serialize(writer1); - - Accessor acc_todo = m.create_accessor( - m.get_attribute_handle(std::string("todo_edgesplit_same_tag"), PrimitiveType::Edge)); - int todo_num = 0; - for (const Tuple& t : m.get_all(PrimitiveType::Edge)) { - spdlog::info("{}", acc_todo.scalar_attribute(t)); - if (acc_todo.scalar_attribute(t) == 1) { - todo_num++; + SECTION("0d_case") + { + TriMesh m = wmtk::tests::hex_plus_two_with_position(); + MeshAttributeHandle pos_handle = + m.get_attribute_handle("position", wmtk::PrimitiveType::Vertex); + MeshAttributeHandle vertex_tag_handle = m.register_attribute( + "vertex_tag", + wmtk::PrimitiveType::Vertex, + 1, + false, + embedding_value); + MeshAttributeHandle edge_tag_handle = m.register_attribute( + "edge_tag", + wmtk::PrimitiveType::Edge, + 1, + false, + embedding_value); + + // 0---1---2 + // / \ / \ / \ . + // 3---4---5---6 + // \ / \ / . + // 7---8 + // set 0 1 4 5 6 + const std::vector& vs = m.get_all(wmtk::PrimitiveType::Vertex); + Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); + acc_vertex_tag.scalar_attribute(vs[0]) = input_value; + acc_vertex_tag.scalar_attribute(vs[1]) = input_value; + acc_vertex_tag.scalar_attribute(vs[4]) = input_value; + acc_vertex_tag.scalar_attribute(vs[5]) = input_value; + acc_vertex_tag.scalar_attribute(vs[6]) = input_value; + + components::internal::RegularSpace rs( + m, + pos_handle, + vertex_tag_handle, + edge_tag_handle, + input_value, + embedding_value, + split_value, + 0); + rs.process(); + + CHECK(m.get_all(PrimitiveType::Vertex).size() == 15); + + Accessor acc_todo = m.create_accessor(m.get_attribute_handle( + std::string("todo_edgesplit_same_tag"), + PrimitiveType::Edge)); + int todo_num = 0; + for (const Tuple& t : m.get_all(PrimitiveType::Edge)) { + // spdlog::info("{}", acc_todo.scalar_attribute(t)); + if (acc_todo.scalar_attribute(t) == 1) { + todo_num++; + } + } + CHECK(todo_num == 0); + + if (false) { + ParaviewWriter writer(data_dir / "my_result", "position", m, true, true, true, false); + m.serialize(writer); } } - CHECK(todo_num == 0); + SECTION("1d_case") + { + tests::DEBUG_TriMesh m = wmtk::tests::hex_plus_two_with_position(); + MeshAttributeHandle pos_handle = + m.get_attribute_handle("position", wmtk::PrimitiveType::Vertex); + MeshAttributeHandle vertex_tag_handle = m.register_attribute( + "vertex_tag", + wmtk::PrimitiveType::Vertex, + 1, + false, + embedding_value); + MeshAttributeHandle edge_tag_handle = m.register_attribute( + "edge_tag", + wmtk::PrimitiveType::Edge, + 1, + false, + embedding_value); + + // 0---1---2 + // / \ / \ / \ . + // 3---4---5---6 + // \ / \ / . + // 7---8 + // set vertex 0 1 4 5 6 7 + // set edge 4-5 5-1 1-4 4-7 7-3 + const std::vector& vs = m.get_all(wmtk::PrimitiveType::Vertex); + Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); + acc_vertex_tag.scalar_attribute(vs[0]) = input_value; + acc_vertex_tag.scalar_attribute(vs[1]) = input_value; + acc_vertex_tag.scalar_attribute(vs[3]) = input_value; + acc_vertex_tag.scalar_attribute(vs[4]) = input_value; + acc_vertex_tag.scalar_attribute(vs[5]) = input_value; + acc_vertex_tag.scalar_attribute(vs[6]) = input_value; + acc_vertex_tag.scalar_attribute(vs[7]) = input_value; + const std::vector& es = m.get_all(wmtk::PrimitiveType::Edge); + Accessor acc_edge_tag = m.create_accessor(edge_tag_handle); + acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(4, 5, 2)) = input_value; + acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(5, 1, 2)) = input_value; + acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(1, 4, 2)) = input_value; + acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(7, 4, 5)) = input_value; + acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(7, 3, 5)) = input_value; + + components::internal::RegularSpace rs( + m, + pos_handle, + vertex_tag_handle, + edge_tag_handle, + input_value, + embedding_value, + split_value, + 1); + rs.process(); + + Accessor acc_todo_edge = m.create_accessor(m.get_attribute_handle( + std::string("todo_edgesplit_same_tag"), + PrimitiveType::Edge)); + Accessor acc_todo_face = m.create_accessor( + m.get_attribute_handle(std::string("todo_facesplit_tag"), PrimitiveType::Face)); + int todo_num = 0; + for (const Tuple& t : m.get_all(PrimitiveType::Edge)) { + // spdlog::info("{}", acc_todo.scalar_attribute(t)); + if (acc_todo_edge.scalar_attribute(t) == 1) { + todo_num++; + } + } + for (const Tuple& t : m.get_all(PrimitiveType::Face)) { + // spdlog::info("{}", acc_todo.scalar_attribute(t)); + if (acc_todo_face.scalar_attribute(t) == 1) { + todo_num++; + } + } + CHECK(todo_num == 0); + CHECK(m.get_all(PrimitiveType::Face).size() == 17); + CHECK(m.get_all(PrimitiveType::Vertex).size() == 15); + if (true) { + ParaviewWriter writer(data_dir / "my_result", "position", m, true, true, true, false); + m.serialize(writer); + } + } + SECTION("2d_case") + { + tests::DEBUG_TriMesh m = wmtk::tests::hex_plus_two_with_position(); + MeshAttributeHandle pos_handle = + m.get_attribute_handle("position", wmtk::PrimitiveType::Vertex); + MeshAttributeHandle vertex_tag_handle = m.register_attribute( + "vertex_tag", + wmtk::PrimitiveType::Vertex, + 1, + false, + embedding_value); + MeshAttributeHandle edge_tag_handle = m.register_attribute( + "edge_tag", + wmtk::PrimitiveType::Edge, + 1, + false, + embedding_value); + const std::vector& vs = m.get_all(wmtk::PrimitiveType::Vertex); + Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); + const std::vector& es = m.get_all(wmtk::PrimitiveType::Edge); + Accessor acc_edge_tag = m.create_accessor(edge_tag_handle); + + components::internal::RegularSpace rs( + m, + pos_handle, + vertex_tag_handle, + edge_tag_handle, + input_value, + embedding_value, + split_value, + 2); + CHECK_THROWS(rs.process()); + } } \ No newline at end of file diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 09eb580614..54d7210966 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include "tools/DEBUG_TriMesh.hpp" @@ -1227,7 +1229,7 @@ TEST_CASE("split_face", "[operations][split][2D]") CHECK(m.id(m.switch_vertex(m.switch_edge(ret)), PV) == 2); CHECK(SimplicialComplex::vertex_one_ring(m, ret).size() == 3); } - SECTION("split in quad") + SECTION("split_face_in_quad") { // 3--1--- 0 // | / \ . @@ -1248,7 +1250,7 @@ TEST_CASE("split_face", "[operations][split][2D]") CHECK(m.id(m.switch_vertex(op.return_tuple()), PV) == 1); CHECK(m.id(m.switch_vertex(m.switch_edge(op.return_tuple())), PV) == 0); } - SECTION("split in diamond") + SECTION("split_in_diamond_with_attribute") { // 0---1---2 // / \ / \ / \ . @@ -1260,20 +1262,179 @@ TEST_CASE("split_face", "[operations][split][2D]") Tuple f0 = m.edge_tuple_between_v1_v2(3, 4, 0); // on boundary Tuple f1 = m.edge_tuple_between_v1_v2(8, 9, 8); // out boundary Tuple f2 = m.edge_tuple_between_v1_v2(4, 8, 7); // overlap of f0 and f1 - OperationSettings settings; + + MeshAttributeHandle attri_handle = + m.register_attribute("test_attribute", PF, 1); + Accessor acc_attri = m.create_accessor(attri_handle); + acc_attri.scalar_attribute(f1) = 1; + + OperationSettings settings; settings.initialize_invariants(m); - wmtk::operations::tri_mesh::FaceSplit op0(m, f0, settings); - wmtk::operations::tri_mesh::FaceSplit op1(m, f1, settings); - wmtk::operations::tri_mesh::FaceSplit op2(m, f2, settings); + settings.position = m.get_attribute_handle("position", PV); + wmtk::operations::tri_mesh::FaceSplitAtMidPoint op0(m, f0, settings); + wmtk::operations::tri_mesh::FaceSplitAtMidPoint op1(m, f1, settings); + wmtk::operations::tri_mesh::FaceSplitAtMidPoint op2(m, f2, settings); CHECK(op0()); auto handle = m.get_attribute_handle(std::string("position"), PV); auto acc = m.create_accessor(handle); CHECK(op1()); CHECK(!op2()); + + for (const Tuple& t : m.get_all(PF)) { + CHECK(acc_attri.scalar_attribute(t) == 0); + } + + if (false) { + const std::filesystem::path data_dir = WMTK_DATA_DIR; + ParaviewWriter writer(data_dir / "my_result", "position", m, true, true, true, false); + m.serialize(writer); + } + } + SECTION("split_single_triangle_at_mid_point") + { + // 0 + // / \ + // 2 1 + // / 0 \ + // / \ + // 1 ----0---- 2 + // + // this case covered the on boundary case + // V.row(0) << 0, 0, 0; + // V.row(1) << 1, 0, 0; + // V.row(2) << 0.5, 0.866, 0; + DEBUG_TriMesh m = single_triangle_with_position(); + Tuple f = m.edge_tuple_between_v1_v2(1, 2, 0); + OperationSettings settings; + settings.initialize_invariants(m); + MeshAttributeHandle pos_handle = m.get_attribute_handle("position", PV); + settings.position = pos_handle; + wmtk::operations::tri_mesh::FaceSplitAtMidPoint op(m, f, settings); + bool is_success = op(); + Tuple ret = op.return_tuple(); + CHECK(is_success); + CHECK(m.get_all(PV).size() == 4); + CHECK(!m.is_boundary_vertex(ret)); + CHECK(!m.is_boundary_edge(ret)); + CHECK(!m.is_boundary_edge(m.switch_edge(ret))); + CHECK(m.id(ret, PV) == 4); + CHECK(m.id(m.switch_vertex(ret), PV) == 1); + CHECK(m.id(m.switch_vertex(m.switch_edge(ret)), PV) == 2); + CHECK(SimplicialComplex::vertex_one_ring(m, ret).size() == 3); + Accessor acc_pos = m.create_accessor(pos_handle); + CHECK(acc_pos.vector_attribute(ret).x() == 0.5); + CHECK(acc_pos.vector_attribute(m.switch_vertex(ret)).x() == 1); + } + SECTION("split_single_triangle_at_mid_point_with_tag_embedding_on") + { + // 0---1---2 + // / \ / \ / \ . + // 3---4---5---6 + // \ / \ / \ / + // 7---8---9 + DEBUG_TriMesh m = edge_region_with_position(); + Tuple f = m.edge_tuple_between_v1_v2(3, 4, 0); + MeshAttributeHandle pos_handle = m.get_attribute_handle("position", PV); + MeshAttributeHandle todo_handle = m.register_attribute("todo_face", PF, 1); + MeshAttributeHandle edge_tag_handle = m.register_attribute("edge_tag", PE, 1); + MeshAttributeHandle vertex_tag_handle = + m.register_attribute("vertex_tag", PV, 1); + Accessor acc_todo = m.create_accessor(todo_handle); + Accessor acc_edge_tag = m.create_accessor(edge_tag_handle); + Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); + acc_todo.scalar_attribute(f) = 1; + OperationSettings settings; + settings.edge_tag = edge_tag_handle; + settings.vertex_tag = vertex_tag_handle; + settings.embedding_tag_value = 0; + settings.face_split_settings.position = pos_handle; + settings.need_embedding_tag_value = true; + settings.split_todo = todo_handle; + settings.split_vertex_tag_value = 3; + settings.initialize_invariants(m); + wmtk::operations::tri_mesh::FaceSplitWithTag op(m, f, settings); + CHECK(op()); + CHECK(m.get_all(PF).size() == 12); + for (const Tuple& t : m.get_all(PF)) { + CHECK(acc_todo.scalar_attribute(t) == 0); + } + } + SECTION("split_single_triangle_at_mid_point_with_tag_embedding_off") + { + // 0 + // / \ + // 2 1 + // / 0 \ + // / \ + // 1 ----0---- 2 + // + // this case covered the on boundary case + // V.row(0) << 0, 0, 0; + // V.row(1) << 1, 0, 0; + // V.row(2) << 0.5, 0.866, 0; + DEBUG_TriMesh m = single_triangle_with_position(); + Tuple f = m.edge_tuple_between_v1_v2(1, 2, 0); + MeshAttributeHandle pos_handle = m.get_attribute_handle("position", PV); + MeshAttributeHandle todo_handle = m.register_attribute("todo_face", PF, 1); + MeshAttributeHandle edge_tag_handle = m.register_attribute("edge_tag", PE, 1); + MeshAttributeHandle vertex_tag_handle = + m.register_attribute("vertex_tag", PV, 1); + Accessor acc_todo = m.create_accessor(todo_handle); + Accessor acc_edge_tag = m.create_accessor(edge_tag_handle); + Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); + acc_todo.scalar_attribute(f) = 1; + acc_vertex_tag.scalar_attribute(m.edge_tuple_between_v1_v2(1, 2, 0)) = 1; + acc_vertex_tag.scalar_attribute(m.edge_tuple_between_v1_v2(0, 1, 0)) = 2; + acc_vertex_tag.scalar_attribute(m.edge_tuple_between_v1_v2(2, 0, 0)) = 3; + OperationSettings settings; + settings.edge_tag = edge_tag_handle; + settings.vertex_tag = vertex_tag_handle; + settings.embedding_tag_value = 0; + settings.face_split_settings.position = pos_handle; + settings.need_embedding_tag_value = false; + settings.split_todo = todo_handle; + settings.split_vertex_tag_value = 3; + settings.initialize_invariants(m); + wmtk::operations::tri_mesh::FaceSplitWithTag op(m, f, settings); + CHECK(op()); + CHECK(acc_edge_tag.scalar_attribute(op.return_tuple()) == 1); + CHECK(acc_edge_tag.scalar_attribute(m.switch_edge(op.return_tuple())) == 3); + CHECK(acc_edge_tag.scalar_attribute(m.switch_edge(m.switch_face(op.return_tuple()))) == 2); + CHECK(m.get_all(PF).size() == 3); + for (const Tuple& t : m.get_all(PF)) { + CHECK(acc_todo.scalar_attribute(t) == 0); + } + } + SECTION("should fail with todo tag 0") + { + DEBUG_TriMesh m = single_triangle_with_position(); + Tuple f = m.edge_tuple_between_v1_v2(1, 2, 0); + MeshAttributeHandle pos_handle = m.get_attribute_handle("position", PV); + MeshAttributeHandle todo_handle = m.register_attribute("todo_face", PF, 1); + MeshAttributeHandle edge_tag_handle = m.register_attribute("edge_tag", PE, 1); + MeshAttributeHandle vertex_tag_handle = + m.register_attribute("vertex_tag", PV, 1); + Accessor acc_todo = m.create_accessor(todo_handle); + Accessor acc_edge_tag = m.create_accessor(edge_tag_handle); + Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); + acc_todo.scalar_attribute(f) = 0; + acc_vertex_tag.scalar_attribute(m.edge_tuple_between_v1_v2(1, 2, 0)) = 1; + acc_vertex_tag.scalar_attribute(m.edge_tuple_between_v1_v2(0, 1, 0)) = 2; + acc_vertex_tag.scalar_attribute(m.edge_tuple_between_v1_v2(2, 0, 0)) = 3; + OperationSettings settings; + settings.edge_tag = edge_tag_handle; + settings.vertex_tag = vertex_tag_handle; + settings.embedding_tag_value = 0; + settings.face_split_settings.position = pos_handle; + settings.need_embedding_tag_value = false; + settings.split_todo = todo_handle; + settings.split_vertex_tag_value = 3; + settings.initialize_invariants(m); + wmtk::operations::tri_mesh::FaceSplitWithTag op(m, f, settings); + CHECK(!op()); } } - TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") { // 3--1--- 0 From fd18030e3869ec6f8d4ae0a68daa897bb074ee13 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Sun, 22 Oct 2023 15:23:01 -0400 Subject: [PATCH 16/19] modify the test, make it cover more code --- src/wmtk/operations/tri_mesh/FaceSplit.cpp | 2 +- .../tri_mesh/FaceSplitAtMidPoint.cpp | 4 - .../tri_mesh/FaceSplitAtMidPoint.hpp | 5 - .../operations/tri_mesh/FaceSplitWithTag.cpp | 7 - .../operations/tri_mesh/FaceSplitWithTag.hpp | 2 - .../test_component_regular_space.cpp | 174 +++++++++--------- tests/test_2d_operations.cpp | 143 +++++++++----- 7 files changed, 185 insertions(+), 152 deletions(-) diff --git a/src/wmtk/operations/tri_mesh/FaceSplit.cpp b/src/wmtk/operations/tri_mesh/FaceSplit.cpp index b8aa9c597e..8a097951e4 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplit.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplit.cpp @@ -27,7 +27,7 @@ FaceSplit::FaceSplit(Mesh& m, const Tuple& t, const OperationSettings std::string FaceSplit::name() const { - return "face_split_with_tag"; + return "tri_mesh_face_split"; } bool FaceSplit::before() const diff --git a/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp index 07c5ffc1fa..70c45b495f 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.cpp @@ -35,10 +35,6 @@ Tuple FaceSplitAtMidPoint::return_tuple() const { return m_output_tuple; } -bool FaceSplitAtMidPoint::before() const -{ - return TupleOperation::before(); -} bool FaceSplitAtMidPoint::execute() { const Eigen::Vector3d p0 = m_pos_accessor.vector_attribute(input_tuple()); diff --git a/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp index 417d07e37f..2a9c5fd7ba 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitAtMidPoint.hpp @@ -14,11 +14,7 @@ struct OperationSettings OperationSettings split_settings; // handle to vertex position MeshAttributeHandle position; - // too short edges get ignored - double min_squared_length = -1; - void initialize_invariants(const TriMesh& m); - // debug functionality to make sure operations are constructed properly bool are_invariants_initialized() const; }; @@ -39,7 +35,6 @@ class FaceSplitAtMidPoint : public TriMeshOperation, private TupleOperation static PrimitiveType primitive_type() { return PrimitiveType::Face; } protected: - bool before() const override; bool execute() override; private: diff --git a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp index 5851977c21..89644a2d0b 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.cpp @@ -14,13 +14,6 @@ void OperationSettings::initialize_invariants(const std::make_shared(m, split_todo)); } -bool OperationSettings::are_invariants_initialized() const -{ - return face_split_settings.are_invariants_initialized() && - find_invariants_in_collection_by_type( - face_split_settings.split_settings.invariants); -} - namespace tri_mesh { FaceSplitWithTag::FaceSplitWithTag( Mesh& m, diff --git a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp index f411b40b16..4fc9cb5570 100644 --- a/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp +++ b/src/wmtk/operations/tri_mesh/FaceSplitWithTag.hpp @@ -19,8 +19,6 @@ struct OperationSettings long embedding_tag_value; bool need_embedding_tag_value; void initialize_invariants(const TriMesh& m); - // debug functionality to make sure operations are constructed properly - bool are_invariants_initialized() const; }; namespace tri_mesh { diff --git a/tests/components/test_component_regular_space.cpp b/tests/components/test_component_regular_space.cpp index 9fb5c7ef65..a26a4807f7 100644 --- a/tests/components/test_component_regular_space.cpp +++ b/tests/components/test_component_regular_space.cpp @@ -36,50 +36,50 @@ TEST_CASE("regular_space_file_reading", "[components][regular_space][.]") TEST_CASE("regular_space_component", "[components][regular_space][scheduler]") { - const long embedding_value = 0; - const long input_value = 1; - const long split_value = 2; - + const long embedding_tag_value = 0; + const long input_tag_value = 1; + const long split_tag_value = 2; + tests::DEBUG_TriMesh m = wmtk::tests::hex_plus_two_with_position(); + MeshAttributeHandle pos_handle = + m.get_attribute_handle("position", wmtk::PrimitiveType::Vertex); + MeshAttributeHandle vertex_tag_handle = m.register_attribute( + "vertex_tag", + wmtk::PrimitiveType::Vertex, + 1, + false, + embedding_tag_value); + MeshAttributeHandle edge_tag_handle = m.register_attribute( + "edge_tag", + wmtk::PrimitiveType::Edge, + 1, + false, + embedding_tag_value); SECTION("0d_case") { - TriMesh m = wmtk::tests::hex_plus_two_with_position(); - MeshAttributeHandle pos_handle = - m.get_attribute_handle("position", wmtk::PrimitiveType::Vertex); - MeshAttributeHandle vertex_tag_handle = m.register_attribute( - "vertex_tag", - wmtk::PrimitiveType::Vertex, - 1, - false, - embedding_value); - MeshAttributeHandle edge_tag_handle = m.register_attribute( - "edge_tag", - wmtk::PrimitiveType::Edge, - 1, - false, - embedding_value); - // 0---1---2 // / \ / \ / \ . // 3---4---5---6 // \ / \ / . // 7---8 // set 0 1 4 5 6 - const std::vector& vs = m.get_all(wmtk::PrimitiveType::Vertex); - Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); - acc_vertex_tag.scalar_attribute(vs[0]) = input_value; - acc_vertex_tag.scalar_attribute(vs[1]) = input_value; - acc_vertex_tag.scalar_attribute(vs[4]) = input_value; - acc_vertex_tag.scalar_attribute(vs[5]) = input_value; - acc_vertex_tag.scalar_attribute(vs[6]) = input_value; + { + const std::vector& vertex_tuples = m.get_all(wmtk::PrimitiveType::Vertex); + Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); + acc_vertex_tag.scalar_attribute(vertex_tuples[0]) = input_tag_value; + acc_vertex_tag.scalar_attribute(vertex_tuples[1]) = input_tag_value; + acc_vertex_tag.scalar_attribute(vertex_tuples[4]) = input_tag_value; + acc_vertex_tag.scalar_attribute(vertex_tuples[5]) = input_tag_value; + acc_vertex_tag.scalar_attribute(vertex_tuples[6]) = input_tag_value; + } components::internal::RegularSpace rs( m, pos_handle, vertex_tag_handle, edge_tag_handle, - input_value, - embedding_value, - split_value, + input_tag_value, + embedding_tag_value, + split_tag_value, 0); rs.process(); @@ -98,28 +98,19 @@ TEST_CASE("regular_space_component", "[components][regular_space][scheduler]") CHECK(todo_num == 0); if (false) { - ParaviewWriter writer(data_dir / "my_result", "position", m, true, true, true, false); + ParaviewWriter writer( + data_dir / "regular_space_result_0d_case", + "position", + m, + true, + true, + true, + false); m.serialize(writer); } } SECTION("1d_case") { - tests::DEBUG_TriMesh m = wmtk::tests::hex_plus_two_with_position(); - MeshAttributeHandle pos_handle = - m.get_attribute_handle("position", wmtk::PrimitiveType::Vertex); - MeshAttributeHandle vertex_tag_handle = m.register_attribute( - "vertex_tag", - wmtk::PrimitiveType::Vertex, - 1, - false, - embedding_value); - MeshAttributeHandle edge_tag_handle = m.register_attribute( - "edge_tag", - wmtk::PrimitiveType::Edge, - 1, - false, - embedding_value); - // 0---1---2 // / \ / \ / \ . // 3---4---5---6 @@ -127,31 +118,32 @@ TEST_CASE("regular_space_component", "[components][regular_space][scheduler]") // 7---8 // set vertex 0 1 4 5 6 7 // set edge 4-5 5-1 1-4 4-7 7-3 - const std::vector& vs = m.get_all(wmtk::PrimitiveType::Vertex); - Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); - acc_vertex_tag.scalar_attribute(vs[0]) = input_value; - acc_vertex_tag.scalar_attribute(vs[1]) = input_value; - acc_vertex_tag.scalar_attribute(vs[3]) = input_value; - acc_vertex_tag.scalar_attribute(vs[4]) = input_value; - acc_vertex_tag.scalar_attribute(vs[5]) = input_value; - acc_vertex_tag.scalar_attribute(vs[6]) = input_value; - acc_vertex_tag.scalar_attribute(vs[7]) = input_value; - const std::vector& es = m.get_all(wmtk::PrimitiveType::Edge); - Accessor acc_edge_tag = m.create_accessor(edge_tag_handle); - acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(4, 5, 2)) = input_value; - acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(5, 1, 2)) = input_value; - acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(1, 4, 2)) = input_value; - acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(7, 4, 5)) = input_value; - acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(7, 3, 5)) = input_value; + { + const std::vector& vertex_tuples = m.get_all(wmtk::PrimitiveType::Vertex); + Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); + acc_vertex_tag.scalar_attribute(vertex_tuples[0]) = input_tag_value; + acc_vertex_tag.scalar_attribute(vertex_tuples[1]) = input_tag_value; + acc_vertex_tag.scalar_attribute(vertex_tuples[3]) = input_tag_value; + acc_vertex_tag.scalar_attribute(vertex_tuples[4]) = input_tag_value; + acc_vertex_tag.scalar_attribute(vertex_tuples[5]) = input_tag_value; + acc_vertex_tag.scalar_attribute(vertex_tuples[6]) = input_tag_value; + acc_vertex_tag.scalar_attribute(vertex_tuples[7]) = input_tag_value; + Accessor acc_edge_tag = m.create_accessor(edge_tag_handle); + acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(4, 5, 2)) = input_tag_value; + acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(5, 1, 2)) = input_tag_value; + acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(1, 4, 2)) = input_tag_value; + acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(7, 4, 5)) = input_tag_value; + acc_edge_tag.scalar_attribute(m.edge_tuple_between_v1_v2(7, 3, 5)) = input_tag_value; + } components::internal::RegularSpace rs( m, pos_handle, vertex_tag_handle, edge_tag_handle, - input_value, - embedding_value, - split_value, + input_tag_value, + embedding_tag_value, + split_tag_value, 1); rs.process(); @@ -176,42 +168,42 @@ TEST_CASE("regular_space_component", "[components][regular_space][scheduler]") CHECK(todo_num == 0); CHECK(m.get_all(PrimitiveType::Face).size() == 17); CHECK(m.get_all(PrimitiveType::Vertex).size() == 15); - if (true) { - ParaviewWriter writer(data_dir / "my_result", "position", m, true, true, true, false); + if (false) { + ParaviewWriter writer( + data_dir / "regular_space_result_1d_case", + "position", + m, + true, + true, + true, + false); m.serialize(writer); } } SECTION("2d_case") { - tests::DEBUG_TriMesh m = wmtk::tests::hex_plus_two_with_position(); - MeshAttributeHandle pos_handle = - m.get_attribute_handle("position", wmtk::PrimitiveType::Vertex); - MeshAttributeHandle vertex_tag_handle = m.register_attribute( - "vertex_tag", - wmtk::PrimitiveType::Vertex, - 1, - false, - embedding_value); - MeshAttributeHandle edge_tag_handle = m.register_attribute( - "edge_tag", - wmtk::PrimitiveType::Edge, - 1, - false, - embedding_value); - const std::vector& vs = m.get_all(wmtk::PrimitiveType::Vertex); - Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); - const std::vector& es = m.get_all(wmtk::PrimitiveType::Edge); - Accessor acc_edge_tag = m.create_accessor(edge_tag_handle); - components::internal::RegularSpace rs( m, pos_handle, vertex_tag_handle, edge_tag_handle, - input_value, - embedding_value, - split_value, + input_tag_value, + embedding_tag_value, + split_tag_value, 2); CHECK_THROWS(rs.process()); } + SECTION("unknown_dimension_case") + { + components::internal::RegularSpace rs( + m, + pos_handle, + vertex_tag_handle, + edge_tag_handle, + input_tag_value, + embedding_tag_value, + split_tag_value, + -7); + CHECK_THROWS(rs.process()); + } } \ No newline at end of file diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 54d7210966..3e472e8efc 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1214,6 +1214,7 @@ TEST_CASE("split_face", "[operations][split][2D]") OperationSettings settings; settings.initialize_invariants(m); wmtk::operations::tri_mesh::FaceSplit op(m, f, settings); + CHECK(op.name().compare("tri_mesh_face_split") == 0); bool is_success = op(); Tuple ret = op.return_tuple(); // spdlog::info("{}", m.id(ret, PV)); @@ -1274,6 +1275,9 @@ TEST_CASE("split_face", "[operations][split][2D]") wmtk::operations::tri_mesh::FaceSplitAtMidPoint op0(m, f0, settings); wmtk::operations::tri_mesh::FaceSplitAtMidPoint op1(m, f1, settings); wmtk::operations::tri_mesh::FaceSplitAtMidPoint op2(m, f2, settings); + CHECK(op0.name().compare("tri_mesh_split_face_at_midpoint") == 0); + CHECK(op1.name().compare("tri_mesh_split_face_at_midpoint") == 0); + CHECK(op2.name().compare("tri_mesh_split_face_at_midpoint") == 0); CHECK(op0()); auto handle = m.get_attribute_handle(std::string("position"), PV); auto acc = m.create_accessor(handle); @@ -1307,6 +1311,7 @@ TEST_CASE("split_face", "[operations][split][2D]") Tuple f = m.edge_tuple_between_v1_v2(1, 2, 0); OperationSettings settings; settings.initialize_invariants(m); + CHECK(settings.are_invariants_initialized()); MeshAttributeHandle pos_handle = m.get_attribute_handle("position", PV); settings.position = pos_handle; wmtk::operations::tri_mesh::FaceSplitAtMidPoint op(m, f, settings); @@ -1452,18 +1457,17 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") Eigen::MatrixXd V(5, 3); V << 0, 0, 0, -1, -1, 0, 1, -1, 0, -1, 1, 0, 1, -1, 0; - + DEBUG_TriMesh m = interior_edge(); + OperationSettings settings; + wmtk::MeshAttributeHandle edge_handle = + m.register_attribute(std::string("edge_tag"), PE, 1); + wmtk::MeshAttributeHandle vertex_handle = + m.register_attribute(std::string("vertex_tag"), PV, 1); + wmtk::MeshAttributeHandle todo_handle = + m.register_attribute(std::string("todo_tag"), PE, 1); + wmtk::mesh_utils::set_matrix_attribute(V, "position", PrimitiveType::Vertex, m); SECTION("should all fail") { - DEBUG_TriMesh m = interior_edge(); - OperationSettings settings; - wmtk::MeshAttributeHandle edge_handle = - m.register_attribute(std::string("edge_tag"), PE, 1); - wmtk::MeshAttributeHandle vertex_handle = - m.register_attribute(std::string("vertex_tag"), PV, 1); - wmtk::MeshAttributeHandle todo_handle = - m.register_attribute(std::string("todo_tag"), PE, 1); - wmtk::mesh_utils::set_matrix_attribute(V, "position", PrimitiveType::Vertex, m); settings.edge_tag = edge_handle; settings.vertex_tag = vertex_handle; settings.embedding_tag_value = -1; @@ -1477,21 +1481,14 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") settings.initialize_invariants(m); for (Tuple t : m.get_all(PV)) { wmtk::operations::tri_mesh::EdgeSplitWithTag op(m, t, settings); + CHECK(op.name().compare("tri_mesh_edge_split_with_tag") == 0); CHECK(!op()); } } - SECTION("check the embedding value and the operations should only success twice") + SECTION("check the embedding value and the operations should only success twice -- need " + "embedding = true") { - DEBUG_TriMesh m = interior_edge(); - OperationSettings settings; - wmtk::MeshAttributeHandle edge_handle = - m.register_attribute(std::string("edge_tag"), PE, 1); - wmtk::MeshAttributeHandle vertex_handle = - m.register_attribute(std::string("vertex_tag"), PV, 1); - wmtk::MeshAttributeHandle todo_handle = - m.register_attribute(std::string("todo_tag"), PE, 1); - wmtk::mesh_utils::set_matrix_attribute(V, "position", PrimitiveType::Vertex, m); settings.edge_tag = edge_handle; settings.vertex_tag = vertex_handle; settings.embedding_tag_value = -1; @@ -1511,30 +1508,92 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") Tuple e1 = m.edge_tuple_between_v1_v2(1, 2, 0); acc.scalar_attribute(e0) = 1; acc.scalar_attribute(e1) = 1; - wmtk::operations::tri_mesh::EdgeSplitWithTag op0(m, e0, settings); - CHECK(op0()); - // todo marks should be removed - CHECK(acc.scalar_attribute(op0.return_tuple()) == 0); - CHECK(acc.scalar_attribute(m.switch_edge(op0.return_tuple())) == 0); - CHECK( - acc.scalar_attribute(m.switch_edge(m.switch_face(m.switch_edge(op0.return_tuple())))) == - 0); - CHECK(acc.scalar_attribute(m.switch_edge(m.switch_face(op0.return_tuple()))) == 0); - // new tag value should be marked - CHECK(acc_e.scalar_attribute(op0.return_tuple()) == -1); - CHECK(acc_e.scalar_attribute(m.switch_edge(op0.return_tuple())) == -2); - CHECK( - acc_e.scalar_attribute( - m.switch_edge(m.switch_face(m.switch_edge(op0.return_tuple())))) == -1); - CHECK(acc_e.scalar_attribute(m.switch_edge(m.switch_face(op0.return_tuple()))) == -2); - CHECK(acc_v.scalar_attribute(op0.return_tuple()) == -3); int success_num = 0; - for (Tuple t : m.get_all(PE)) { - wmtk::operations::tri_mesh::EdgeSplitWithTag op(m, t, settings); - if (op()) { - success_num++; + for (int i = 0; i < 5; i++) { + // i should be 2, but I set 5 for make sure there are no additional error todo tag + // created in this process. + for (const Tuple& t : m.get_all(PE)) { + wmtk::operations::tri_mesh::EdgeSplitWithTag op(m, t, settings); + if (op()) { + // todo marks should be removed + CHECK(acc.scalar_attribute(op.return_tuple()) == 0); + CHECK(acc.scalar_attribute(m.switch_edge(op.return_tuple())) == 0); + CHECK( + acc.scalar_attribute( + m.switch_edge(m.switch_face(m.switch_edge(op.return_tuple())))) == 0); + CHECK( + acc.scalar_attribute(m.switch_edge(m.switch_face(op.return_tuple()))) == 0); + // new tag value should be marked + CHECK(acc_e.scalar_attribute(op.return_tuple()) == -1); + CHECK(acc_e.scalar_attribute(m.switch_edge(op.return_tuple())) == -2); + CHECK( + acc_e.scalar_attribute( + m.switch_edge(m.switch_face(m.switch_edge(op.return_tuple())))) == -1); + CHECK( + acc_e.scalar_attribute(m.switch_edge(m.switch_face(op.return_tuple()))) == + -2); + CHECK(acc_v.scalar_attribute(op.return_tuple()) == -3); + success_num++; + } + } + } + CHECK(success_num == 2); + } + SECTION("check the embedding value and the operations should only success twice -- need " + "embedding = false") + { + settings.edge_tag = edge_handle; + settings.vertex_tag = vertex_handle; + settings.embedding_tag_value = -1; + settings.need_embedding_tag_value = false; + settings.split_with_tag_settings.position = + m.get_attribute_handle(std::string("position"), PV); + settings.split_with_tag_settings.split_settings.split_boundary_edges = true; + settings.split_edge_tag_value = -2; + settings.split_vertex_tag_value = -3; + settings.split_todo = todo_handle; + settings.initialize_invariants(m); + std::vector edges = m.get_all(PE); + wmtk::Accessor acc = m.create_accessor(todo_handle); + wmtk::Accessor acc_e = m.create_accessor(edge_handle); + wmtk::Accessor acc_v = m.create_accessor(vertex_handle); + Tuple e0 = m.edge_tuple_between_v1_v2(1, 0, 1); + Tuple e1 = m.edge_tuple_between_v1_v2(1, 2, 0); + acc.scalar_attribute(e0) = 1; + acc.scalar_attribute(e1) = 1; + int success_num = 0; + for (int i = 0; i < 5; i++) { + // i should be 2, but I set 5 for make sure there are no additional error todo tag + // created in this process. + for (const Tuple& t : m.get_all(PE)) { + wmtk::operations::tri_mesh::EdgeSplitWithTag op(m, t, settings); + if (op()) { + // todo marks should be removed + CHECK(acc.scalar_attribute(op.return_tuple()) == 0); + CHECK(acc.scalar_attribute(m.switch_edge(op.return_tuple())) == 0); + CHECK( + acc.scalar_attribute( + m.switch_edge(m.switch_face(m.switch_edge(op.return_tuple())))) == 0); + CHECK( + acc.scalar_attribute(m.switch_edge(m.switch_face(op.return_tuple()))) == 0); + // new tag value should be marked + CHECK( + acc_e.scalar_attribute(op.return_tuple()) == + acc_v.scalar_attribute(m.switch_vertex(op.return_tuple()))); + CHECK(acc_e.scalar_attribute(m.switch_edge(op.return_tuple())) == -2); + CHECK( + acc_e.scalar_attribute( + m.switch_edge(m.switch_face(m.switch_edge(op.return_tuple())))) == + acc_v.scalar_attribute(m.switch_vertex( + m.switch_edge(m.switch_face(m.switch_edge(op.return_tuple())))))); + CHECK( + acc_e.scalar_attribute(m.switch_edge(m.switch_face(op.return_tuple()))) == + -2); + CHECK(acc_v.scalar_attribute(op.return_tuple()) == -3); + success_num++; + } } } - CHECK(success_num == 1); + CHECK(success_num == 2); } } \ No newline at end of file From da26055e0cc3009d8ec3042d9c8593a1a305396b Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Sun, 22 Oct 2023 15:49:09 -0400 Subject: [PATCH 17/19] clean the test code and make it cover more code --- tests/test_2d_operations.cpp | 45 +++++++++++------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 3e472e8efc..0952867766 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1358,6 +1358,7 @@ TEST_CASE("split_face", "[operations][split][2D]") settings.split_vertex_tag_value = 3; settings.initialize_invariants(m); wmtk::operations::tri_mesh::FaceSplitWithTag op(m, f, settings); + CHECK(op.name().compare("tri_mesh_split_face_with_tag") == 0); CHECK(op()); CHECK(m.get_all(PF).size() == 12); for (const Tuple& t : m.get_all(PF)) { @@ -1466,19 +1467,20 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") wmtk::MeshAttributeHandle todo_handle = m.register_attribute(std::string("todo_tag"), PE, 1); wmtk::mesh_utils::set_matrix_attribute(V, "position", PrimitiveType::Vertex, m); + settings.edge_tag = edge_handle; + settings.vertex_tag = vertex_handle; + settings.embedding_tag_value = -1; + settings.need_embedding_tag_value = true; + settings.split_with_tag_settings.position = + m.get_attribute_handle(std::string("position"), PV); + settings.split_with_tag_settings.split_settings.split_boundary_edges = true; + settings.split_edge_tag_value = -2; + settings.split_vertex_tag_value = -3; + settings.split_todo = todo_handle; + settings.initialize_invariants(m); + CHECK(settings.are_invariants_initialized()); SECTION("should all fail") { - settings.edge_tag = edge_handle; - settings.vertex_tag = vertex_handle; - settings.embedding_tag_value = -1; - settings.need_embedding_tag_value = true; - settings.split_with_tag_settings.position = - m.get_attribute_handle(std::string("position"), PV); - settings.split_with_tag_settings.split_settings.split_boundary_edges = true; - settings.split_edge_tag_value = -2; - settings.split_vertex_tag_value = -3; - settings.split_todo = todo_handle; - settings.initialize_invariants(m); for (Tuple t : m.get_all(PV)) { wmtk::operations::tri_mesh::EdgeSplitWithTag op(m, t, settings); CHECK(op.name().compare("tri_mesh_edge_split_with_tag") == 0); @@ -1489,17 +1491,6 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") SECTION("check the embedding value and the operations should only success twice -- need " "embedding = true") { - settings.edge_tag = edge_handle; - settings.vertex_tag = vertex_handle; - settings.embedding_tag_value = -1; - settings.need_embedding_tag_value = true; - settings.split_with_tag_settings.position = - m.get_attribute_handle(std::string("position"), PV); - settings.split_with_tag_settings.split_settings.split_boundary_edges = true; - settings.split_edge_tag_value = -2; - settings.split_vertex_tag_value = -3; - settings.split_todo = todo_handle; - settings.initialize_invariants(m); std::vector edges = m.get_all(PE); wmtk::Accessor acc = m.create_accessor(todo_handle); wmtk::Accessor acc_e = m.create_accessor(edge_handle); @@ -1542,17 +1533,7 @@ TEST_CASE("split_edge_operation_with_tag", "[operations][split][2D]") SECTION("check the embedding value and the operations should only success twice -- need " "embedding = false") { - settings.edge_tag = edge_handle; - settings.vertex_tag = vertex_handle; - settings.embedding_tag_value = -1; settings.need_embedding_tag_value = false; - settings.split_with_tag_settings.position = - m.get_attribute_handle(std::string("position"), PV); - settings.split_with_tag_settings.split_settings.split_boundary_edges = true; - settings.split_edge_tag_value = -2; - settings.split_vertex_tag_value = -3; - settings.split_todo = todo_handle; - settings.initialize_invariants(m); std::vector edges = m.get_all(PE); wmtk::Accessor acc = m.create_accessor(todo_handle); wmtk::Accessor acc_e = m.create_accessor(edge_handle); From 154bd1f6580c10acab24be3b7d16ae48467b1194 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Sun, 22 Oct 2023 15:53:33 -0400 Subject: [PATCH 18/19] cancel data writer operation(make statement false) --- tests/test_2d_operations.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 0952867766..3515dbd078 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1290,7 +1290,14 @@ TEST_CASE("split_face", "[operations][split][2D]") if (false) { const std::filesystem::path data_dir = WMTK_DATA_DIR; - ParaviewWriter writer(data_dir / "my_result", "position", m, true, true, true, false); + ParaviewWriter writer( + data_dir / "split_in_diamond_with_attribute_result", + "position", + m, + true, + true, + true, + false); m.serialize(writer); } } From 89b8c9c7ea80af11ebcee2d4b83e48075f288cb8 Mon Sep 17 00:00:00 2001 From: zhouyuan chen <867442167@qq.com> Date: Tue, 24 Oct 2023 11:40:11 -0400 Subject: [PATCH 19/19] remove the variables never used --- tests/test_2d_operations.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/test_2d_operations.cpp b/tests/test_2d_operations.cpp index 3515dbd078..2d6744a96d 100644 --- a/tests/test_2d_operations.cpp +++ b/tests/test_2d_operations.cpp @@ -1279,8 +1279,6 @@ TEST_CASE("split_face", "[operations][split][2D]") CHECK(op1.name().compare("tri_mesh_split_face_at_midpoint") == 0); CHECK(op2.name().compare("tri_mesh_split_face_at_midpoint") == 0); CHECK(op0()); - auto handle = m.get_attribute_handle(std::string("position"), PV); - auto acc = m.create_accessor(handle); CHECK(op1()); CHECK(!op2()); @@ -1352,8 +1350,6 @@ TEST_CASE("split_face", "[operations][split][2D]") MeshAttributeHandle vertex_tag_handle = m.register_attribute("vertex_tag", PV, 1); Accessor acc_todo = m.create_accessor(todo_handle); - Accessor acc_edge_tag = m.create_accessor(edge_tag_handle); - Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); acc_todo.scalar_attribute(f) = 1; OperationSettings settings; settings.edge_tag = edge_tag_handle; @@ -1428,7 +1424,6 @@ TEST_CASE("split_face", "[operations][split][2D]") MeshAttributeHandle vertex_tag_handle = m.register_attribute("vertex_tag", PV, 1); Accessor acc_todo = m.create_accessor(todo_handle); - Accessor acc_edge_tag = m.create_accessor(edge_tag_handle); Accessor acc_vertex_tag = m.create_accessor(vertex_tag_handle); acc_todo.scalar_attribute(f) = 0; acc_vertex_tag.scalar_attribute(m.edge_tuple_between_v1_v2(1, 2, 0)) = 1;