Wildmeshing Toolkit
TetMeshOperationExecutor.cpp
Go to the documentation of this file.
5 #include <wmtk/simplex/faces.hpp>
12 #include <wmtk/utils/Logger.hpp>
14 
15 namespace wmtk {
16 namespace {
17 constexpr static PrimitiveType PE = PrimitiveType::Edge;
18 constexpr static PrimitiveType PF = PrimitiveType::Triangle;
19 } // namespace
20 
21 std::tuple<std::vector<Tuple>, std::vector<Tuple>>
23 {
24  std::vector<Tuple> incident_tets, incident_faces;
25 
26  incident_tets.emplace_back(t);
27  incident_faces.emplace_back(t);
28 
29  // direction
30  /*
31  /\\ /\\
32  /ot\\ --> / \\ --> ...
33  /____\\ /____\\
34  */
35  // incident face size = incident tet size if loop
36  Tuple iter_tuple = t;
37 
38  bool loop_flag = false;
39 
40  while (!m_mesh.is_boundary_face(iter_tuple)) {
41  iter_tuple = m_mesh.switch_tetrahedron(iter_tuple);
42 
43  // if no boundary, break;
44  if (m_mesh.id_tet(iter_tuple) == m_mesh.id_tet(t)) {
45  loop_flag = true;
46  break;
47  }
48 
49  // switch to another face
50  iter_tuple = m_mesh.switch_face(iter_tuple);
51  incident_tets.emplace_back(iter_tuple);
52  incident_faces.emplace_back(iter_tuple);
53  }
54 
55  if (!loop_flag) {
56  // has boundary case
57  // go to an one boundary and start there
58  // direction
59  /*
60  /\\ /\\
61  / \\ --> /ot\\ --> ...
62  /____\\ /____\\
63  */
64  // incident face size = incident tet size + 1 if boundary
65 
66  incident_tets.clear();
67  incident_faces.clear();
68 
69  // go to the left boundary
70  iter_tuple = m_mesh.switch_face(t);
71  while (!m_mesh.is_boundary_face(iter_tuple)) {
72  iter_tuple = m_mesh.switch_face(m_mesh.switch_tetrahedron(iter_tuple));
73  }
74 
75  const Tuple last_face_tuple = iter_tuple;
76  iter_tuple = m_mesh.switch_face(iter_tuple);
77 
78  incident_tets.emplace_back(iter_tuple);
79  incident_faces.emplace_back(iter_tuple);
80 
81  while (!m_mesh.is_boundary_face(iter_tuple)) {
82  iter_tuple = m_mesh.switch_face(m_mesh.switch_tetrahedron(iter_tuple));
83  incident_tets.emplace_back(iter_tuple);
84  incident_faces.emplace_back(iter_tuple);
85  }
86 
87  incident_faces.emplace_back(last_face_tuple);
88  }
89 
90  return {incident_tets, incident_faces};
91 }
92 
93 
94 // constructor
96  TetMesh& m,
97  const Tuple& operating_tuple)
99  , tt_accessor(*m.m_tt_accessor)
100  , tf_accessor(*m.m_tf_accessor)
101  , te_accessor(*m.m_te_accessor)
102  , tv_accessor(*m.m_tv_accessor)
103  , vt_accessor(*m.m_vt_accessor)
104  , et_accessor(*m.m_et_accessor)
105  , ft_accessor(*m.m_ft_accessor)
106  , m_mesh(m)
107 {
108  m_operating_tuple = operating_tuple;
109  // store ids of edge and incident vertices
110  m_operating_edge_id = m_mesh.id_edge(m_operating_tuple);
111  m_spine_vids[0] = m_mesh.id_vertex(m_operating_tuple);
112  m_spine_vids[1] = m_mesh.id_vertex(m_mesh.switch_vertex(m_operating_tuple));
113  m_operating_face_id = m_mesh.id_face(m_operating_tuple);
114  m_operating_tet_id = m_mesh.id_tet(m_operating_tuple);
115 
116  if (m_mesh.has_child_mesh()) {
117  // get the closed star of the edge
118  simplex::SimplexCollection edge_closed_star_vertices(m_mesh);
119  const simplex::Simplex edge_operating(m_mesh, PrimitiveType::Edge, operating_tuple);
121  m_mesh,
122  edge_operating,
124  edge_closed_star_vertices.add(PrimitiveType::Vertex, t);
125  }
127  edge_closed_star_vertices,
128  edge_operating,
130 
131 
132  assert(
133  edge_closed_star_vertices.simplex_vector().size() ==
134  edge_closed_star_vertices.simplex_vector(PrimitiveType::Vertex).size());
135 
136  // update hash on all tets in the two-ring neighborhood
137  simplex::IdSimplexCollection hash_update_region(m);
138  for (const simplex::Simplex& v : edge_closed_star_vertices.simplex_vector()) {
139  // simplex::top_dimension_cofaces(v, hash_update_region, false);
140  for (const Tuple& t : simplex::top_dimension_cofaces_iterable(m_mesh, v)) {
141  hash_update_region.add(PrimitiveType::Tetrahedron, t);
142  }
143  }
144  hash_update_region.sort_and_clean();
145 
146  global_ids_to_potential_tuples.resize(4);
147  simplex::IdSimplexCollection faces(m_mesh);
148  faces.reserve(hash_update_region.simplex_vector().size() * 15);
149 
150  for (const simplex::IdSimplex& t : hash_update_region.simplex_vector()) {
151  faces.add(t);
152  const simplex::Simplex s = m.get_simplex(t);
153  // faces.add(wmtk::simplex::faces(m, s, false));
154  for (const simplex::Simplex& f : simplex::faces(m, s, false)) {
155  faces.add(m.get_id_simplex(f));
156  }
157  }
158 
159  // hack (I guess, because the hack below only makes sense with the next line)
160  // faces.add(simplex::Simplex(PrimitiveType::Tetrahedron, operating_tuple));
161 
163 
164  for (const simplex::IdSimplex& s : faces) {
165  // hack
166  // if (s.primitive_type() == PrimitiveType::Tetrahedron) continue;
167 
168  const int64_t index = static_cast<int64_t>(s.primitive_type());
169  if (!m.has_child_mesh_in_dimension(index)) {
170  continue;
171  }
172  global_ids_to_potential_tuples.at(index).emplace_back(
173  m_mesh.id(s),
174  wmtk::simplex::top_dimension_cofaces_tuples(m_mesh, m_mesh.get_simplex(s)));
175  }
176 
177  global_ids_to_potential_tuples.at(3).emplace_back(
178  m_mesh.id(simplex::Simplex(m, PrimitiveType::Tetrahedron, operating_tuple)),
180  m_mesh,
181  simplex::Simplex(m, PrimitiveType::Tetrahedron, operating_tuple)));
182  }
183 }
184 
186 {
187  for (size_t d = 0; d < simplex_ids_to_delete.size(); ++d) {
188  for (const int64_t id : simplex_ids_to_delete[d]) {
189  flag_accessors[d].index_access().scalar_attribute(id) = 0; // TODO: reset single bit
190  }
191  }
192 }
193 
195 
196 const std::array<std::vector<int64_t>, 4>
198  const Tuple& tuple,
199  const TetMesh& m)
200 {
202  std::array<std::vector<int64_t>, 4> ids;
203  for (const simplex::Simplex& s : sc) {
204  ids[get_primitive_type_id(s.primitive_type())].emplace_back(m.id(s));
205  }
206 
207  return ids;
208 }
209 
210 const std::array<std::vector<int64_t>, 4>
212  const Tuple& tuple,
213  const TetMesh& m)
214 {
215  std::array<std::vector<int64_t>, 4> ids;
216  for (const simplex::IdSimplex& s : simplex::half_closed_star_iterable(m, tuple)) {
217  ids[get_primitive_type_id(s.primitive_type())].emplace_back(m.id(s));
218  }
219  return ids;
220 }
221 
223  const int64_t ear_tid,
224  const int64_t new_tid,
225  const int64_t old_tid,
226  const int64_t common_fid)
227 {
228  if (ear_tid < 0) return;
229 
230  auto ear_tt = tt_accessor.index_access().vector_attribute(ear_tid);
231  auto ear_tf = tf_accessor.index_access().vector_attribute(ear_tid);
232  for (int i = 0; i < 4; ++i) {
233  if (ear_tt(i) == old_tid) {
234  ear_tt(i) = new_tid;
235  ear_tf(i) = common_fid; // redundant for split
236  break;
237  }
238  }
239 
240  ft_accessor.index_access().scalar_attribute(common_fid) = ear_tid;
241 }
242 
244 {
245  set_split();
246  simplex_ids_to_delete = get_split_simplices_to_delete(m_operating_tuple, m_mesh);
247 
248 
249  // create new vertex (center)
250  std::vector<int64_t> new_vids = this->request_simplex_indices(PrimitiveType::Vertex, 1);
251  assert(new_vids.size() == 1);
252  const int64_t v_new = new_vids[0];
253  m_split_new_vid = v_new;
254 
255  // create new edges (spine)
256  std::vector<int64_t> new_eids = this->request_simplex_indices(PrimitiveType::Edge, 2);
257  assert(new_eids.size() == 2);
258  std::copy(new_eids.begin(), new_eids.end(), m_split_new_spine_eids.begin());
259 
260  // get incident tets and faces(two cases: loop and boundary)
261  // auto incident_tets_and_faces = get_incident_tets_and_faces(m_operating_tuple);
262  // const auto& incident_tets = incident_tets_and_faces[0];
263  // const auto& incident_faces = incident_tets_and_faces[1];
264 
265  const auto [incident_tets, incident_faces] = get_incident_tets_and_faces(m_operating_tuple);
266  const bool loop_flag = (incident_tets.size() == incident_faces.size());
267 
268  const size_t facet_size = incident_tets.size();
269  std::vector<int64_t> new_facet_ids =
271  assert(new_facet_ids.size() == 2 * facet_size);
272  const size_t face_size = incident_faces.size();
273  std::vector<int64_t> new_face_ids =
274  this->request_simplex_indices(PrimitiveType::Triangle, 2 * face_size);
275  assert(new_face_ids.size() == 2 * face_size);
276 
277  // create new faces and edges
278  std::vector<FaceSplitData> new_incident_face_data;
279  for (int64_t i = 0; i < incident_faces.size(); ++i) {
280  std::vector<int64_t> splitting_eids = this->request_simplex_indices(PrimitiveType::Edge, 1);
281 
282  FaceSplitData fsd;
283  fsd.fid_old = m_mesh.id_face(incident_faces[i]);
284  std::copy(
285  new_face_ids.begin() + 2 * i,
286  new_face_ids.begin() + 2 * (i + 1),
287  fsd.fid_new.begin());
288  fsd.eid_spine_old = m_operating_edge_id;
289  fsd.eid_spine_new[0] = new_eids[0]; // redundant
290  fsd.eid_spine_new[1] = new_eids[1]; // redundant
291  fsd.eid_rib = splitting_eids[0]; // redundant
292  fsd.local_operating_tuple = incident_faces[i];
293  new_incident_face_data.emplace_back(fsd);
294  }
295 
296 
297  int64_t incident_face_cnt = new_incident_face_data.size();
298 
299  // create new tets
300  m_incident_tet_datas.clear();
301  for (int64_t i = 0; i < incident_tets.size(); ++i) {
302  std::vector<int64_t> split_fids = this->request_simplex_indices(PrimitiveType::Triangle, 1);
303 
304  IncidentTetData tsd;
305  tsd.local_operating_tuple = incident_tets[i];
306  tsd.tid = m_mesh.id_tet(incident_tets[i]);
307  std::copy(
308  new_facet_ids.begin() + 2 * i,
309  new_facet_ids.begin() + 2 * (i + 1),
310  tsd.split_t.begin());
311  tsd.rib_f = split_fids[0];
312  tsd.new_face_id = split_fids[0];
313 
314  split_facet_data().add_facet(m_mesh, m_operating_tuple, tsd.split_t);
315 
316  // get ears here
317  Tuple ear1 = m_mesh.switch_face(m_mesh.switch_edge(incident_tets[i]));
318  if (!m_mesh.is_boundary_face(ear1)) {
319  ear1 = m_mesh.switch_tuple(ear1, PrimitiveType::Tetrahedron);
320  tsd.ears[0] = EarTet{m_mesh.id_tet(ear1), m_mesh.id_face(ear1)};
321  } else {
322  tsd.ears[0] = EarTet{-1, m_mesh.id_face(ear1)};
323  }
324 
325  Tuple ear2 = m_mesh.switch_face(m_mesh.switch_edge(m_mesh.switch_vertex(incident_tets[i])));
326  if (!m_mesh.is_boundary_face(ear2)) {
327  ear2 = m_mesh.switch_tuple(ear2, PrimitiveType::Tetrahedron);
328  tsd.ears[1] = EarTet{m_mesh.id_tet(ear2), m_mesh.id_face(ear2)};
329  } else {
330  tsd.ears[1] = EarTet{-1, m_mesh.id_face(ear2)};
331  }
332 
333  tsd.new_face_data[0] =
334  new_incident_face_data[(i + incident_face_cnt - 1) % incident_face_cnt];
335  tsd.new_face_data[1] = new_incident_face_data[i];
336 
337  // for multimesh update
338  // get the corresponding face data index
339  // TODO: add this also to collapse, maybe?
340  tsd.incident_face_data_idx[0] = (i + incident_face_cnt - 1) % incident_face_cnt;
341  tsd.incident_face_data_idx[1] = i;
342 
343  tsd.v0 = m_mesh.id_vertex(incident_tets[i]); // redundant
344  tsd.v1 = m_mesh.id_vertex(m_mesh.switch_vertex(incident_tets[i])); // redundant
345  tsd.v2 = m_mesh.id_vertex(m_mesh.switch_vertex(
346  m_mesh.switch_edge(m_mesh.switch_face(incident_tets[i])))); // put in face
347  tsd.v3 = m_mesh.id_vertex(
348  m_mesh.switch_vertex(m_mesh.switch_edge(incident_tets[i]))); // put in face rename
349 
350  tsd.e01 = m_mesh.id_edge(incident_tets[i]); // redundant
351  tsd.e03 = m_mesh.id_edge(m_mesh.switch_edge(incident_tets[i])); // face 1 ear 1 edge
352  tsd.e13 = m_mesh.id_edge(
353  m_mesh.switch_edge(m_mesh.switch_vertex(incident_tets[i]))); // face 2 ear 2 edge
354  tsd.e02 = m_mesh.id_edge(
355  m_mesh.switch_edge(m_mesh.switch_face(incident_tets[i]))); // face 1 ear 1 edge
356  tsd.e12 = m_mesh.id_edge(m_mesh.switch_edge(
357  m_mesh.switch_face(m_mesh.switch_vertex(incident_tets[i])))); // face 2 ear 1 edge
358  tsd.e23 = m_mesh.id_edge(m_mesh.switch_edge(m_mesh.switch_vertex(
359  m_mesh.switch_face(m_mesh.switch_edge(incident_tets[i]))))); // opposite edge
360 
361  m_incident_tet_datas.emplace_back(tsd);
362  }
363 
364  // incident face data for multimesh and attribute update
365  m_incident_face_datas.clear();
366  for (int64_t i = 0; i < m_incident_tet_datas.size(); ++i) {
367  auto& data = m_incident_face_datas.emplace_back();
368  data.fid = m_incident_tet_datas[i].new_face_data[1].fid_old;
369  data.ear_eids[0] = m_incident_tet_datas[i].e03;
370  data.ear_eids[1] = m_incident_tet_datas[i].e13;
371  data.new_edge_id = m_incident_tet_datas[i].new_face_data[1].eid_rib;
372  data.split_f[0] = m_incident_tet_datas[i].new_face_data[1].fid_new[0];
373  data.split_f[1] = m_incident_tet_datas[i].new_face_data[1].fid_new[1];
374  data.local_operating_tuple = m_incident_tet_datas[i].new_face_data[1].local_operating_tuple;
375  }
376 
377  if (!loop_flag) {
378  auto& data = m_incident_face_datas.emplace_back();
379  data.fid = m_incident_tet_datas[0].new_face_data[0].fid_old;
380  data.ear_eids[0] = m_incident_tet_datas[0].e02;
381  data.ear_eids[1] = m_incident_tet_datas[0].e12;
382  data.new_edge_id = m_incident_tet_datas[0].new_face_data[0].eid_rib;
383  data.split_f[0] = m_incident_tet_datas[0].new_face_data[0].fid_new[0];
384  data.split_f[1] = m_incident_tet_datas[0].new_face_data[0].fid_new[1];
385  data.local_operating_tuple = m_incident_tet_datas[0].new_face_data[0].local_operating_tuple;
386  }
387 
388  assert(m_incident_face_datas.size() == new_incident_face_data.size());
389 
390 // debug code
391 #ifndef NDEBUG
392  for (int64_t i = 0; i < m_incident_face_datas.size(); ++i) {
393  assert(m_incident_face_datas[i].fid == new_incident_face_data[i].fid_old);
394  }
395 #endif
396 
397 
398  // local ids for return tuple
399  int64_t return_local_vid = -1;
400  int64_t return_local_eid = -1;
401  int64_t return_local_fid = -1;
402  int64_t return_tid = -1;
403 
404  // these are used only for assertions
405 #ifndef NDEBUG
406  int64_t return_fid = -1;
407  int64_t return_split_fid = -1;
408 #endif
409 
410  // update connectivity
411  for (int64_t i = 0; i < m_incident_tet_datas.size(); ++i) {
412  // prepare all indices
413  const auto& data = m_incident_tet_datas[i];
414  const int64_t vid_new = v_new;
415  const int64_t v0 = data.v0; // m_operating_tuple.vid
416  const int64_t v1 = data.v1; // switch_vertex(m_operating_tuple)
417  const int64_t v2 = data.v2; // f_old_1 opposite v
418  const int64_t v3 = data.v3; // f_old_2 opposite v
419  const int64_t e_spine_1 = new_eids[0];
420  const int64_t e_spine_2 = new_eids[1];
421  const int64_t e_rib_1 = data.new_face_data[0].eid_rib;
422  const int64_t e_rib_2 = data.new_face_data[1].eid_rib;
423  const int64_t e01 = data.e01;
424  const int64_t e02 = data.e02;
425  const int64_t e12 = data.e12;
426  const int64_t e03 = data.e03;
427  const int64_t e13 = data.e13;
428  const int64_t e23 = data.e23;
429  const int64_t f_ear_1 = data.ears[0].fid;
430  const int64_t f_ear_2 = data.ears[1].fid;
431  const int64_t f1 = data.new_face_data[0].fid_new[0];
432  const int64_t f2 = data.new_face_data[0].fid_new[1];
433  const int64_t f_old_1 = data.new_face_data[0].fid_old; // f1 + f2
434  const int64_t f3 = data.new_face_data[1].fid_new[0];
435  const int64_t f4 = data.new_face_data[1].fid_new[1];
436  const int64_t f_old_2 = data.new_face_data[1].fid_old; // f3 + f4
437  const int64_t f_rib = data.rib_f;
438  const int64_t t_ear_1 = data.ears[0].tid;
439  const int64_t t_ear_2 = data.ears[1].tid;
440  const int64_t t1 = data.split_t[0];
441  const int64_t t2 = data.split_t[1];
442  const int64_t t_old = data.tid;
443  int64_t t_f1; // prev t1
444  int64_t t_f2; // prev t2
445  int64_t t_f3; // next t1
446  int64_t t_f4; // next t2
447 
448  // /////////////////////////////////////////////////
449  // // debug code , to delete
450  // if (e_spine_1 == 2223) {
451  // wmtk::logger().info(
452  // "edge 2223 is created in tet {} face {} edge {} as spine edge 1, belongs to new "
453  // "tet {}, face {} and face {}, loop flag {}, left ear {}, right ear{}, right "
454  // "neighbor{}, left ear face {}, right ear face {}",
455  // t_old,
456  // f_old_1,
457  // e01,
458  // t1,
459  // f1,
460  // f3,
461  // loop_flag,
462  // t_ear_1,
463  // t_ear_2,
464  // t2,
465  // f_ear_1,
466  // f_ear_2);
467  // }
468  // if (e_spine_2 == 2223) {
469  // wmtk::logger().info(
470  // "edge 2223 is created in tet {} face {} edge {} as spine edge 2, belongs to new "
471  // "tet {}, face {} and face {}, loop flag {}",
472  // t_old,
473  // f_old_2,
474  // e01,
475  // t2,
476  // f2,
477  // f4,
478  // loop_flag);
479  // }
480  // if (e_rib_1 == 2223) {
481  // wmtk::logger().info(
482  // "edge 2223 is created in tet {} face {} as rib edge 1, belongs to new "
483  // "tet {} and {}, face {} and face {}, loop flag {}",
484  // t_old,
485  // f_old_1,
486  // t1,
487  // t2,
488  // f1,
489  // f3,
490  // loop_flag);
491  // }
492  // if (e_rib_2 == 2223) {
493  // wmtk::logger().info(
494  // "edge 2223 is created in tet {} face {} as rib edge 2, belongs to new "
495  // "tet {} and {}, face {} and face {}, loop flag {}",
496  // t_old,
497  // f_old_2,
498  // t1,
499  // t2,
500  // f2,
501  // f4,
502  // loop_flag);
503  // }
504 
505  // /////////////////////////////////////////////////
506 
507  // for return tuple
508  // return_flag == true means this is the tet for the tuple to return
509 
510  bool return_flag = false;
511  if (t_old == m_operating_tet_id) {
512  return_tid = t2;
513 
514  logger().trace("split fid is {}", f_rib);
515  logger().trace("fids {} {} are joined by edge {}", f3, f4, e_rib_2);
516 #ifndef NDEBUG
517  return_fid = f4;
518  return_split_fid = f_rib;
519 #endif
520  return_flag = true;
521  }
522  int64_t prev_index = (i - 1 + m_incident_tet_datas.size()) % m_incident_tet_datas.size();
523  int64_t next_index = (i + 1 + m_incident_tet_datas.size()) % m_incident_tet_datas.size();
524 
525  if (loop_flag) {
526  t_f1 = m_incident_tet_datas[prev_index].split_t[0];
527  t_f2 = m_incident_tet_datas[prev_index].split_t[1];
528  t_f3 = m_incident_tet_datas[next_index].split_t[0];
529  t_f4 = m_incident_tet_datas[next_index].split_t[1];
530  } else {
531  if (m_incident_tet_datas.size() == 1) {
532  t_f1 = -1;
533  t_f2 = -1;
534  t_f3 = -1;
535  t_f4 = -1;
536  } else {
537  if (i == 0) {
538  // no prev
539  t_f1 = -1;
540  t_f2 = -1;
541  } else {
542  t_f1 = m_incident_tet_datas[prev_index].split_t[0];
543  t_f2 = m_incident_tet_datas[prev_index].split_t[1];
544  }
545  if (i == m_incident_tet_datas.size() - 1) {
546  // no next
547  t_f3 = -1;
548  t_f4 = -1;
549  } else {
550  t_f3 = m_incident_tet_datas[next_index].split_t[0];
551  t_f4 = m_incident_tet_datas[next_index].split_t[1];
552  }
553  }
554  }
555 
556  // t1
557  {
558  // update ear tet 1 (tt, tf)
559  update_ear_connectivity(t_ear_1, t1, t_old, f_ear_1);
560 
561  auto tt = tt_accessor.index_access().vector_attribute(t1);
562  auto tf = tf_accessor.index_access().vector_attribute(t1);
563  auto te = te_accessor.index_access().vector_attribute(t1);
564  auto tv = tv_accessor.index_access().vector_attribute(t1);
565 
566  /*
567  copy t_old
568  v1 --> v_new
569  e13 --> e_split2
570  e12 --> e_split1
571  e01 --> e_spine1
572  f_old_1 --> f1
573  f_old_2 --> f3
574  f_ear_2 --> fsp
575  t(f_ear_2) t_ear_2 --> t2
576  t(f_old_1) --> -1 or tetdata[idx-1].t1
577  t(f_old_2) --> -1 or tetdata[idx+1].t1
578  */
579  // copy t_old
580  tt = tt_accessor.index_access().vector_attribute(t_old);
581  tf = tf_accessor.index_access().vector_attribute(t_old);
582  te = te_accessor.index_access().vector_attribute(t_old);
583  tv = tv_accessor.index_access().vector_attribute(t_old);
584 
585  // get ids for return tuple
586  if (return_flag) {
587  // vertex and face
588  for (int k = 0; k < 4; ++k) {
589  // vertex
590  if (tv(k) == m_spine_vids[0]) {
591  return_local_vid = k;
592  }
593 
594  // face
595  if (tf(k) == m_operating_face_id) {
596  return_local_fid = k;
597  }
598  }
599 
600  // edge
601  for (int k = 0; k < 6; ++k) {
602  if (te(k) == e01) {
603  return_local_eid = k;
604  break;
605  }
606  }
607  }
608 
609 
610  for (size_t k = 0; k < 4; ++k) {
611  // vertices
612  if (tv(k) == v1) {
613  tv(k) = vid_new;
614  }
615 
616  // faces and tets
617  if (tf(k) == f_old_1) {
618  // local fid for multimesh update
619  m_incident_tet_datas[i].incident_face_local_fid[0] = k;
620 
621  tf(k) = f1;
622  tt(k) = t_f1;
623  }
624  if (tf(k) == f_old_2) {
625  // local fid for multimesh update
626  m_incident_tet_datas[i].incident_face_local_fid[1] = k;
627 
628  tf(k) = f3;
629  tt(k) = t_f3;
630  }
631  if (tf(k) == f_ear_2) {
632  tf(k) = f_rib;
633  tt(k) = t2;
634  }
635  }
636 
637  for (size_t k = 0; k < 6; ++k) {
638  // edges
639  if (te(k) == e13) {
640  te(k) = e_rib_2;
641  }
642  if (te(k) == e12) {
643  te(k) = e_rib_1;
644  }
645  if (te(k) == e01) {
646  te(k) = e_spine_1;
647  }
648  }
649  }
650 
651  // t2
652  {
653  // update ear tet 2 (tt, tf)
654  update_ear_connectivity(t_ear_2, t2, t_old, f_ear_2);
655 
656  auto tt = tt_accessor.index_access().vector_attribute(t2);
657  auto tf = tf_accessor.index_access().vector_attribute(t2);
658  auto te = te_accessor.index_access().vector_attribute(t2);
659  auto tv = tv_accessor.index_access().vector_attribute(t2);
660 
661  /*
662  copy t_old
663  v0 --> v_new
664  e03 --> e_split2
665  e02 --> e_split1
666  e01 --> e_spine2
667  f_old_1 --> f2
668  f_old_2 --> f4
669  f_ear_1 --> fsp
670  t(f_ear_1) t_ear_1 --> t1
671  t(f_old_1) --> -1 or tetdata[idx-1].t2
672  t(f_old_2) --> -1 or tetdata[idx+1].t2
673  */
674  // copy t_old
675  tt = tt_accessor.index_access().const_vector_attribute(t_old);
676  tf = tf_accessor.index_access().const_vector_attribute(t_old);
677  te = te_accessor.index_access().const_vector_attribute(t_old);
678  tv = tv_accessor.index_access().const_vector_attribute(t_old);
679  for (size_t k = 0; k < 4; ++k) {
680  // vertices
681  if (tv(k) == v0) {
682  tv(k) = vid_new;
683  }
684 
685  // faces and tets
686  if (tf(k) == f_old_1) {
687  tf(k) = f2;
688  tt(k) = t_f2;
689  }
690  if (tf(k) == f_old_2) {
691  tf(k) = f4;
692  tt(k) = t_f4;
693  }
694  if (tf(k) == f_ear_1) {
695  tf(k) = f_rib;
696  tt(k) = t1;
697  }
698  }
699 
700  for (size_t k = 0; k < 6; ++k) {
701  // edges
702  if (te(k) == e03) {
703  te(k) = e_rib_2;
704  }
705  if (te(k) == e02) {
706  te(k) = e_rib_1;
707  }
708  if (te(k) == e01) {
709  te(k) = e_spine_2;
710  }
711  }
712  }
713 
714  // assign each face one tet
715  ft_accessor.index_access().scalar_attribute(f_ear_1) = t1;
716  ft_accessor.index_access().scalar_attribute(f_ear_2) = t2;
717  ft_accessor.index_access().scalar_attribute(f1) = t1;
718  ft_accessor.index_access().scalar_attribute(f2) = t2;
719  ft_accessor.index_access().scalar_attribute(f3) = t1;
720  ft_accessor.index_access().scalar_attribute(f4) = t2;
721  ft_accessor.index_access().scalar_attribute(f_rib) = t1;
722 
723  // assign each edge one tet
724  et_accessor.index_access().scalar_attribute(e02) = t1;
725  et_accessor.index_access().scalar_attribute(e12) = t2;
726  et_accessor.index_access().scalar_attribute(e03) = t1;
727  et_accessor.index_access().scalar_attribute(e13) = t2;
728  et_accessor.index_access().scalar_attribute(e23) = t1;
729  et_accessor.index_access().scalar_attribute(e_spine_1) = t1;
730  et_accessor.index_access().scalar_attribute(e_spine_2) = t2;
731  et_accessor.index_access().scalar_attribute(e_rib_1) = t1;
732  et_accessor.index_access().scalar_attribute(e_rib_2) = t1;
733 
734  // assign each vertex one tet
735  vt_accessor.index_access().scalar_attribute(v0) = t1;
736  vt_accessor.index_access().scalar_attribute(v1) = t2;
737  vt_accessor.index_access().scalar_attribute(v2) = t1;
738  vt_accessor.index_access().scalar_attribute(v3) = t1;
739  vt_accessor.index_access().scalar_attribute(vid_new) = t1;
740  }
741 
742 
743  // update hash and delete simplices
744  update_cell_hash();
745  delete_simplices();
746 
747 
748  assert(return_tid > -1);
749  assert(return_local_vid > -1);
750  assert(return_local_eid > -1);
751  assert(return_local_fid > -1);
752 
753  assert(return_local_vid == utils::TupleInspector::local_vid(m_operating_tuple));
754  assert(return_local_eid == utils::TupleInspector::local_eid(m_operating_tuple));
755  assert(return_local_fid == utils::TupleInspector::local_fid(m_operating_tuple));
756  m_output_tuple = Tuple(return_local_vid, return_local_eid, return_local_fid, return_tid);
757 
758  assert(m_split_new_vid == m_mesh.id(simplex::Simplex::vertex(m_mesh, m_output_tuple)));
759  assert(m_split_new_spine_eids[1] == m_mesh.id(simplex::Simplex::edge(m_mesh, m_output_tuple)));
760  assert(return_fid == m_mesh.id(simplex::Simplex::face(m_mesh, m_output_tuple)));
761  assert(return_tid == m_mesh.id(simplex::Simplex::tetrahedron(m_mesh, m_output_tuple)));
762 
763  logger().trace(
764  "split fid is {}",
765  m_mesh.id(simplex::Simplex::face(m_mesh, m_mesh.switch_tuples(m_output_tuple, {PE, PF}))));
766  // assert(m_mesh.id(simplex::Simplex::edge(m_mesh.switch_tuples(m_output_tuple, {PE}))) =
767  // return_face_spine_eid);
768  assert(
769  m_mesh.id(simplex::Simplex::face(m_mesh, m_mesh.switch_tuples(m_output_tuple, {PE, PF}))) ==
770  return_split_fid);
771  assert(!m_mesh.is_boundary_face(m_mesh.switch_tuples(m_output_tuple, {PE, PF})));
772 }
773 
775 {
776  set_collapse();
777  is_collapse = true;
778  simplex_ids_to_delete = get_collapse_simplices_to_delete(m_operating_tuple, m_mesh);
779 
780  // collect star before changing connectivity
781  // update all tv's after other updates
782  simplex::IdSimplexCollection v0_star(m_mesh);
783  v0_star.reserve(32);
785  m_mesh,
786  simplex::Simplex::vertex(m_mesh, m_operating_tuple))) {
787  v0_star.add(PrimitiveType::Tetrahedron, t);
788  }
789 
790 
791  // collect incident tets and their ears
792  // loop case and boundary case
793  // auto incident_tets_and_faces = get_incident_tets_and_faces(m_operating_tuple);
794  // const auto& incident_tets = incident_tets_and_faces[0];
795 
796  auto [incident_tets, incident_faces] = get_incident_tets_and_faces(m_operating_tuple);
797 
798 
799  for (const Tuple& tet : incident_tets) {
800  IncidentTetData tcd;
801  tcd.local_operating_tuple = tet;
802  tcd.tid = m_mesh.id_tet(tet);
803 
804  // get ears
805  Tuple ear1 = m_mesh.switch_face(m_mesh.switch_edge(tet));
806  if (!m_mesh.is_boundary_face(ear1)) {
807  ear1 = m_mesh.switch_tuple(ear1, PrimitiveType::Tetrahedron);
808  tcd.ears[0] = EarTet{m_mesh.id_tet(ear1), m_mesh.id_face(ear1)};
809  } else {
810  tcd.ears[0] = EarTet{-1, m_mesh.id_face(ear1)};
811  }
812 
813  Tuple ear2 = m_mesh.switch_face(m_mesh.switch_edge(m_mesh.switch_vertex(tet)));
814  if (!m_mesh.is_boundary_face(ear2)) {
815  ear2 = m_mesh.switch_tuple(ear2, PrimitiveType::Tetrahedron);
816  tcd.ears[1] = EarTet{m_mesh.id_tet(ear2), m_mesh.id_face(ear2)};
817  } else {
818  tcd.ears[1] = EarTet{-1, m_mesh.id_face(ear2)};
819  }
820 
821  tcd.v0 = m_mesh.id_vertex(tet);
822  tcd.v1 = m_mesh.id_vertex(m_mesh.switch_vertex(tet));
823  tcd.v2 =
824  m_mesh.id_vertex(m_mesh.switch_vertex(m_mesh.switch_edge(m_mesh.switch_face(tet))));
825  tcd.v3 = m_mesh.id_vertex(m_mesh.switch_vertex(m_mesh.switch_edge(tet)));
826 
827  tcd.e01 = m_mesh.id_edge(tet);
828  tcd.e03 = m_mesh.id_edge(m_mesh.switch_edge(tet));
829  tcd.e13 = m_mesh.id_edge(m_mesh.switch_edge(m_mesh.switch_vertex(tet)));
830  tcd.e02 = m_mesh.id_edge(m_mesh.switch_edge(m_mesh.switch_face(tet)));
831  tcd.e12 = m_mesh.id_edge(m_mesh.switch_edge(m_mesh.switch_face(m_mesh.switch_vertex(tet))));
832  tcd.e23 = m_mesh.id_edge(
833  m_mesh.switch_edge(m_mesh.switch_vertex(m_mesh.switch_face(m_mesh.switch_edge(tet)))));
834 
835  m_incident_tet_datas.emplace_back(tcd);
836  }
837 
838  // incident face data for multimesh and attribute update
839  m_incident_face_datas.clear();
840  for (int64_t i = 0; i < m_incident_tet_datas.size(); ++i) {
841  auto& data = m_incident_face_datas.emplace_back();
842  data.ear_eids[0] = m_incident_tet_datas[i].e03;
843  data.ear_eids[1] = m_incident_tet_datas[i].e13;
844  data.new_edge_id = data.ear_eids[1];
845  }
846 
847  if (incident_tets.size() != incident_faces.size()) {
848  auto& data = m_incident_face_datas.emplace_back();
849  data.ear_eids[0] = m_incident_tet_datas[0].e02;
850  data.ear_eids[1] = m_incident_tet_datas[0].e12;
851  data.new_edge_id = data.ear_eids[1];
852  }
853 
854  assert(m_incident_face_datas.size() == incident_faces.size());
855 
856 
857  // local ids for return tuple
858  int64_t return_local_vid = -1;
859  int64_t return_local_eid = -1;
860  int64_t return_local_fid = -1;
861  int64_t return_tid = -1;
862 
863  std::map<int64_t, int64_t> edge_replacement;
864 
865  // update connectivity for ears
866  for (IncidentTetData& data : m_incident_tet_datas) {
867  // prepare all indices
868  const int64_t v0 = data.v0;
869  const int64_t v1 = data.v1;
870  const int64_t v2 = data.v2;
871  const int64_t v3 = data.v3;
872  const int64_t e01 = data.e01;
873  const int64_t e02 = data.e02;
874  const int64_t e12 = data.e12;
875  const int64_t e03 = data.e03;
876  const int64_t e13 = data.e13;
877  const int64_t e23 = data.e23;
878  const int64_t f_ear_1 = data.ears[0].fid;
879  const int64_t f_ear_2 = data.ears[1].fid;
880  const int64_t t_ear_1 = data.ears[0].tid;
881  const int64_t t_ear_2 = data.ears[1].tid;
882  const int64_t t_old = data.tid;
883 
884  edge_replacement[e02] = e12;
885  edge_replacement[e03] = e13;
886 
888  // // debug code
889  // if (e13 == 2223) {
890  // wmtk::logger().info(
891  // "edge 2223 in tet {} is assigned to tet {} face {} as merged edge 03->13, "
892  // "replacing edge {}, right ear is tet {} face {} edge {}",
893  // t_old,
894  // t_ear_1,
895  // f_ear_1,
896  // e03,
897  // t_ear_2,
898  // f_ear_2,
899  // e13);
900  // }
901 
902  // if (e12 == 2223) {
903  // wmtk::logger().info(
904  // "edge 2223 in tet {} is assigned to tet {} face {} as merged edge 02->12, "
905  // "replacing edge {}, right ear is tet {} face {} edge {}",
906  // t_old,
907  // t_ear_1,
908  // f_ear_1,
909  // e02,
910  // t_ear_2,
911  // f_ear_2,
912  // e12);
913  // }
914  // /////////////////////////////////////////////////
915 
916 
917  // check by link condition
918  assert(t_ear_1 > -1 || t_ear_2 > -1);
919 
920  // return_flag == true means this is the tet for the tuple to return
921  bool return_flag = false;
922  if (t_old == m_operating_tet_id) {
923  // found the tet to return
924  return_flag = true;
925  // prior return tet is ear_2
926  return_tid = (t_ear_2 > -1) ? t_ear_2 : t_ear_1;
927  }
928 
929  // collapse v0 to v1
930  // update t_ear_1
931 
932  /*
933  t_old --> t_ear_2
934  f_ear_1 --> f_ear_2
935  e02 --> e12
936  e03 --> e13
937  v0 --> v1 (update later)
938  */
939  if (t_ear_1 != -1) {
940  auto tt = tt_accessor.index_access().vector_attribute(t_ear_1);
941  auto tf = tf_accessor.index_access().vector_attribute(t_ear_1);
942  auto te = te_accessor.index_access().vector_attribute(t_ear_1);
943  auto tv = tv_accessor.index_access().vector_attribute(t_ear_1);
944 
945  // get local ids for the return tuple
946  if (return_flag && return_tid == t_ear_1) {
947  for (int k = 0; k < 4; ++k) {
948  // face
949  if (tf(k) == f_ear_1) {
950  return_local_fid = k;
951  }
952 
953  // vertex
954  if (tv(k) == v0) {
955  return_local_vid = k;
956  }
957  }
958 
959  for (int k = 0; k < 6; ++k) {
960  // edge
961  if (te(k) == e03) {
962  return_local_eid = k;
963  break;
964  }
965  }
966  }
967 
968  // update
969  // face and tet
970  for (int k = 0; k < 4; ++k) {
971  if (tf(k) == f_ear_1) {
972  assert(tt(k) == t_old);
973  tf(k) = f_ear_2;
974  tt(k) = t_ear_2;
975  }
976  }
977 
978  // edge
979  for (int k = 0; k < 6; ++k) {
980  if (te(k) == e02) {
981  te(k) = e12;
982  }
983  if (te(k) == e03) {
984  te(k) = e13;
985  }
986  }
987  }
988 
989  // update t_ear_2
990  if (t_ear_2 != -1) {
991  auto tt = tt_accessor.index_access().vector_attribute(t_ear_2);
992  auto tf = tf_accessor.index_access().vector_attribute(t_ear_2);
993  auto te = te_accessor.index_access().vector_attribute(t_ear_2);
994  auto tv = tv_accessor.index_access().vector_attribute(t_ear_2);
995 
996 
997  // for return tuple
998  if (return_flag && return_tid == t_ear_2) {
999  for (int k = 0; k < 4; ++k) {
1000  if (tv(k) == v1) {
1001  return_local_vid = k;
1002  }
1003  if (tf(k) == f_ear_2) {
1004  return_local_fid = k;
1005  }
1006  }
1007 
1008  for (int k = 0; k < 6; ++k) {
1009  if (te(k) == e13) {
1010  return_local_eid = k;
1011  break;
1012  }
1013  }
1014  }
1015 
1016  for (int k = 0; k < 4; ++k) {
1017  if (tt(k) == t_old) {
1018  // assert(tf(k) == f_ear_2);
1019  tt(k) = t_ear_1;
1020  }
1021  }
1022  }
1023 
1024  const int64_t t_ear_valid = (t_ear_2 > -1) ? t_ear_2 : t_ear_1;
1025  // for multimesh update
1026 
1027  data.merged_face_tid = t_ear_valid;
1028  // assign tet for each face
1029  ft_accessor.index_access().scalar_attribute(f_ear_2) = t_ear_valid;
1030 
1031  data.new_face_id = f_ear_2;
1032 
1033  // assign tet for each edge
1034  et_accessor.index_access().scalar_attribute(e12) = t_ear_valid;
1035  et_accessor.index_access().scalar_attribute(e13) = t_ear_valid;
1036  et_accessor.index_access().scalar_attribute(e23) = t_ear_valid;
1037 
1038  // assign tet for each vertex
1039  vt_accessor.index_access().scalar_attribute(v1) = t_ear_valid;
1040  vt_accessor.index_access().scalar_attribute(v2) = t_ear_valid;
1041  vt_accessor.index_access().scalar_attribute(v3) = t_ear_valid;
1042  }
1043 
1044  // update v0 one ring tv
1045  // update ear edge replacements
1046  const int64_t v0 = m_spine_vids[0];
1047  const int64_t v1 = m_spine_vids[1];
1048 
1049  for (const simplex::IdSimplex& t : v0_star) {
1050  // for (const simplex::Simplex& t : v0_star.simplex_vector(PrimitiveType::Tetrahedron)) {
1051  const int64_t tid = m_mesh.id(t);
1052  auto tv = tv_accessor.index_access().vector_attribute(tid);
1053  auto te = te_accessor.index_access().vector_attribute(tid);
1054  for (int i = 0; i < 4; ++i) {
1055  if (tv(i) == v0) {
1056  tv(i) = v1;
1057  break;
1058  }
1059  }
1060  for (int i = 0; i < 6; ++i) {
1061  if (edge_replacement.find(te(i)) != edge_replacement.end()) {
1062  te(i) = edge_replacement[te(i)];
1063  }
1064  }
1065  }
1066 
1067 
1068  update_cell_hash();
1069  delete_simplices();
1070 
1071  // debug code
1072  assert(m_mesh.is_connectivity_valid());
1073  assert(return_tid > -1);
1074  assert(return_local_fid > -1);
1075  assert(return_local_eid > -1);
1076  assert(return_local_vid > -1);
1077  m_output_tuple = Tuple(return_local_vid, return_local_eid, return_local_fid, return_tid);
1078 
1079  assert(m_mesh.id_vertex(m_output_tuple) == v1);
1080 }
1081 
1083  const PrimitiveType type,
1084  int64_t count)
1085 {
1086  m_mesh.guarantee_more_attributes(type, count);
1087 
1088  return m_mesh.request_simplex_indices(type, count);
1089 }
1090 
1091 
1092 } // namespace wmtk
std::vector< int64_t > request_simplex_indices(PrimitiveType type, int64_t count)
const attribute::Accessor< char > get_flag_accessor(PrimitiveType type) const
Definition: Mesh.cpp:158
std::tuple< std::vector< Tuple >, std::vector< Tuple > > get_incident_tets_and_faces(Tuple t)
Get the incident tets and faces for an edge tuple.
std::vector< int64_t > request_simplex_indices(const PrimitiveType type, int64_t count)
static const std::array< std::vector< int64_t >, 4 > get_split_simplices_to_delete(const Tuple &tuple, const TetMesh &m)
gather all simplices that are deleted in a split
static const std::array< std::vector< int64_t >, 4 > get_collapse_simplices_to_delete(const Tuple &tuple, const TetMesh &m)
gather all simplices that are deleted in a collapse
void update_ear_connectivity(const int64_t ear_tid, const int64_t new_tid, const int64_t old_tid, const int64_t common_fid)
std::array< attribute::Accessor< char >, 4 > flag_accessors
TetMeshOperationExecutor(TetMesh &m, const Tuple &operating_tuple)
Tuple switch_face(const Tuple &tuple) const
Definition: TetMesh.hpp:121
int64_t id(const Tuple &tuple, PrimitiveType type) const
Definition: TetMesh.hpp:130
int64_t id_tet(const Tuple &tuple) const
Definition: TetMesh.hpp:73
Tuple switch_tetrahedron(const Tuple &tuple) const
Definition: TetMesh.hpp:125
bool is_boundary_face(const Tuple &tuple) const
Definition: TetMesh.cpp:382
std::array< std::vector< int64_t >, 4 > simplex_ids_to_delete
void add(const IdSimplex &simplex)
Add simplex to the collection.
void reserve(const size_t new_cap)
void add(const Simplex &simplex)
Add simplex to the collection.
void sort_and_clean()
Sort simplex vector and remove duplicates.
static Simplex face(const Mesh &m, const Tuple &t)
Definition: Simplex.hpp:63
static Simplex edge(const Mesh &m, const Tuple &t)
Definition: Simplex.hpp:61
static Simplex tetrahedron(const Mesh &m, const Tuple &t)
Definition: Simplex.hpp:68
static Simplex vertex(const Mesh &m, const Tuple &t)
Definition: Simplex.hpp:56
static int8_t local_eid(const Tuple &t)
static int8_t local_vid(const Tuple &t)
static int8_t local_fid(const Tuple &t)
constexpr wmtk::PrimitiveType PF
void top_dimension_cofaces_tuples(const PointMesh &mesh, const Simplex &simplex, SimplexCollection &collection)
TopDimensionCofacesIterable top_dimension_cofaces_iterable(const Mesh &mesh, const Simplex &simplex)
SimplexCollection open_star(const Mesh &mesh, const Simplex &simplex, const bool sort_and_clean)
Definition: open_star.cpp:12
LinkSingleDimensionIterable link_single_dimension_iterable(const Mesh &mesh, const Simplex &simplex, const PrimitiveType link_type)
HalfClosedStarIterable half_closed_star_iterable(const Mesh &mesh, const Tuple &tuple)
The half closed star is used to determine the deleted simplices in an edge collapse.
SimplexCollection faces_single_dimension(const Mesh &mesh, const Simplex &simplex, const PrimitiveType face_type)
Returns a vector with all faces in the boundary of a simplex of the given dimension.
SimplexCollection faces(const Mesh &mesh, const Simplex &simplex, const bool sort_and_clean)
Returns all faces of a simplex.
Definition: faces.cpp:10
Definition: Accessor.hpp:6
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
constexpr PrimitiveType PE
An EarTet is a neighbor of a tet to be deleted in the split/collapse operation.
Data on the incident tets of the operating edge.