Wildmeshing Toolkit
Loading...
Searching...
No Matches
SimplicialEmbedding.cpp
Go to the documentation of this file.
2
3#include <wmtk/Scheduler.hpp>
12#include <wmtk/utils/Logger.hpp>
14
15#include <deque>
16
18
19namespace {
20
21class TagAttribute
22{
23public:
26 int64_t m_val;
27
28 TagAttribute(
29 Mesh& m,
30 const attribute::MeshAttributeHandle& attribute,
31 PrimitiveType ptype,
32 int64_t val)
33 : m_accessor(m.create_accessor<int64_t>(attribute))
34 , m_ptype(ptype)
35 , m_val(val)
36 {}
37
38 TagAttribute(TagAttribute&) = delete;
39};
40} // namespace
41
42SimplicialEmbedding::SimplicialEmbedding(
43 Mesh& mesh,
44 const std::vector<attribute::MeshAttributeHandle>& label_attributes,
45 const int64_t& value,
46 const std::vector<attribute::MeshAttributeHandle>& pass_through_attributes)
47 : m_mesh(mesh)
48 , m_label_attributes(label_attributes)
49 , m_value(value)
50 , m_pass_through_attributes(pass_through_attributes)
51{}
52
53void SimplicialEmbedding::regularize_tags(bool generate_simplicial_embedding)
54{
55 using namespace operations;
56
57 std::vector<attribute::MeshAttributeHandle> todo_handles;
58 for (size_t i = 0; i < m_label_attributes.size(); ++i) {
60 m_mesh.register_attribute<int64_t>("todo", m_label_attributes[i].primitive_type(), 1);
61 todo_handles.emplace_back(todo_handle);
62 }
63
64 std::deque<TagAttribute> tag_attributes;
65 for (size_t i = 0; i < m_label_attributes.size(); ++i) {
66 tag_attributes.emplace_back(
67 m_mesh,
69 m_label_attributes[i].primitive_type(),
70 m_value);
71 }
72
73 // make sure tag vector is complete and sorted in descending order
74 for (size_t i = 0; i < tag_attributes.size(); ++i) {
75 TagAttribute& a = tag_attributes[i];
76 if (get_primitive_type_id(a.m_ptype) != m_mesh.top_cell_dimension() - i) {
77 log_and_throw_error("Tag array must be sorted in descending order starting with "
78 "the top simplex type up to vertex.");
79 }
80 }
81
82
83 // tag all faces of attributes
84 for (size_t attr_it = 0; attr_it < tag_attributes.size() - 1; ++attr_it) {
85 const TagAttribute& ta = tag_attributes[attr_it];
86 for (const Tuple& t : m_mesh.get_all(ta.m_ptype)) {
87 if (ta.m_accessor.const_scalar_attribute(t) != ta.m_val) {
88 continue; // t is not tagged
89 }
90
91 const PrimitiveType face_ptype =
94 m_mesh,
95 simplex::Simplex(m_mesh, ta.m_ptype, t),
96 face_ptype);
97
98 TagAttribute& face_ta = tag_attributes[attr_it + 1];
99 for (const Tuple& f : faces) {
100 face_ta.m_accessor.scalar_attribute(f) = face_ta.m_val;
101 }
102 }
103 }
104
105 if (!generate_simplicial_embedding) {
106 return;
107 }
108
109 // check for inversions
110 if (m_mesh.has_attribute<double>("vertices", PrimitiveType::Vertex)) {
111 const auto pos_handle =
113 if (pos_handle.dimension() == m_mesh.top_cell_dimension() - 1) {
114 SimplexInversionInvariant<double> inv(pos_handle.mesh(), pos_handle.as<double>());
115
116 if (!inv.after({}, m_mesh.get_all(m_mesh.top_simplex_type()))) {
117 logger().error("Mesh is not inversion free BEFORE simplicial embedding!");
118 }
119 }
120 }
121
122 // split untagged simplices that have only tagged faces
123 for (size_t attr_it = 0; attr_it < tag_attributes.size() - 1;) {
124 const TagAttribute& ta = tag_attributes[attr_it];
125
126 attribute::MeshAttributeHandle& todo_handle = todo_handles[attr_it];
127 auto todo_acc = m_mesh.create_accessor<int64_t>(todo_handle);
128
129 int64_t count_todos = 0;
130 for (const Tuple& t : m_mesh.get_all(ta.m_ptype)) {
131 if (ta.m_accessor.const_scalar_attribute(t) == ta.m_val) {
132 continue; // t is tagged
133 }
134
135 const PrimitiveType face_ptype =
138 m_mesh,
139 simplex::Simplex(m_mesh, ta.m_ptype, t),
140 face_ptype);
141
142 const TagAttribute& face_ta = tag_attributes[attr_it + 1];
143
144 bool all_faces_are_tagged = true;
145
146 for (const Tuple& f : faces) {
147 if (face_ta.m_accessor.const_scalar_attribute(f) != face_ta.m_val) {
148 all_faces_are_tagged = false;
149 break;
150 }
151 }
152
153 if (all_faces_are_tagged) {
154 todo_acc.scalar_attribute(t) = 1;
155 ++count_todos;
156 }
157 }
158
159 // split simplex because all its faces are tagged
160 Scheduler scheduler;
161 int64_t count_done = 0;
162 switch (ta.m_ptype) {
163 case PrimitiveType::Edge: { // edge split
164 EdgeSplit op_split(m_mesh);
165 op_split.add_invariant(std::make_shared<TodoInvariant>(
166 m_mesh,
167 std::get<attribute::TypedAttributeHandle<int64_t>>(todo_handle.handle())));
168
169 // todos
170 for (const attribute::MeshAttributeHandle& h : todo_handles) {
172 h,
173 SplitBasicStrategy::None,
174 SplitRibBasicStrategy::None);
175 }
176 // labels
179 h,
180 SplitBasicStrategy::Copy,
181 SplitRibBasicStrategy::None);
182 }
183 // pass_through
184 for (const auto& attr : m_pass_through_attributes) {
185 op_split.set_new_attribute_strategy(attr);
186 }
187
188 logger().info("split {} edges", count_todos);
189 while (true) {
190 const auto stats = scheduler.run_operation_on_all(op_split);
191 count_done += stats.number_of_successful_operations();
192 if (stats.number_of_successful_operations() == 0) {
193 break;
194 }
195 }
196
197 break;
198 }
199 case PrimitiveType::Triangle: { // face split
200 composite::TriFaceSplit op_face_split(m_mesh);
201 op_face_split.add_invariant(std::make_shared<TodoInvariant>(
202 m_mesh,
203 std::get<attribute::TypedAttributeHandle<int64_t>>(todo_handle.handle())));
204
205 // todos
206 for (const attribute::MeshAttributeHandle& h : todo_handles) {
207 op_face_split.split().set_new_attribute_strategy(
208 h,
209 SplitBasicStrategy::None,
210 SplitRibBasicStrategy::None);
211 op_face_split.collapse().set_new_attribute_strategy(h, CollapseBasicStrategy::None);
212 }
213 // labels
215 op_face_split.split().set_new_attribute_strategy(
216 h,
217 SplitBasicStrategy::Copy,
218 SplitRibBasicStrategy::None);
219 op_face_split.collapse().set_new_attribute_strategy(h, CollapseBasicStrategy::None);
220 }
221 // pass_through
222 for (const auto& attr : m_pass_through_attributes) {
223 op_face_split.split().set_new_attribute_strategy(attr);
224 op_face_split.collapse().set_new_attribute_strategy(
225 attr,
226 CollapseBasicStrategy::None);
227 }
228
229
230 logger().info("split {} faces", count_todos);
231 while (true) {
232 const auto stats = scheduler.run_operation_on_all(op_face_split);
233 count_done += stats.number_of_successful_operations();
234 if (stats.number_of_successful_operations() == 0) {
235 break;
236 }
237 }
238
239 break;
240 }
241 case PrimitiveType::Tetrahedron: { // tet split
242 composite::TetCellSplit op_tet_split(m_mesh);
243 op_tet_split.add_invariant(std::make_shared<TodoInvariant>(
244 m_mesh,
245 std::get<attribute::TypedAttributeHandle<int64_t>>(todo_handle.handle())));
246
247 // todos
248 for (const attribute::MeshAttributeHandle& h : todo_handles) {
249 op_tet_split.split().set_new_attribute_strategy(
250 h,
251 SplitBasicStrategy::None,
252 SplitRibBasicStrategy::None);
253 op_tet_split.collapse().set_new_attribute_strategy(h, CollapseBasicStrategy::None);
254 }
255 // labels
257 op_tet_split.split().set_new_attribute_strategy(
258 h,
259 SplitBasicStrategy::Copy,
260 SplitRibBasicStrategy::None);
261 op_tet_split.collapse().set_new_attribute_strategy(h, CollapseBasicStrategy::None);
262 }
263 // pass_through
264 for (const auto& attr : m_pass_through_attributes) {
265 op_tet_split.split().set_new_attribute_strategy(attr);
267 attr,
268 CollapseBasicStrategy::None);
269 }
270
271 logger().info("split {} tetrahedra", count_todos);
272 while (true) {
273 const auto stats = scheduler.run_operation_on_all(op_tet_split);
274 count_done += stats.number_of_successful_operations();
275 if (stats.number_of_successful_operations() == 0) {
276 break;
277 }
278 }
279
280 break;
281 }
282 default: log_and_throw_error("unknown primitive type"); break;
283 }
284
285 if (count_done == count_todos) {
286 ++attr_it;
287 } else {
288 logger().info(
289 "{} remain. Regularize same primitive type once more.",
290 count_todos - count_done);
291 }
292 }
293
294 // check for inversions
295 if (m_mesh.has_attribute<double>("vertices", PrimitiveType::Vertex)) {
296 const auto pos_handle =
298 SimplexInversionInvariant<double> inv(pos_handle.mesh(), pos_handle.as<double>());
299
300 if (pos_handle.dimension() == m_mesh.top_cell_dimension() - 1) {
301 SimplexInversionInvariant<double> inv(pos_handle.mesh(), pos_handle.as<double>());
302
303 if (!inv.after({}, m_mesh.get_all(m_mesh.top_simplex_type()))) {
304 logger().error("Mesh is not inversion free after simplicial embedding!");
305 }
306 }
307 }
308}
309
310
311} // namespace wmtk::components::internal
attribute::MeshAttributeHandle register_attribute(const std::string &name, PrimitiveType type, int64_t size, bool replace=false, T default_value=T(0))
attribute::MeshAttributeHandle get_attribute_handle(const std::string &name, const PrimitiveType ptype) const
Definition Mesh.hpp:903
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
std::vector< Tuple > get_all(PrimitiveType type) const
Generate a vector of Tuples from global vertex/edge/triangle/tetrahedron index.
Definition Mesh.cpp:18
bool has_attribute(const std::string &name, const PrimitiveType ptype) const
Definition Mesh.hpp:923
int64_t top_cell_dimension() const
Definition Mesh.hpp:978
PrimitiveType top_simplex_type() const
Definition Mesh.hpp:982
SchedulerStats run_operation_on_all(operations::Operation &op)
Definition Scheduler.cpp:33
int64_t number_of_successful_operations() const
Returns the number of successful operations performed by the scheduler.
Definition Scheduler.hpp:16
bool after(const std::vector< Tuple > &, const std::vector< Tuple > &top_dimension_tuples_after) const override
we assume with local vid order (v0,v1,v2,v3) has positive volume (orient3d(v0,v1,v2,...
The Tuple is the basic navigation tool in our mesh data structure.
Definition Tuple.hpp:19
A CachingAccessor that uses tuples for accessing attributes instead of indices.
Definition Accessor.hpp:28
Handle that represents attributes for some mesh.
std::vector< attribute::MeshAttributeHandle > m_pass_through_attributes
std::vector< attribute::MeshAttributeHandle > m_label_attributes
wmtk::attribute::Accessor< int64_t > m_accessor
TagAttribute(Mesh &m, const attribute::MeshAttributeHandle &attribute, PrimitiveType ptype, int64_t val)
void set_new_attribute_strategy(const attribute::MeshAttributeHandle &attribute, const std::shared_ptr< const operations::BaseCollapseNewAttributeStrategy > &other)
void set_new_attribute_strategy(const attribute::MeshAttributeHandle &attribute, const std::shared_ptr< const operations::BaseSplitNewAttributeStrategy > &other)
Definition EdgeSplit.cpp:85
void add_invariant(std::shared_ptr< Invariant > invariant)
Definition Operation.hpp:48
The return tuple is the new vertex, pointing to the original vertex.
std::vector< Tuple > faces_single_dimension_tuples(const Mesh &mesh, const Simplex &simplex, const PrimitiveType face_type)
SimplexCollection faces(const Mesh &mesh, const Simplex &simplex, const bool sort_and_clean)
Returns all faces of a simplex.
Definition faces.cpp:10
constexpr PrimitiveType get_primitive_type_from_id(int8_t id)
Get the primitive type corresponding to its unique integer id.
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:101
constexpr int8_t get_primitive_type_id(PrimitiveType t)
Get a unique integer id corresponding to each primitive type.
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:58