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)
592 "This method only supports serial meshes. If you are calling this method with a " 593 "distributed mesh, please serialize it first.");
594 std::vector<dof_id_type> converted_elems_ids_to_retain;
598 for (
const auto & elem_to_process : elems_to_process)
605 elem_to_process.first,
606 elem_to_process.second ? converted_elems_ids_to_track
607 : converted_elems_ids_to_retain);
610 case ElemType::PYRAMID5:
613 elem_to_process.first,
614 elem_to_process.second ? converted_elems_ids_to_track
615 : converted_elems_ids_to_retain);
618 case ElemType::PRISM6:
621 elem_to_process.first,
622 elem_to_process.second ? converted_elems_ids_to_track
623 : converted_elems_ids_to_retain);
627 if (elem_to_process.second)
628 converted_elems_ids_to_track.push_back(elem_to_process.first);
630 converted_elems_ids_to_retain.push_back(elem_to_process.first);
637 if (delete_block_to_remove)
639 for (
auto elem_it =
mesh.active_subdomain_elements_begin(block_id_to_remove);
640 elem_it !=
mesh.active_subdomain_elements_end(block_id_to_remove);
653 "This method only supports serial meshes. If you are calling this method with a " 654 "distributed mesh, please serialize it first.");
656 std::set<subdomain_id_type> subdomain_ids_set;
660 std::vector<std::pair<dof_id_type, bool>> original_elems;
662 for (
auto elem_it =
mesh.active_elements_begin(); elem_it !=
mesh.active_elements_end();
665 if ((*elem_it)->default_order() != Order::FIRST)
666 mooseError(
"Only first order elements are supported for cutting.");
667 original_elems.push_back(std::make_pair((*elem_it)->id(),
false));
670 std::vector<dof_id_type> converted_elems_ids_to_track;
673 mesh, original_elems, converted_elems_ids_to_track, block_id_to_remove,
true);
679 const unsigned short n_elem_sides,
680 std::vector<std::vector<boundary_id_type>> & elem_side_list)
682 elem_side_list.resize(n_elem_sides);
683 const auto selected_bdry_side_list =
684 std::equal_range(bdry_side_list.begin(), bdry_side_list.end(), elem_id,
BCTupleKeyComp{});
685 for (
auto selected_bdry_side = selected_bdry_side_list.first;
686 selected_bdry_side != selected_bdry_side_list.second;
687 ++selected_bdry_side)
689 elem_side_list[std::get<1>(*selected_bdry_side)].push_back(std::get<2>(*selected_bdry_side));
696 const std::vector<unsigned int> & side_indices,
697 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
719 "The provided element type '" + std::to_string(elem_type) +
720 "' is not supported and is not supposed to be passed to this function. " 721 "Only HEX8, PRISM6 and PYRAMID5 are supported.");
728 const std::vector<unsigned int> & side_indices,
729 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
740 if (
std::find(side_indices.begin(), side_indices.end(), i_side) != side_indices.end())
742 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
745 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
752 const unsigned int & side_index,
753 const Node * new_node,
754 const std::vector<boundary_id_type> & side_info,
757 auto new_elem = std::make_unique<Pyramid5>();
762 new_elem->set_node(4, const_cast<Node *>(new_node));
766 for (
const auto & bid : side_info)
773 const unsigned int & side_index,
774 const Node * new_node,
775 const std::vector<boundary_id_type> & side_info,
780 unsigned int lid_index = 0;
788 auto new_elem_0 = std::make_unique<Tet4>();
789 new_elem_0->set_node(0,
793 new_elem_0->set_node(1,
797 new_elem_0->set_node(2,
801 new_elem_0->set_node(3, const_cast<Node *>(new_node));
803 auto new_elem_ptr_0 =
mesh.
add_elem(std::move(new_elem_0));
806 auto new_elem_1 = std::make_unique<Tet4>();
807 new_elem_1->set_node(0,
811 new_elem_1->set_node(1,
815 new_elem_1->set_node(2,
819 new_elem_1->set_node(3, const_cast<Node *>(new_node));
821 auto new_elem_ptr_1 =
mesh.
add_elem(std::move(new_elem_1));
824 for (
const auto & bid : side_info)
834 const std::vector<unsigned int> & side_indices,
835 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
845 if (i_side % 4 == 0 ||
846 std::find(side_indices.begin(), side_indices.end(), i_side) != side_indices.end())
848 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
851 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
858 const unsigned int & side_index,
859 const Node * new_node,
860 const std::vector<boundary_id_type> & side_info,
867 bool is_side_quad = (side_index % 4 != 0);
868 unsigned int lid_index = 0;
877 auto new_elem_0 = std::make_unique<Tet4>();
878 new_elem_0->set_node(0,
882 new_elem_0->set_node(1,
886 new_elem_0->set_node(2,
890 new_elem_0->set_node(3, const_cast<Node *>(new_node));
892 auto new_elem_ptr_0 =
mesh.
add_elem(std::move(new_elem_0));
895 Elem * new_elem_ptr_1 =
nullptr;
898 auto new_elem_1 = std::make_unique<Tet4>();
903 new_elem_1->set_node(1,
907 new_elem_1->set_node(2,
911 new_elem_1->set_node(3, const_cast<Node *>(new_node));
917 for (
const auto & bid : side_info)
928 const unsigned int & side_index,
929 const Node * new_node,
930 const std::vector<boundary_id_type> & side_info,
935 mesh, elem_id, side_index, new_node, side_info, subdomain_id_shift_base);
941 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
945 unsigned int lid_index = 0;
952 auto new_elem_0 = std::make_unique<Tet4>();
953 new_elem_0->set_node(
956 new_elem_0->set_node(
959 new_elem_0->set_node(
964 auto new_elem_ptr_0 =
mesh.
add_elem(std::move(new_elem_0));
967 auto new_elem_1 = std::make_unique<Tet4>();
968 new_elem_1->set_node(
971 new_elem_1->set_node(
974 new_elem_1->set_node(
979 auto new_elem_ptr_1 =
mesh.
add_elem(std::move(new_elem_1));
982 for (
const auto & bid : elem_side_info[0])
984 for (
const auto & bid : elem_side_info[1])
989 for (
const auto & bid : elem_side_info[2])
991 for (
const auto & bid : elem_side_info[3])
996 for (
const auto & bid : elem_side_info[4])
1013 const std::vector<BoundaryName> & boundary_names,
1014 const unsigned int conversion_element_layer_number,
1015 const bool external_boundaries_checking)
1018 "This method only supports serial meshes. If you are calling this method with a " 1019 "distributed mesh, please serialize it first.");
1031 std::vector<boundary_id_type> boundary_ids;
1032 for (
const auto &
sideset : boundary_names)
1043 std::vector<std::pair<dof_id_type, std::vector<unsigned int>>> elems_list;
1044 std::vector<std::set<dof_id_type>> layered_elems_list;
1045 layered_elems_list.push_back(std::set<dof_id_type>());
1049 for (
const auto & side_info : side_list)
1051 if (std::get<2>(side_info) == uniform_tmp_bid)
1061 "The provided boundary set contains non-linear side elements, which is not supported.");
1062 const auto side_type =
1064 layered_elems_list.back().emplace(std::get<0>(side_info));
1068 const auto neighbor_ptr =
1072 if (external_boundaries_checking)
1074 "The provided boundary contains non-external sides, which is required when " 1075 "external_boundaries_checking is enabled.");
1077 layered_elems_list.back().emplace(neighbor_ptr->id());
1080 if (conversion_element_layer_number == 1)
1082 if (side_type ==
TRI3)
1084 else if (side_type ==
QUAD4)
1086 auto pit = std::find_if(elems_list.begin(),
1088 [elem_id = std::get<0>(side_info)](
const auto & p)
1089 {
return p.first == elem_id; });
1090 if (elems_list.size() && pit != elems_list.end())
1092 pit->second.push_back(std::get<1>(side_info));
1095 elems_list.push_back(std::make_pair(
1096 std::get<0>(side_info), std::vector<unsigned int>({std::get<1>(side_info)})));
1099 auto sit = std::find_if(elems_list.begin(),
1101 [elem_id = neighbor_ptr->id()](
const auto & p)
1102 {
return p.first == elem_id; });
1103 if (elems_list.size() && sit != elems_list.end())
1105 sit->second.push_back(
1106 neighbor_ptr->which_neighbor_am_i(
mesh.
elem_ptr(std::get<0>(side_info))));
1110 elems_list.push_back(std::make_pair(
1112 std::vector<unsigned int>(
1113 {neighbor_ptr->which_neighbor_am_i(
mesh.
elem_ptr(std::get<0>(side_info)))})));
1118 throw MooseException(
"The provided boundary set contains C0POLYGON side elements, which " 1119 "is not supported.");
1122 "Impossible scenario: a linear non-polygon side element that is neither TRI3 " 1128 if (conversion_element_layer_number > 1)
1130 std::set<dof_id_type> total_elems_set(layered_elems_list.back());
1132 while (layered_elems_list.back().size() &&
1133 layered_elems_list.size() < conversion_element_layer_number)
1135 layered_elems_list.push_back(std::set<dof_id_type>());
1136 for (
const auto & elem_id : *(layered_elems_list.end() - 2))
1143 if (total_elems_set.find(neighbor_id) == total_elems_set.end())
1145 layered_elems_list.back().emplace(neighbor_id);
1146 total_elems_set.emplace(neighbor_id);
1155 if (layered_elems_list.back().empty())
1156 layered_elems_list.pop_back();
1158 if (conversion_element_layer_number > layered_elems_list.size())
1159 throw MooseException(
"There is fewer layers of elements in the input mesh than the requested " 1160 "number of layers to convert.");
1162 std::vector<std::pair<dof_id_type, bool>> original_elems;
1165 const unsigned int n_layer_conversion = layered_elems_list.size() - 1;
1166 for (
unsigned int i = 0; i < n_layer_conversion; ++i)
1167 for (
const auto & elem_id : layered_elems_list[i])
1173 original_elems.push_back(std::make_pair(elem_id,
false));
1180 std::vector<dof_id_type> converted_elems_ids_to_track;
1182 mesh, original_elems, converted_elems_ids_to_track, block_id_to_remove,
false);
1187 if (n_layer_conversion)
1189 for (
const auto & elem_id : layered_elems_list[n_layer_conversion])
1194 layered_elems_list[n_layer_conversion - 1].count(
1197 if (elems_list.size() && elems_list.back().first == elem_id)
1198 elems_list.back().second.push_back(i_side);
1200 elems_list.push_back(std::make_pair(elem_id, std::vector<unsigned int>({i_side})));
1207 for (
const auto & elem_info : elems_list)
1210 std::vector<std::vector<boundary_id_type>> elem_side_info(
1212 auto side_range = sideset_map.equal_range(
mesh.
elem_ptr(elem_info.first));
1213 for (
auto i = side_range.first; i != side_range.second; ++i)
1214 elem_side_info[i->second.first].push_back(i->second.second);
1217 mesh, elem_info.first, elem_info.second, elem_side_info, sid_shift_base);
1221 for (
const auto & elem_info : elems_list)
1223 for (
auto elem_it =
mesh.active_subdomain_elements_begin(block_id_to_remove);
1224 elem_it !=
mesh.active_subdomain_elements_end(block_id_to_remove);
1237 const std::set<subdomain_id_type> & original_subdomain_ids,
1239 const SubdomainName & tet_suffix,
1240 const SubdomainName & pyramid_suffix)
1242 for (
const auto & subdomain_id : original_subdomain_ids)
1246 const SubdomainName new_name =
1252 "This suffix for converted TET4 elements results in a subdomain name, " + new_name +
1253 ", that already exists in the mesh. Please choose a different suffix.");
1258 const SubdomainName new_name =
1261 '_' + pyramid_suffix;
1264 "This suffix for converted PYRAMID5 elements results in a subdomain name, " + new_name +
1265 ", that already exists in the mesh. Please choose a different suffix.");
virtual Point true_centroid() const
void assignConvertedElementsSubdomainNameSuffix(MeshBase &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)
void remove_id(boundary_id_type id, bool global=false)
void createUnitPyramid5FromHex8(MeshBase &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)
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
void convert3DMeshToAllTet4(MeshBase &mesh)
void createUnitTet4FromHex8(MeshBase &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 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 prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
void createUnitPyramid5FromPrism6(MeshBase &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)
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...
void convertHex8Elem(MeshBase &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)
const BoundaryInfo & get_boundary_info() const
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
void prismElemSplitter(MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
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 bool is_serial() const
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...
void convert3DMeshToAllTet4(MeshBase &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...
virtual void delete_elem(Elem *e)=0
void retainEEID(MeshBase &mesh, const dof_id_type &elem_id, Elem *new_elem_ptr)
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
std::string & subdomain_name(subdomain_id_type id)
void createUnitTet4FromPrism6(MeshBase &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 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 convertPyramid5Elem(MeshBase &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 hexElemSplitter(MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
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.
virtual const Elem * elem_ptr(const dof_id_type i) const=0
void convertElem(MeshBase &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 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.
virtual bool contract()=0
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
void pyramidElemSplitter(MeshBase &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, std::vector< dof_id_type > &converted_elems_ids)
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 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 convertPrism6Elem(MeshBase &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...
virtual ElemType type() const=0
void transitionLayerGenerator(MeshBase &mesh, const std::vector< BoundaryName > &boundary_names, const unsigned int conversion_element_layer_number, const bool external_boundaries_checking)
auto index_range(const T &sizable)
void set_extra_integer(const unsigned int index, const dof_id_type value)
dof_id_type get_extra_integer(const unsigned int index) const