16 #include "libmesh/elem.h" 17 #include "libmesh/enum_order.h" 18 #include "libmesh/boundary_info.h" 19 #include "libmesh/mesh_base.h" 20 #include "libmesh/parallel.h" 21 #include "libmesh/parallel_algebra.h" 22 #include "libmesh/utility.h" 23 #include "libmesh/cell_tet4.h" 24 #include "libmesh/face_tri3.h" 25 #include "libmesh/cell_pyramid5.h" 33 const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
35 std::vector<dof_id_type> & converted_elems_ids)
40 std::vector<std::vector<boundary_id_type>> elem_side_list;
41 elem_side_list.resize(6);
45 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
47 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
50 std::vector<std::vector<unsigned int>> opt_option;
59 std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
61 std::vector<std::vector<const Node *>> optimized_node_list;
64 std::vector<Elem *> elems_Tet4;
65 for (
const auto i :
index_range(optimized_node_list))
67 auto new_elem = std::make_unique<Tet4>();
68 new_elem->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
69 new_elem->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
70 new_elem->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
71 new_elem->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
73 elems_Tet4.push_back(
mesh.
add_elem(std::move(new_elem)));
74 converted_elems_ids.push_back(elems_Tet4.back()->id());
76 for (
unsigned int j = 0; j < 4; j++)
81 if (rotated_tet_face_indices[i][j] < 6)
83 for (
const auto & side_info : elem_side_list[rotated_tet_face_indices[i][j]])
84 boundary_info.
add_side(elems_Tet4.back(), j, side_info);
90 for (
unsigned int i = 0; i < 6; i++)
91 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
93 elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
99 const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
101 std::vector<dof_id_type> & converted_elems_ids)
106 std::vector<std::vector<boundary_id_type>> elem_side_list;
110 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
113 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
122 std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
123 std::vector<std::vector<const Node *>> optimized_node_list;
126 std::vector<Elem *> elems_Tet4;
127 for (
const auto i :
index_range(optimized_node_list))
129 auto new_elem = std::make_unique<Tet4>();
130 new_elem->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
131 new_elem->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
132 new_elem->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
133 new_elem->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
135 elems_Tet4.push_back(
mesh.
add_elem(std::move(new_elem)));
136 converted_elems_ids.push_back(elems_Tet4.back()->id());
138 for (
unsigned int j = 0; j < 4; j++)
143 if (rotated_tet_face_indices[i][j] < 5)
145 for (
const auto & side_info : elem_side_list[rotated_tet_face_indices[i][j]])
146 boundary_info.
add_side(elems_Tet4.back(), j, side_info);
152 for (
unsigned int i = 0; i < 3; i++)
153 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
155 elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
161 const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
163 std::vector<dof_id_type> & converted_elems_ids)
168 std::vector<std::vector<boundary_id_type>> elem_side_list;
172 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
174 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
182 std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
183 std::vector<std::vector<const Node *>> optimized_node_list;
186 std::vector<Elem *> elems_Tet4;
187 for (
const auto i :
index_range(optimized_node_list))
189 auto new_elem = std::make_unique<Tet4>();
190 new_elem->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
191 new_elem->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
192 new_elem->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
193 new_elem->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
195 elems_Tet4.push_back(
mesh.
add_elem(std::move(new_elem)));
196 converted_elems_ids.push_back(elems_Tet4.back()->id());
198 for (
unsigned int j = 0; j < 4; j++)
203 if (rotated_tet_face_indices[i][j] < 5)
205 for (
const auto & side_info : elem_side_list[rotated_tet_face_indices[i][j]])
206 boundary_info.
add_side(elems_Tet4.back(), j, side_info);
212 for (
unsigned int i = 0; i < 2; i++)
213 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
215 elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
219 std::vector<unsigned int>
222 const std::vector<std::vector<unsigned int>> preset_indices = {
223 {1, 3, 4}, {0, 2, 5}, {3, 1, 6}, {2, 0, 7}, {5, 7, 0}, {4, 6, 1}, {7, 5, 2}, {6, 4, 3}};
224 if (min_id_index > 7)
225 mooseError(
"The input node index is out of range.");
227 return preset_indices[min_id_index];
232 std::vector<std::vector<unsigned int>> & rotated_tet_face_indices,
233 std::vector<std::vector<const Node *>> & tet_nodes_list)
236 std::vector<dof_id_type> node_ids(8);
237 for (
unsigned int i = 0; i < 8; i++)
238 node_ids[i] = hex_nodes[i]->
id();
240 const unsigned int min_node_id_index = std::distance(
241 std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
247 const auto neighbor_node_ids = {node_ids[neighbor_node_indices[0]],
248 node_ids[neighbor_node_indices[1]],
249 node_ids[neighbor_node_indices[2]]};
250 const unsigned int sec_min_pos =
251 std::distance(std::begin(neighbor_node_ids),
252 std::min_element(std::begin(neighbor_node_ids), std::end(neighbor_node_ids)));
258 std::vector<unsigned int> face_rotation;
259 std::vector<unsigned int> rotated_indices;
260 nodeRotationHEX8(min_node_id_index, sec_min_pos, face_rotation, rotated_indices);
261 std::vector<const Node *> rotated_hex_nodes;
262 for (
unsigned int i = 0; i < 8; i++)
263 rotated_hex_nodes.push_back(hex_nodes[rotated_indices[i]]);
270 std::vector<std::vector<unsigned int>> tet_face_indices;
271 const auto tet_nodes_set =
tetNodesForHex(diagonal_directions, tet_face_indices);
272 for (
const auto & tet_face_index : tet_face_indices)
274 rotated_tet_face_indices.push_back(std::vector<unsigned int>());
275 for (
const auto & face_index : tet_face_index)
278 rotated_tet_face_indices.back().push_back(face_rotation[face_index]);
280 rotated_tet_face_indices.back().push_back(6);
284 for (
const auto & tet_nodes : tet_nodes_set)
286 tet_nodes_list.push_back(std::vector<const Node *>());
287 for (
const auto & tet_node : tet_nodes)
288 tet_nodes_list.back().push_back(rotated_hex_nodes[tet_node]);
296 const std::vector<std::vector<unsigned int>> face_indices = {
297 {0, 1, 2, 3}, {4, 5, 6, 7}, {0, 1, 5, 4}, {2, 3, 7, 6}, {1, 2, 6, 5}, {3, 0, 4, 7}};
298 std::vector<bool> diagonal_directions;
299 for (
const auto & face_index : face_indices)
301 std::vector<const Node *> quad_nodes = {hex_nodes[face_index[0]],
302 hex_nodes[face_index[1]],
303 hex_nodes[face_index[2]],
304 hex_nodes[face_index[3]]};
307 return diagonal_directions;
313 const std::vector<dof_id_type> node_ids = {
314 quad_nodes[0]->id(), quad_nodes[1]->id(), quad_nodes[2]->id(), quad_nodes[3]->id()};
315 const unsigned int min_id_index = std::distance(
316 std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
317 if (min_id_index == 0 || min_id_index == 2)
323 std::vector<std::vector<unsigned int>>
325 std::vector<std::vector<unsigned int>> & tet_face_indices)
327 const std::vector<std::vector<bool>> possible_inputs = {{
true,
true,
true,
true,
true,
false},
328 {
true,
true,
true,
true,
false,
false},
329 {
true,
true,
true,
false,
true,
false},
330 {
true,
false,
true,
true,
true,
false},
331 {
true,
false,
true,
true,
false,
false},
332 {
true,
false,
true,
false,
true,
false},
333 {
true,
false,
true,
false,
false,
false}};
335 const unsigned int input_index = std::distance(
336 std::begin(possible_inputs),
337 std::find(std::begin(possible_inputs), std::end(possible_inputs), diagonal_directions));
343 {0, 6, 2, 6}, {1, 6, 2, 6}, {1, 6, 5, 6}, {0, 6, 3, 4}, {6, 6, 3, 6}, {6, 4, 5, 6}};
344 return {{0, 1, 2, 6}, {0, 5, 1, 6}, {0, 4, 5, 6}, {0, 2, 3, 7}, {0, 6, 2, 7}, {0, 4, 6, 7}};
347 {0, 1, 2, 6}, {6, 6, 2, 6}, {6, 6, 5, 1}, {0, 6, 3, 4}, {6, 6, 3, 6}, {6, 4, 5, 6}};
348 return {{0, 1, 2, 5}, {0, 2, 6, 5}, {0, 6, 4, 5}, {0, 2, 3, 7}, {0, 6, 2, 7}, {0, 4, 6, 7}};
351 {0, 6, 2, 6}, {1, 6, 2, 6}, {1, 6, 5, 6}, {4, 6, 5, 6}, {4, 6, 3, 6}, {0, 6, 3, 6}};
352 return {{0, 1, 2, 6}, {0, 5, 1, 6}, {0, 4, 5, 6}, {0, 7, 4, 6}, {0, 3, 7, 6}, {0, 2, 3, 6}};
355 {4, 6, 5, 1}, {6, 6, 5, 6}, {6, 1, 2, 6}, {4, 0, 3, 6}, {6, 6, 3, 6}, {6, 6, 2, 0}};
356 return {{0, 7, 4, 5}, {0, 6, 7, 5}, {0, 1, 6, 5}, {0, 3, 7, 2}, {0, 7, 6, 2}, {0, 6, 1, 2}};
358 tet_face_indices = {{0, 1, 2, 6}, {0, 6, 3, 4}, {5, 4, 6, 1}, {5, 6, 3, 2}, {6, 6, 6, 6}};
359 return {{0, 1, 2, 5}, {0, 2, 3, 7}, {4, 7, 5, 0}, {5, 7, 6, 2}, {0, 2, 7, 5}};
362 {4, 6, 5, 1}, {6, 6, 5, 6}, {6, 1, 2, 6}, {2, 6, 6, 0}, {3, 6, 6, 0}, {3, 6, 6, 4}};
363 return {{0, 7, 4, 5}, {0, 6, 7, 5}, {0, 1, 6, 5}, {1, 6, 2, 0}, {2, 6, 3, 0}, {3, 6, 7, 0}};
366 {1, 4, 5, 6}, {6, 6, 5, 6}, {6, 6, 3, 4}, {1, 6, 2, 0}, {6, 6, 2, 6}, {6, 0, 3, 6}};
367 return {{0, 4, 5, 7}, {0, 5, 6, 7}, {0, 6, 3, 7}, {0, 5, 1, 2}, {0, 6, 5, 2}, {0, 3, 6, 2}};
375 const unsigned int sec_min_pos,
376 std::vector<unsigned int> & face_rotation,
377 std::vector<unsigned int> & node_rotation)
383 const std::vector<std::vector<std::vector<unsigned int>>> preset_indices = {
384 {{0, 1, 2, 3, 4, 5, 6, 7}, {0, 3, 7, 4, 1, 2, 6, 5}, {0, 4, 5, 1, 3, 7, 6, 2}},
385 {{1, 0, 4, 5, 2, 3, 7, 6}, {1, 2, 3, 0, 5, 6, 7, 4}, {1, 5, 6, 2, 0, 4, 7, 3}},
386 {{2, 3, 0, 1, 6, 7, 4, 5}, {2, 1, 5, 6, 3, 0, 4, 7}, {2, 6, 7, 3, 1, 5, 4, 0}},
387 {{3, 2, 6, 7, 0, 1, 5, 4}, {3, 0, 1, 2, 7, 4, 5, 6}, {3, 7, 4, 0, 2, 6, 5, 1}},
388 {{4, 5, 1, 0, 7, 6, 2, 3}, {4, 7, 6, 5, 0, 3, 2, 1}, {4, 0, 3, 7, 5, 1, 2, 6}},
389 {{5, 4, 7, 6, 1, 0, 3, 2}, {5, 6, 2, 1, 4, 7, 3, 0}, {5, 1, 0, 4, 6, 2, 3, 7}},
390 {{6, 7, 3, 2, 5, 4, 0, 1}, {6, 5, 4, 7, 2, 1, 0, 3}, {6, 2, 1, 5, 7, 3, 0, 4}},
391 {{7, 6, 5, 4, 3, 2, 1, 0}, {7, 4, 0, 3, 6, 5, 1, 2}, {7, 3, 2, 6, 4, 0, 1, 5}}};
393 const std::vector<std::vector<std::vector<unsigned int>>> preset_face_indices = {
394 {{0, 1, 2, 3, 4, 5}, {4, 0, 3, 5, 1, 2}, {1, 4, 5, 2, 0, 3}},
395 {{1, 0, 4, 5, 2, 3}, {0, 2, 3, 4, 1, 5}, {2, 1, 5, 3, 0, 4}},
396 {{0, 3, 4, 1, 2, 5}, {2, 0, 1, 5, 3, 4}, {3, 2, 5, 4, 0, 1}},
397 {{3, 0, 2, 5, 4, 1}, {0, 4, 1, 2, 3, 5}, {4, 3, 5, 1, 0, 2}},
398 {{1, 5, 2, 0, 4, 3}, {5, 4, 3, 2, 1, 0}, {4, 1, 0, 3, 5, 2}},
399 {{5, 1, 4, 3, 2, 0}, {2, 5, 3, 0, 1, 4}, {1, 2, 0, 4, 5, 3}},
400 {{3, 5, 4, 0, 2, 1}, {5, 2, 1, 4, 3, 0}, {2, 3, 0, 1, 5, 4}},
401 {{5, 3, 2, 1, 4, 0}, {4, 5, 1, 0, 3, 2}, {3, 4, 0, 2, 5, 1}}};
403 if (min_id_index > 7 || sec_min_pos > 2)
404 mooseError(
"The input node index is out of range.");
408 face_rotation = preset_face_indices[min_id_index][sec_min_pos];
409 node_rotation = preset_indices[min_id_index][sec_min_pos];
415 std::vector<unsigned int> & face_rotation,
416 std::vector<unsigned int> & node_rotation)
418 const std::vector<std::vector<unsigned int>> preset_indices = {{0, 1, 2, 3, 4, 5},
425 const std::vector<std::vector<unsigned int>> preset_face_indices = {{0, 1, 2, 3, 4},
432 if (min_id_index > 5)
433 mooseError(
"The input node index is out of range.");
437 face_rotation = preset_face_indices[min_id_index];
438 node_rotation = preset_indices[min_id_index];
444 std::vector<std::vector<unsigned int>> & rotated_tet_face_indices,
445 std::vector<std::vector<const Node *>> & tet_nodes_list)
448 std::vector<dof_id_type> node_ids(6);
449 for (
unsigned int i = 0; i < 6; i++)
450 node_ids[i] = prism_nodes[i]->
id();
452 const unsigned int min_node_id_index = std::distance(
453 std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
458 std::vector<unsigned int> face_rotation;
459 std::vector<unsigned int> rotated_indices;
461 std::vector<const Node *> rotated_prism_nodes;
462 for (
unsigned int i = 0; i < 6; i++)
463 rotated_prism_nodes.push_back(prism_nodes[rotated_indices[i]]);
465 std::vector<const Node *> key_quad_nodes = {rotated_prism_nodes[1],
466 rotated_prism_nodes[2],
467 rotated_prism_nodes[5],
468 rotated_prism_nodes[4]};
475 std::vector<std::vector<unsigned int>> tet_face_indices;
476 const auto tet_nodes_set =
tetNodesForPrism(diagonal_direction, tet_face_indices);
477 for (
const auto & tet_face_index : tet_face_indices)
479 rotated_tet_face_indices.push_back(std::vector<unsigned int>());
480 for (
const auto & face_index : tet_face_index)
483 rotated_tet_face_indices.back().push_back(face_rotation[face_index]);
485 rotated_tet_face_indices.back().push_back(5);
489 for (
const auto & tet_nodes : tet_nodes_set)
491 tet_nodes_list.push_back(std::vector<const Node *>());
492 for (
const auto & tet_node : tet_nodes)
493 tet_nodes_list.back().push_back(rotated_prism_nodes[tet_node]);
497 std::vector<std::vector<unsigned int>>
499 std::vector<std::vector<unsigned int>> & tet_face_indices)
502 if (diagonal_direction)
504 tet_face_indices = {{4, 3, 5, 1}, {2, 1, 5, 5}, {2, 5, 3, 0}};
505 return {{3, 5, 4, 0}, {1, 4, 5, 0}, {1, 5, 2, 0}};
509 tet_face_indices = {{4, 3, 5, 1}, {2, 1, 5, 0}, {2, 5, 5, 3}};
510 return {{3, 5, 4, 0}, {1, 4, 2, 0}, {2, 4, 5, 0}};
516 std::vector<unsigned int> & face_rotation,
517 std::vector<unsigned int> & node_rotation)
519 const std::vector<std::vector<unsigned int>> preset_indices = {
520 {0, 1, 2, 3, 4}, {1, 2, 3, 0, 4}, {2, 3, 0, 1, 4}, {3, 0, 1, 2, 4}};
522 const std::vector<std::vector<unsigned int>> preset_face_indices = {
523 {0, 1, 2, 3, 4}, {1, 2, 3, 0, 4}, {2, 3, 0, 1, 4}, {3, 0, 1, 2, 4}};
525 if (min_id_index > 3)
526 mooseError(
"The input node index is out of range.");
530 face_rotation = preset_face_indices[min_id_index];
531 node_rotation = preset_indices[min_id_index];
537 std::vector<std::vector<unsigned int>> & rotated_tet_face_indices,
538 std::vector<std::vector<const Node *>> & tet_nodes_list)
541 std::vector<dof_id_type> node_ids(4);
542 for (
unsigned int i = 0; i < 4; i++)
543 node_ids[i] = pyramid_nodes[i]->
id();
545 const unsigned int min_node_id_index = std::distance(
546 std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
551 std::vector<unsigned int> face_rotation;
552 std::vector<unsigned int> rotated_indices;
554 std::vector<const Node *> rotated_pyramid_nodes;
555 for (
unsigned int i = 0; i < 5; i++)
556 rotated_pyramid_nodes.push_back(pyramid_nodes[rotated_indices[i]]);
559 const std::vector<std::vector<unsigned int>> tet_nodes_set = {{0, 1, 2, 4}, {0, 2, 3, 4}};
560 const std::vector<std::vector<unsigned int>> tet_face_indices = {{4, 0, 1, 5}, {4, 5, 2, 3}};
564 for (
const auto & tet_face_index : tet_face_indices)
566 rotated_tet_face_indices.push_back(std::vector<unsigned int>());
567 for (
const auto & face_index : tet_face_index)
570 rotated_tet_face_indices.back().push_back(face_rotation[face_index]);
572 rotated_tet_face_indices.back().push_back(5);
576 for (
const auto & tet_nodes : tet_nodes_set)
578 tet_nodes_list.push_back(std::vector<const Node *>());
579 for (
const auto & tet_node : tet_nodes)
580 tet_nodes_list.back().push_back(rotated_pyramid_nodes[tet_node]);
586 const std::vector<std::pair<dof_id_type, bool>> & elems_to_process,
587 std::vector<dof_id_type> & converted_elems_ids_to_track,
589 const bool delete_block_to_remove)
591 std::vector<dof_id_type> converted_elems_ids_to_retain;
595 for (
const auto & elem_to_process : elems_to_process)
602 elem_to_process.first,
603 elem_to_process.second ? converted_elems_ids_to_track
604 : converted_elems_ids_to_retain);
607 case ElemType::PYRAMID5:
610 elem_to_process.first,
611 elem_to_process.second ? converted_elems_ids_to_track
612 : converted_elems_ids_to_retain);
615 case ElemType::PRISM6:
618 elem_to_process.first,
619 elem_to_process.second ? converted_elems_ids_to_track
620 : converted_elems_ids_to_retain);
624 if (elem_to_process.second)
625 converted_elems_ids_to_track.push_back(elem_to_process.first);
627 converted_elems_ids_to_retain.push_back(elem_to_process.first);
634 if (delete_block_to_remove)
636 for (
auto elem_it =
mesh.active_subdomain_elements_begin(block_id_to_remove);
637 elem_it !=
mesh.active_subdomain_elements_end(block_id_to_remove);
650 std::set<subdomain_id_type> subdomain_ids_set;
654 std::vector<std::pair<dof_id_type, bool>> original_elems;
656 for (
auto elem_it =
mesh.active_elements_begin(); elem_it !=
mesh.active_elements_end();
659 if ((*elem_it)->default_order() != Order::FIRST)
660 mooseError(
"Only first order elements are supported for cutting.");
661 original_elems.push_back(std::make_pair((*elem_it)->id(),
false));
664 std::vector<dof_id_type> converted_elems_ids_to_track;
667 mesh, original_elems, converted_elems_ids_to_track, block_id_to_remove,
true);
673 const unsigned short n_elem_sides,
674 std::vector<std::vector<boundary_id_type>> & elem_side_list)
676 elem_side_list.resize(n_elem_sides);
677 const auto selected_bdry_side_list =
678 std::equal_range(bdry_side_list.begin(), bdry_side_list.end(), elem_id,
BCTupleKeyComp{});
679 for (
auto selected_bdry_side = selected_bdry_side_list.first;
680 selected_bdry_side != selected_bdry_side_list.second;
681 ++selected_bdry_side)
683 elem_side_list[std::get<1>(*selected_bdry_side)].push_back(std::get<2>(*selected_bdry_side));
690 const std::vector<unsigned int> & side_indices,
691 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
713 "The provided element type '" + std::to_string(elem_type) +
714 "' is not supported and is not supposed to be passed to this function. " 715 "Only HEX8, PRISM6 and PYRAMID5 are supported.");
722 const std::vector<unsigned int> & side_indices,
723 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
734 if (std::find(side_indices.begin(), side_indices.end(), i_side) != side_indices.end())
736 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
739 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
746 const unsigned int & side_index,
747 const Node * new_node,
748 const std::vector<boundary_id_type> & side_info,
751 auto new_elem = std::make_unique<Pyramid5>();
756 new_elem->set_node(4, const_cast<Node *>(new_node));
760 for (
const auto & bid : side_info)
767 const unsigned int & side_index,
768 const Node * new_node,
769 const std::vector<boundary_id_type> & side_info,
774 unsigned int lid_index = 0;
782 auto new_elem_0 = std::make_unique<Tet4>();
783 new_elem_0->set_node(0,
787 new_elem_0->set_node(1,
791 new_elem_0->set_node(2,
795 new_elem_0->set_node(3, const_cast<Node *>(new_node));
797 auto new_elem_ptr_0 =
mesh.
add_elem(std::move(new_elem_0));
800 auto new_elem_1 = std::make_unique<Tet4>();
801 new_elem_1->set_node(0,
805 new_elem_1->set_node(1,
809 new_elem_1->set_node(2,
813 new_elem_1->set_node(3, const_cast<Node *>(new_node));
815 auto new_elem_ptr_1 =
mesh.
add_elem(std::move(new_elem_1));
818 for (
const auto & bid : side_info)
828 const std::vector<unsigned int> & side_indices,
829 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
839 if (i_side % 4 == 0 ||
840 std::find(side_indices.begin(), side_indices.end(), i_side) != side_indices.end())
842 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
845 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
852 const unsigned int & side_index,
853 const Node * new_node,
854 const std::vector<boundary_id_type> & side_info,
861 bool is_side_quad = (side_index % 4 != 0);
862 unsigned int lid_index = 0;
871 auto new_elem_0 = std::make_unique<Tet4>();
872 new_elem_0->set_node(0,
876 new_elem_0->set_node(1,
880 new_elem_0->set_node(2,
884 new_elem_0->set_node(3, const_cast<Node *>(new_node));
886 auto new_elem_ptr_0 =
mesh.
add_elem(std::move(new_elem_0));
889 Elem * new_elem_ptr_1 =
nullptr;
892 auto new_elem_1 = std::make_unique<Tet4>();
897 new_elem_1->set_node(1,
901 new_elem_1->set_node(2,
905 new_elem_1->set_node(3, const_cast<Node *>(new_node));
911 for (
const auto & bid : side_info)
922 const unsigned int & side_index,
923 const Node * new_node,
924 const std::vector<boundary_id_type> & side_info,
929 mesh, elem_id, side_index, new_node, side_info, subdomain_id_shift_base);
935 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
939 unsigned int lid_index = 0;
946 auto new_elem_0 = std::make_unique<Tet4>();
947 new_elem_0->set_node(
950 new_elem_0->set_node(
953 new_elem_0->set_node(
958 auto new_elem_ptr_0 =
mesh.
add_elem(std::move(new_elem_0));
961 auto new_elem_1 = std::make_unique<Tet4>();
962 new_elem_1->set_node(
965 new_elem_1->set_node(
968 new_elem_1->set_node(
973 auto new_elem_ptr_1 =
mesh.
add_elem(std::move(new_elem_1));
976 for (
const auto & bid : elem_side_info[0])
978 for (
const auto & bid : elem_side_info[1])
983 for (
const auto & bid : elem_side_info[2])
985 for (
const auto & bid : elem_side_info[3])
990 for (
const auto & bid : elem_side_info[4])
1007 const std::vector<BoundaryName> & boundary_names,
1008 const unsigned int conversion_element_layer_number,
1009 const bool external_boundaries_checking)
1022 std::vector<boundary_id_type> boundary_ids;
1023 for (
const auto &
sideset : boundary_names)
1034 std::vector<std::pair<dof_id_type, std::vector<unsigned int>>> elems_list;
1035 std::vector<std::set<dof_id_type>> layered_elems_list;
1036 layered_elems_list.push_back(std::set<dof_id_type>());
1040 for (
const auto & side_info : side_list)
1042 if (std::get<2>(side_info) == uniform_tmp_bid)
1052 "The provided boundary set contains non-linear side elements, which is not supported.");
1053 const auto side_type =
1055 layered_elems_list.back().emplace(std::get<0>(side_info));
1059 const auto neighbor_ptr =
1063 if (external_boundaries_checking)
1065 "The provided boundary contains non-external sides, which is required when " 1066 "external_boundaries_checking is enabled.");
1068 layered_elems_list.back().emplace(neighbor_ptr->id());
1071 if (conversion_element_layer_number == 1)
1073 if (side_type ==
TRI3)
1075 else if (side_type ==
QUAD4)
1077 auto pit = std::find_if(elems_list.begin(),
1079 [elem_id = std::get<0>(side_info)](
const auto & p)
1080 {
return p.first == elem_id; });
1081 if (elems_list.size() && pit != elems_list.end())
1083 pit->second.push_back(std::get<1>(side_info));
1086 elems_list.push_back(std::make_pair(
1087 std::get<0>(side_info), std::vector<unsigned int>({std::get<1>(side_info)})));
1090 auto sit = std::find_if(elems_list.begin(),
1092 [elem_id = neighbor_ptr->id()](
const auto & p)
1093 {
return p.first == elem_id; });
1094 if (elems_list.size() && sit != elems_list.end())
1096 sit->second.push_back(
1097 neighbor_ptr->which_neighbor_am_i(
mesh.
elem_ptr(std::get<0>(side_info))));
1101 elems_list.push_back(std::make_pair(
1103 std::vector<unsigned int>(
1104 {neighbor_ptr->which_neighbor_am_i(
mesh.
elem_ptr(std::get<0>(side_info)))})));
1109 throw MooseException(
"The provided boundary set contains C0POLYGON side elements, which " 1110 "is not supported.");
1113 "Impossible scenario: a linear non-polygon side element that is neither TRI3 " 1119 if (conversion_element_layer_number > 1)
1121 std::set<dof_id_type> total_elems_set(layered_elems_list.back());
1123 while (layered_elems_list.back().size() &&
1124 layered_elems_list.size() < conversion_element_layer_number)
1126 layered_elems_list.push_back(std::set<dof_id_type>());
1127 for (
const auto & elem_id : *(layered_elems_list.end() - 2))
1134 if (total_elems_set.find(neighbor_id) == total_elems_set.end())
1136 layered_elems_list.back().emplace(neighbor_id);
1137 total_elems_set.emplace(neighbor_id);
1146 if (layered_elems_list.back().empty())
1147 layered_elems_list.pop_back();
1149 if (conversion_element_layer_number > layered_elems_list.size())
1150 throw MooseException(
"There is fewer layers of elements in the input mesh than the requested " 1151 "number of layers to convert.");
1153 std::vector<std::pair<dof_id_type, bool>> original_elems;
1156 const unsigned int n_layer_conversion = layered_elems_list.size() - 1;
1157 for (
unsigned int i = 0; i < n_layer_conversion; ++i)
1158 for (
const auto & elem_id : layered_elems_list[i])
1164 original_elems.push_back(std::make_pair(elem_id,
false));
1171 std::vector<dof_id_type> converted_elems_ids_to_track;
1173 mesh, original_elems, converted_elems_ids_to_track, block_id_to_remove,
false);
1178 if (n_layer_conversion)
1180 for (
const auto & elem_id : layered_elems_list[n_layer_conversion])
1185 layered_elems_list[n_layer_conversion - 1].count(
1188 if (elems_list.size() && elems_list.back().first == elem_id)
1189 elems_list.back().second.push_back(i_side);
1191 elems_list.push_back(std::make_pair(elem_id, std::vector<unsigned int>({i_side})));
1198 for (
const auto & elem_info : elems_list)
1201 std::vector<std::vector<boundary_id_type>> elem_side_info(
1203 auto side_range = sideset_map.equal_range(
mesh.
elem_ptr(elem_info.first));
1204 for (
auto i = side_range.first; i != side_range.second; ++i)
1205 elem_side_info[i->second.first].push_back(i->second.second);
1208 mesh, elem_info.first, elem_info.second, elem_side_info, sid_shift_base);
1212 for (
const auto & elem_info : elems_list)
1214 for (
auto elem_it =
mesh.active_subdomain_elements_begin(block_id_to_remove);
1215 elem_it !=
mesh.active_subdomain_elements_end(block_id_to_remove);
1228 const std::set<subdomain_id_type> & original_subdomain_ids,
1230 const SubdomainName & tet_suffix,
1231 const SubdomainName & pyramid_suffix)
1233 for (
const auto & subdomain_id : original_subdomain_ids)
1237 const SubdomainName new_name =
1243 "This suffix for converted TET4 elements results in a subdomain name, " + new_name +
1244 ", that already exists in the mesh. Please choose a different suffix.");
1249 const SubdomainName new_name =
1252 '_' + pyramid_suffix;
1255 "This suffix for converted PYRAMID5 elements results in a subdomain name, " + new_name +
1256 ", that already exists in the mesh. Please choose a different suffix.");
virtual Point true_centroid() const
void remove_id(boundary_id_type id, bool global=false)
void convertPyramid5Elem(ReplicatedMesh &mesh, const dof_id_type &elem_id, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
void pyramidElemSplitter(ReplicatedMesh &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
virtual Node *& set_node(const unsigned int i)
std::vector< bool > quadFaceDiagonalDirectionsHex(const std::vector< const Node *> &hex_nodes)
virtual Order default_side_order() const
bool hasBoundaryName(const MeshBase &input_mesh, const BoundaryName &name)
Whether a particular boundary name exists in the mesh.
void nodeRotationHEX8(const unsigned int min_id_index, const unsigned int sec_min_pos, std::vector< unsigned int > &face_rotation, std::vector< unsigned int > &node_rotation)
Rotate a HEX8 element's nodes to ensure that the node with the minimum id is the first node; and the ...
std::set< std::string > sideset
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
void createUnitTet4FromHex8(ReplicatedMesh &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
void createUnitPyramid5FromPrism6(ReplicatedMesh &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
unsigned int n_elem_integers() const
bool quadFaceDiagonalDirection(const std::vector< const Node *> &quad_nodes)
void hexNodesToTetNodesDeterminer(std::vector< const Node *> &hex_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
void elementBoundaryInfoCollector(const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, const unsigned short n_elem_sides, std::vector< std::vector< boundary_id_type >> &elem_side_list)
Collect the boundary information of the given element in a mesh.
std::vector< unsigned int > neighborNodeIndicesHEX8(unsigned int min_id_index)
Calculate the indices (within the element nodes) of the three neighboring nodes of a node in a HEX8 e...
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
const BoundaryInfo & get_boundary_info() const
void convert3DMeshToAllTet4(ReplicatedMesh &mesh)
void retainEEID(ReplicatedMesh &mesh, const dof_id_type &elem_id, Elem *new_elem_ptr)
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
auto max(const L &left, const R &right)
void build_side_list(std::vector< dof_id_type > &element_id_list, std::vector< unsigned short int > &side_list, std::vector< boundary_id_type > &bc_id_list) const
bool hasSubdomainID(const MeshBase &input_mesh, const SubdomainID &id)
Whether a particular subdomain ID exists in the mesh.
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
Gets the boundary ID associated with the given BoundaryName.
std::size_t euclideanMod(T1 dividend, T2 divisor)
perform modulo operator for Euclidean division that ensures a non-negative result ...
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true)=0
std::vector< std::vector< unsigned int > > tetNodesForPrism(const bool diagonal_direction, std::vector< std::vector< unsigned int >> &tet_face_indices)
Creates sets of four nodes indices that can form TET4 elements to replace the original PRISM6 element...
virtual void delete_elem(Elem *e)=0
virtual Elem * add_elem(Elem *e)=0
void nodeRotationPRISM6(unsigned int min_id_index, std::vector< unsigned int > &face_rotation, std::vector< unsigned int > &node_rotation)
Rotate a PRISM6 element nodes to ensure that the node with the minimum id is the first node...
void subdomain_ids(std::set< subdomain_id_type > &ids, const bool global=true) const
void createUnitTet4FromPrism6(ReplicatedMesh &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
std::string & subdomain_name(subdomain_id_type id)
void nodeRotationPYRAMID5(unsigned int min_id_index, std::vector< unsigned int > &face_rotation, std::vector< unsigned int > &node_rotation)
Rotate a PYRAMID5 element nodes to ensure that the node with the minimum id is the first node for the...
void convert3DMeshToAllTet4(ReplicatedMesh &mesh, const std::vector< std::pair< dof_id_type, bool >> &elems_to_process, std::vector< dof_id_type > &converted_elems_ids_to_track, const subdomain_id_type block_id_to_remove, const bool delete_block_to_remove)
Convert all the elements in a 3D mesh, consisting of only linear elements, into TET4 elements...
const std::multimap< const Elem *, std::pair< unsigned short int, boundary_id_type > > & get_sideset_map() const
bool hasSubdomainName(const MeshBase &input_mesh, const SubdomainName &name)
Whether a particular subdomain name exists in the mesh.
void convertElem(ReplicatedMesh &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
virtual const Elem * elem_ptr(const dof_id_type i) const=0
virtual unsigned int n_sides() const=0
const Elem * neighbor_ptr(unsigned int i) const
Provides a way for users to bail out of the current solve.
void prismElemSplitter(ReplicatedMesh &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
void assignConvertedElementsSubdomainNameSuffix(ReplicatedMesh &mesh, const std::set< subdomain_id_type > &original_subdomain_ids, const subdomain_id_type sid_shift_base, const SubdomainName &tet_suffix, const SubdomainName &pyramid_suffix)
virtual bool contract()=0
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
subdomain_id_type subdomain_id() const
const Node * node_ptr(const unsigned int i) const
void pyramidNodesToTetNodesDeterminer(std::vector< const Node *> &pyramid_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
void hexElemSplitter(ReplicatedMesh &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
void convertPrism6Elem(ReplicatedMesh &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
IntRange< T > make_range(T beg, T end)
void convertHex8Elem(ReplicatedMesh &mesh, const dof_id_type &elem_id, const std::vector< unsigned int > &side_indices, const std::vector< std::vector< boundary_id_type >> &elem_side_info, const SubdomainID &subdomain_id_shift_base)
std::vector< std::vector< unsigned int > > tetNodesForHex(const std::vector< bool > diagonal_directions, std::vector< std::vector< unsigned int >> &tet_face_indices)
Creates sets of four nodes indices that can form TET4 elements to replace the original HEX8 element...
void changeBoundaryId(MeshBase &mesh, const libMesh::boundary_id_type old_id, const libMesh::boundary_id_type new_id, bool delete_prev)
Changes the old boundary ID to a new ID in the mesh.
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
void prismNodesToTetNodesDeterminer(std::vector< const Node *> &prism_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
BoundaryID getNextFreeBoundaryID(MeshBase &input_mesh)
Checks input mesh and returns the largest boundary ID in the mesh plus one, which is a boundary ID in...
void createUnitPyramid5FromHex8(ReplicatedMesh &mesh, const dof_id_type &elem_id, const unsigned int &side_index, const Node *new_node, const std::vector< boundary_id_type > &side_info, const SubdomainID &subdomain_id_shift_base)
virtual ElemType type() const=0
auto index_range(const T &sizable)
void set_extra_integer(const unsigned int index, const dof_id_type value)
void transitionLayerGenerator(ReplicatedMesh &mesh, const std::vector< BoundaryName > &boundary_names, const unsigned int conversion_element_layer_number, const bool external_boundaries_checking)
dof_id_type get_extra_integer(const unsigned int index) const