Wildmeshing Toolkit
SplitNewAttributeStrategy.cpp
Go to the documentation of this file.
2 #include <wmtk/utils/Logger.hpp>
4 
8 
9 
10 namespace wmtk::operations {
11 
12 template <typename T>
14 {
15  return m_will_throw || m_will_throw_rib;
16 }
17 template <typename T>
19 {
20  return fmt::format("SplitNewAttributeStrategy[{}]", m_handle.name());
21 }
22 
23 template <typename T>
25  T>::standard_split_strategy(SplitBasicStrategy optype, const std::string_view& name)
26 {
28 
29  switch (optype) {
30  default: [[fallthrough]];
31  case SplitBasicStrategy::Default: [[fallthrough]];
33  return [](const VT& a, const std::bitset<2>&) -> std::array<VT, 2> {
34  return std::array<VT, 2>{{a, a}};
35  };
37  return [](const VT& a, const std::bitset<2>&) -> std::array<VT, 2> {
38  return std::array<VT, 2>{{a / T(2), a / T(2)}};
39  };
41  std::string mn(name);
42  return [mn](const VT&, const std::bitset<2>&) -> std::array<VT, 2> {
43  log_and_throw_error("Split should have a new attribute for [{}]", mn);
44  };
45  }
46  case SplitBasicStrategy::None: return {};
47  }
48  return {};
49 }
50 
51 template <>
53  Rational>::standard_split_strategy(SplitBasicStrategy optype, const std::string_view& name)
54 {
56 
57  switch (optype) {
58  default: [[fallthrough]];
59  case SplitBasicStrategy::Default: [[fallthrough]];
61  return [](const VT& a, const std::bitset<2>&) -> std::array<VT, 2> {
62  return std::array<VT, 2>{{a, a}};
63  };
65  return [](const VT& a, const std::bitset<2>&) -> std::array<VT, 2> {
66  return std::array<VT, 2>{{a / Rational(2, true), a / Rational(2, true)}};
67  };
69  std::string mn(name);
70  return [mn](const VT&, const std::bitset<2>&) -> std::array<VT, 2> {
71  log_and_throw_error("Split should have a new attribute for [{}]", mn);
72  };
73  }
74  case SplitBasicStrategy::None: return {};
75  }
76  return {};
77 }
78 
79 
80 template <typename T>
82  T>::standard_split_rib_strategy(SplitRibBasicStrategy optype, const std::string_view& name)
83 {
85 
86  switch (optype) {
87  default: [[fallthrough]];
89  if constexpr (std::is_same_v<T, double> || std::is_same_v<T, Rational>) {
91  } else {
92  return standard_split_rib_strategy(SplitRibBasicStrategy::CopyTuple);
93  }
95  return [](const VT& a, const VT& b, const std::bitset<2>& bs) -> VT {
96  // if both are boundary then return a (failed link anyway but oh well)
97  // if a is boundary but b is interior get b though
98  if (!bs[1] && bs[0]) {
99  return b;
100  } else {
101  return a;
102  }
103  };
105  return [](const VT& a, const VT& b, const std::bitset<2>& bs) -> VT {
106  if (!bs[0] && bs[1]) {
107  return a;
108  } else {
109  return b;
110  }
111  };
113  return [](const VT& a, const VT& b, const std::bitset<2>& bs) -> VT {
114  if (bs[0] == bs[1]) {
115  return (a + b) / T(2);
116  } else if (bs[0]) {
117  return a;
118 
119  } else {
120  return b;
121  }
122  };
124  std::string mn(name);
125  return [mn](const VT&, const VT&, const std::bitset<2>&) -> VT {
126  log_and_throw_error("Split should have a new attribute [{}]", mn);
127  };
128  }
129  case SplitRibBasicStrategy::None: return {};
130  }
131  return {};
132 }
133 template <>
136  SplitRibBasicStrategy optype,
137  const std::string_view& name)
138 {
140 
141  switch (optype) {
142  default: [[fallthrough]];
144  return standard_split_rib_strategy(SplitRibBasicStrategy::Mean);
146  return [](const VT& a, const VT& b, const std::bitset<2>& bs) -> VT {
147  // if both are boundary then return a (failed link anyway but oh well)
148  // if a is boundary but b is interior get b though
149  if (!bs[1] && bs[0]) {
150  return b;
151  } else {
152  return a;
153  }
154  };
156  return [](const VT& a, const VT& b, const std::bitset<2>& bs) -> VT {
157  if (!bs[0] && bs[1]) {
158  return a;
159  } else {
160  return b;
161  }
162  };
164  return [](const VT& a, const VT& b, const std::bitset<2>& bs) -> VT {
165  if (bs[0] == bs[1]) {
166  return (a + b) / Rational(2, true);
167  } else if (bs[0]) {
168  return a;
169 
170  } else {
171  return b;
172  }
173  };
175  std::string mn(name);
176  return [mn](const VT&, const VT&, const std::bitset<2>&) -> VT {
177  log_and_throw_error("Split should have a new attribute [{}]", mn);
178  };
179  }
180  case SplitRibBasicStrategy::None: return {};
181  }
182  return {};
183 }
184 
185 
186 template <typename T>
189  : m_handle(h)
190  , m_split_rib_op(nullptr)
191  , m_split_op(nullptr)
192 {
193  assert(h.holds<T>());
196 
197  auto& mesh = m_handle.mesh();
198  assert(
200  PrimitiveType::Vertex); // attribute new is not valid on free meshes
201 
203  m_topo_info =
204  std::make_unique<edge_mesh::SplitNewAttributeTopoInfo>(static_cast<EdgeMesh&>(mesh));
206  m_topo_info =
207  std::make_unique<tri_mesh::SplitNewAttributeTopoInfo>(static_cast<TriMesh&>(mesh));
209  m_topo_info =
210  std::make_unique<tet_mesh::SplitNewAttributeTopoInfo>(static_cast<TetMesh&>(mesh));
211  } else {
212  log_and_throw_error("Invalid mesh");
213  }
214 }
215 
216 template <typename T>
218  Mesh& m,
219  const ReturnData& data,
220  const OperationInOutData& op_datas) const
221 {
222  if (!bool(m_split_rib_op) && !bool(m_split_op)) {
223  return;
224  }
225 
226  if (op_datas.find(&mesh()) == op_datas.end()) return;
227  assert(&m == &mesh());
228  const std::vector<std::tuple<simplex::NavigatableSimplex, Tuple>>& tuple_pairs =
229  op_datas.at(&mesh());
230 
231  const PrimitiveType pt = primitive_type();
232  auto acc = m.create_accessor(m_handle.as<T>());
233  for (const auto& tuple_pair : tuple_pairs) {
234  const simplex::NavigatableSimplex& input_simplex = std::get<0>(tuple_pair);
235  const Tuple& output_tuple = std::get<1>(tuple_pair);
236 
237 
238  const auto& return_data_variant = data.get_variant(mesh(), input_simplex);
239 
240  // for (const PrimitiveType pt : wmtk::utils::primitive_below(mesh().top_simplex_type()))
241  {
242  // copy attributes opposing ears
243  auto old_simps =
244  m_topo_info->input_ear_simplices(return_data_variant, input_simplex.tuple(), pt);
245  auto new_simps =
246  m_topo_info->output_rib_simplices(return_data_variant, output_tuple, pt);
247 
248 
249  assert(old_simps.size() == new_simps.size());
250 
251  for (size_t s = 0; s < old_simps.size(); ++s) {
252  assign_split_ribs(acc, old_simps[s], new_simps[s]);
253  }
254  }
255  {
256  auto old_simps =
257  m_topo_info->input_split_simplices(return_data_variant, input_simplex.tuple(), pt);
258  auto new_simps =
259  m_topo_info->output_split_simplices(return_data_variant, output_tuple, pt);
260 
261 
262  assert(old_simps.size() == new_simps.size());
263 
264  for (size_t s = 0; s < old_simps.size(); ++s) {
265  assign_split(acc, old_simps[s], new_simps[s]);
266  }
267  }
268  if (mesh().is_free()) {
269  assert(m_handle.primitive_type() == PrimitiveType::Vertex);
270 
271  auto pairs = m_topo_info->output_duplicated_free_simplices(return_data_variant, pt);
272  for (const auto& [first, second] : pairs) {
273  acc.index_access().vector_attribute(second) =
274  acc.index_access().const_vector_attribute(first);
275  }
276  }
277  }
278 }
279 
280 
281 template <typename T>
284  const std::array<Tuple, 2>& input_ears,
285  const Tuple& final_simplex) const
286 {
287  if (!bool(m_split_rib_op)) {
288  return;
289  }
290  assert(acc.primitive_type() == primitive_type());
291 
292  auto old_values = m_handle.mesh().parent_scope([&]() {
293  return std::make_tuple(
294  acc.const_vector_attribute(input_ears[0]),
295  acc.const_vector_attribute(input_ears[1]));
296  });
297 
298  VecType a, b;
299  std::tie(a, b) = old_values;
300  auto new_value = acc.vector_attribute(final_simplex);
301 
302  const auto old_pred = this->evaluate_predicate(acc.primitive_type(), input_ears);
303 
304  new_value = m_split_rib_op(a, b, old_pred);
305 }
306 
307 template <typename T>
310  const Tuple& input_simplex,
311  const std::array<Tuple, 2>& split_simplices) const
312 {
313  if (!bool(m_split_op)) {
314  return;
315  }
316  assert(acc.primitive_type() == primitive_type());
317  const VecType old_value =
318  m_handle.mesh().parent_scope([&]() { return acc.const_vector_attribute(input_simplex); });
319 
320  std::bitset<2> pred = this->evaluate_predicate(acc.primitive_type(), split_simplices);
321 
322  auto arr = m_split_op(old_value, pred);
323  for (size_t j = 0; j < 2; ++j) {
324  acc.vector_attribute(split_simplices[j]) = arr[j];
325  }
326 }
327 
328 
329 template <typename T>
331 {
332  set_rib_strategy(standard_split_rib_strategy(t, m_handle.name()));
333  m_will_throw_rib = t == SplitRibBasicStrategy::Throw;
334 }
335 template <typename T>
337 {
338  set_strategy(standard_split_strategy(t, m_handle.name()));
339  m_will_throw = t == SplitBasicStrategy::Throw;
340 }
341 
342 template <typename T>
344 {
345  m_split_rib_op = std::move(f);
346  m_will_throw_rib = false;
347 }
348 template <typename T>
350 {
351  m_split_op = std::move(f);
352  m_will_throw = false;
353 }
354 
355 template <typename T>
357 {
358  return m_handle.mesh();
359 }
360 
361 template <typename T>
363 {
364  return m_handle.primitive_type();
365 }
366 
367 template <typename T>
369 {
370  m_handle = wmtk::attribute::MeshAttributeHandle(m, m_handle.handle());
371 }
372 
373 template <typename T>
375  const attribute::MeshAttributeHandle& handle) const
376 {
377  return handle == m_handle;
378 }
379 
380 
381 template class SplitNewAttributeStrategy<char>;
383 template class SplitNewAttributeStrategy<double>;
385 
386 } // namespace wmtk::operations
bool is_free() const
Definition: Mesh.hpp:987
attribute::Accessor< T, Mesh, D > create_accessor(const attribute::MeshAttributeHandle &handle)
PrimitiveType top_simplex_type() const
Definition: Mesh.hpp:996
A CachingAccessor that uses tuples for accessing attributes instead of indices.
Definition: Accessor.hpp:25
MapResult< D > vector_attribute(const ArgType &t)
PrimitiveType primitive_type() const
ConstMapResult< D > const_vector_attribute(const ArgType &t) const
wmtk::multimesh::operations::SplitReturnData ReturnData
wmtk::multimesh::operations::OperationInOutData OperationInOutData
wmtk::attribute::MeshAttributeHandle m_handle
void update(Mesh &m, const ReturnData &ret_data, const OperationInOutData &op_data) const final override
std::function< VecType(const VecType &, const VecType &, const std::bitset< 2 > &)> SplitRibFuncType
std::unique_ptr< SplitNewAttributeTopoInfo > m_topo_info
void assign_split_ribs(wmtk::attribute::Accessor< T > &accessor, const std::array< Tuple, 2 > &input_ears, const Tuple &final_simplex) const
SplitNewAttributeStrategy(const wmtk::attribute::MeshAttributeHandle &h)
void assign_split(wmtk::attribute::Accessor< T > &accessor, const Tuple &input_simplex, const std::array< Tuple, 2 > &split_simplices) const
bool matches_attribute(const attribute::MeshAttributeHandle &) const override
static SplitRibFuncType standard_split_rib_strategy(SplitRibBasicStrategy optype, const std::string_view &={})
std::function< std::array< VecType, 2 >(const VecType &, const std::bitset< 2 > &)> SplitFuncType
void log_and_throw_error(const std::string &msg)
Definition: Logger.cpp:101