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