Wildmeshing Toolkit
SimplicialEmbedding.cpp
Go to the documentation of this file.
2 
3 #include <wmtk/Scheduler.hpp>
10 #include <wmtk/simplex/faces.hpp>
12 #include <wmtk/utils/Logger.hpp>
14 
15 #include <deque>
16 
18 
19 namespace {
20 
21 class TagAttribute
22 {
23 public:
26  int64_t m_val;
27 
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 
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 
53 void 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) {
59  attribute::MeshAttributeHandle todo_handle =
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);
266  op_tet_split.collapse().set_new_attribute_strategy(
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:918
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:938
int64_t top_cell_dimension() const
Definition: Mesh.hpp:993
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
PrimitiveType top_simplex_type() const
Definition: Mesh.hpp:997
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,...
T & scalar_attribute(const ArgType &t)
SimplicialEmbedding(Mesh &mesh, const std::vector< attribute::MeshAttributeHandle > &label_attributes, const int64_t &value, const std::vector< attribute::MeshAttributeHandle > &pass_through_attributes)
std::vector< attribute::MeshAttributeHandle > m_pass_through_attributes
void regularize_tags(bool generate_simplicial_embedding=true)
Regularize tags in mesh.
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