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