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" 26 #include "libmesh/cell_c0polyhedron.h" 34 const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
36 std::vector<dof_id_type> & converted_elems_ids)
41 std::vector<std::vector<boundary_id_type>> elem_side_list;
42 elem_side_list.resize(6);
46 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
48 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
51 std::vector<std::vector<unsigned int>> opt_option;
60 std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
62 std::vector<std::vector<const Node *>> optimized_node_list;
65 std::vector<Elem *> elems_Tet4;
66 for (
const auto i :
index_range(optimized_node_list))
68 auto new_elem = std::make_unique<Tet4>();
69 new_elem->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
70 new_elem->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
71 new_elem->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
72 new_elem->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
74 elems_Tet4.push_back(
mesh.
add_elem(std::move(new_elem)));
75 converted_elems_ids.push_back(elems_Tet4.back()->id());
77 for (
unsigned int j = 0; j < 4; j++)
82 if (rotated_tet_face_indices[i][j] < 6)
84 for (
const auto & side_info : elem_side_list[rotated_tet_face_indices[i][j]])
85 boundary_info.
add_side(elems_Tet4.back(), j, side_info);
91 for (
unsigned int i = 0; i < 6; i++)
92 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
94 elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
100 const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
102 std::vector<dof_id_type> & converted_elems_ids)
107 std::vector<std::vector<boundary_id_type>> elem_side_list;
111 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
114 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
123 std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
124 std::vector<std::vector<const Node *>> optimized_node_list;
127 std::vector<Elem *> elems_Tet4;
128 for (
const auto i :
index_range(optimized_node_list))
130 auto new_elem = std::make_unique<Tet4>();
131 new_elem->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
132 new_elem->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
133 new_elem->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
134 new_elem->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
136 elems_Tet4.push_back(
mesh.
add_elem(std::move(new_elem)));
137 converted_elems_ids.push_back(elems_Tet4.back()->id());
139 for (
unsigned int j = 0; j < 4; j++)
144 if (rotated_tet_face_indices[i][j] < 5)
146 for (
const auto & side_info : elem_side_list[rotated_tet_face_indices[i][j]])
147 boundary_info.
add_side(elems_Tet4.back(), j, side_info);
153 for (
unsigned int i = 0; i < 3; i++)
154 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
156 elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
162 const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
164 std::vector<dof_id_type> & converted_elems_ids)
169 std::vector<std::vector<boundary_id_type>> elem_side_list;
173 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
175 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
183 std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
184 std::vector<std::vector<const Node *>> optimized_node_list;
187 std::vector<Elem *> elems_Tet4;
188 for (
const auto i :
index_range(optimized_node_list))
190 auto new_elem = std::make_unique<Tet4>();
191 new_elem->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
192 new_elem->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
193 new_elem->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
194 new_elem->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
196 elems_Tet4.push_back(
mesh.
add_elem(std::move(new_elem)));
197 converted_elems_ids.push_back(elems_Tet4.back()->id());
199 for (
unsigned int j = 0; j < 4; j++)
204 if (rotated_tet_face_indices[i][j] < 5)
206 for (
const auto & side_info : elem_side_list[rotated_tet_face_indices[i][j]])
207 boundary_info.
add_side(elems_Tet4.back(), j, side_info);
213 for (
unsigned int i = 0; i < 2; i++)
214 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
216 elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
222 const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
224 std::vector<dof_id_type> & converted_elems_ids)
230 std::vector<std::vector<boundary_id_type>> elem_side_list;
234 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
237 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
238 exist_extra_ids[j] = elem->get_extra_integer(j);
242 Node * v_avg_node =
nullptr;
244 if (dynamic_cast<C0Polyhedron *>(elem))
248 std::vector<Elem *> elems_Tet4;
251 const auto tri_indices =
poly->subelement(tri_i);
253 auto new_elem = std::make_unique<Tet4>();
255 if (tri_indices[i] >= 0)
256 new_elem->set_node(i, const_cast<Node *>(elem->node_ptr(tri_indices[i])));
258 new_elem->set_node(i, v_avg_node);
260 new_elem->subdomain_id() = elem->subdomain_id();
261 elems_Tet4.push_back(
mesh.
add_elem(std::move(new_elem)));
262 converted_elems_ids.push_back(elems_Tet4.back()->id());
265 const auto tet_face_indices =
poly->subelement_sides_to_poly_sides(tri_i);
268 for (
unsigned int j = 0; j < 4; j++)
269 if (tet_face_indices[j] <
int(elem->n_sides()))
270 for (
const auto & side_info : elem_side_list[tet_face_indices[j]])
271 boundary_info.
add_side(elems_Tet4.back(), j, side_info);
276 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
277 elems_Tet4[i]->set_extra_integer(j, exist_extra_ids[j]);
280 std::vector<unsigned int>
283 const std::vector<std::vector<unsigned int>> preset_indices = {
284 {1, 3, 4}, {0, 2, 5}, {3, 1, 6}, {2, 0, 7}, {5, 7, 0}, {4, 6, 1}, {7, 5, 2}, {6, 4, 3}};
285 if (min_id_index > 7)
286 mooseError(
"The input node index is out of range.");
288 return preset_indices[min_id_index];
293 std::vector<std::vector<unsigned int>> & rotated_tet_face_indices,
294 std::vector<std::vector<const Node *>> & tet_nodes_list)
297 std::vector<dof_id_type> node_ids(8);
298 for (
unsigned int i = 0; i < 8; i++)
299 node_ids[i] = hex_nodes[i]->
id();
301 const unsigned int min_node_id_index = std::distance(
302 std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
308 const auto neighbor_node_ids = {node_ids[neighbor_node_indices[0]],
309 node_ids[neighbor_node_indices[1]],
310 node_ids[neighbor_node_indices[2]]};
311 const unsigned int sec_min_pos =
312 std::distance(std::begin(neighbor_node_ids),
313 std::min_element(std::begin(neighbor_node_ids), std::end(neighbor_node_ids)));
319 std::vector<unsigned int> face_rotation;
320 std::vector<unsigned int> rotated_indices;
321 nodeRotationHEX8(min_node_id_index, sec_min_pos, face_rotation, rotated_indices);
322 std::vector<const Node *> rotated_hex_nodes;
323 for (
unsigned int i = 0; i < 8; i++)
324 rotated_hex_nodes.push_back(hex_nodes[rotated_indices[i]]);
331 std::vector<std::vector<unsigned int>> tet_face_indices;
332 const auto tet_nodes_set =
tetNodesForHex(diagonal_directions, tet_face_indices);
333 for (
const auto & tet_face_index : tet_face_indices)
335 rotated_tet_face_indices.push_back(std::vector<unsigned int>());
336 for (
const auto & face_index : tet_face_index)
339 rotated_tet_face_indices.back().push_back(face_rotation[face_index]);
341 rotated_tet_face_indices.back().push_back(6);
345 for (
const auto & tet_nodes : tet_nodes_set)
347 tet_nodes_list.push_back(std::vector<const Node *>());
348 for (
const auto & tet_node : tet_nodes)
349 tet_nodes_list.back().push_back(rotated_hex_nodes[tet_node]);
357 const std::vector<std::vector<unsigned int>> face_indices = {
358 {0, 1, 2, 3}, {4, 5, 6, 7}, {0, 1, 5, 4}, {2, 3, 7, 6}, {1, 2, 6, 5}, {3, 0, 4, 7}};
359 std::vector<bool> diagonal_directions;
360 for (
const auto & face_index : face_indices)
362 std::vector<const Node *> quad_nodes = {hex_nodes[face_index[0]],
363 hex_nodes[face_index[1]],
364 hex_nodes[face_index[2]],
365 hex_nodes[face_index[3]]};
368 return diagonal_directions;
374 const std::vector<dof_id_type> node_ids = {
375 quad_nodes[0]->id(), quad_nodes[1]->id(), quad_nodes[2]->id(), quad_nodes[3]->id()};
376 const unsigned int min_id_index = std::distance(
377 std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
378 if (min_id_index == 0 || min_id_index == 2)
384 std::vector<std::vector<unsigned int>>
386 std::vector<std::vector<unsigned int>> & tet_face_indices)
388 const std::vector<std::vector<bool>> possible_inputs = {{
true,
true,
true,
true,
true,
false},
389 {
true,
true,
true,
true,
false,
false},
390 {
true,
true,
true,
false,
true,
false},
391 {
true,
false,
true,
true,
true,
false},
392 {
true,
false,
true,
true,
false,
false},
393 {
true,
false,
true,
false,
true,
false},
394 {
true,
false,
true,
false,
false,
false}};
396 const unsigned int input_index = std::distance(
397 std::begin(possible_inputs),
398 std::find(std::begin(possible_inputs), std::end(possible_inputs), diagonal_directions));
404 {0, 6, 2, 6}, {1, 6, 2, 6}, {1, 6, 5, 6}, {0, 6, 3, 4}, {6, 6, 3, 6}, {6, 4, 5, 6}};
405 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}};
408 {0, 1, 2, 6}, {6, 6, 2, 6}, {6, 6, 5, 1}, {0, 6, 3, 4}, {6, 6, 3, 6}, {6, 4, 5, 6}};
409 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}};
412 {0, 6, 2, 6}, {1, 6, 2, 6}, {1, 6, 5, 6}, {4, 6, 5, 6}, {4, 6, 3, 6}, {0, 6, 3, 6}};
413 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}};
416 {4, 6, 5, 1}, {6, 6, 5, 6}, {6, 1, 2, 6}, {4, 0, 3, 6}, {6, 6, 3, 6}, {6, 6, 2, 0}};
417 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}};
419 tet_face_indices = {{0, 1, 2, 6}, {0, 6, 3, 4}, {5, 4, 6, 1}, {5, 6, 3, 2}, {6, 6, 6, 6}};
420 return {{0, 1, 2, 5}, {0, 2, 3, 7}, {4, 7, 5, 0}, {5, 7, 6, 2}, {0, 2, 7, 5}};
423 {4, 6, 5, 1}, {6, 6, 5, 6}, {6, 1, 2, 6}, {2, 6, 6, 0}, {3, 6, 6, 0}, {3, 6, 6, 4}};
424 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}};
427 {1, 4, 5, 6}, {6, 6, 5, 6}, {6, 6, 3, 4}, {1, 6, 2, 0}, {6, 6, 2, 6}, {6, 0, 3, 6}};
428 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}};
436 const unsigned int sec_min_pos,
437 std::vector<unsigned int> & face_rotation,
438 std::vector<unsigned int> & node_rotation)
444 const std::vector<std::vector<std::vector<unsigned int>>> preset_indices = {
445 {{0, 1, 2, 3, 4, 5, 6, 7}, {0, 3, 7, 4, 1, 2, 6, 5}, {0, 4, 5, 1, 3, 7, 6, 2}},
446 {{1, 0, 4, 5, 2, 3, 7, 6}, {1, 2, 3, 0, 5, 6, 7, 4}, {1, 5, 6, 2, 0, 4, 7, 3}},
447 {{2, 3, 0, 1, 6, 7, 4, 5}, {2, 1, 5, 6, 3, 0, 4, 7}, {2, 6, 7, 3, 1, 5, 4, 0}},
448 {{3, 2, 6, 7, 0, 1, 5, 4}, {3, 0, 1, 2, 7, 4, 5, 6}, {3, 7, 4, 0, 2, 6, 5, 1}},
449 {{4, 5, 1, 0, 7, 6, 2, 3}, {4, 7, 6, 5, 0, 3, 2, 1}, {4, 0, 3, 7, 5, 1, 2, 6}},
450 {{5, 4, 7, 6, 1, 0, 3, 2}, {5, 6, 2, 1, 4, 7, 3, 0}, {5, 1, 0, 4, 6, 2, 3, 7}},
451 {{6, 7, 3, 2, 5, 4, 0, 1}, {6, 5, 4, 7, 2, 1, 0, 3}, {6, 2, 1, 5, 7, 3, 0, 4}},
452 {{7, 6, 5, 4, 3, 2, 1, 0}, {7, 4, 0, 3, 6, 5, 1, 2}, {7, 3, 2, 6, 4, 0, 1, 5}}};
454 const std::vector<std::vector<std::vector<unsigned int>>> preset_face_indices = {
455 {{0, 1, 2, 3, 4, 5}, {4, 0, 3, 5, 1, 2}, {1, 4, 5, 2, 0, 3}},
456 {{1, 0, 4, 5, 2, 3}, {0, 2, 3, 4, 1, 5}, {2, 1, 5, 3, 0, 4}},
457 {{0, 3, 4, 1, 2, 5}, {2, 0, 1, 5, 3, 4}, {3, 2, 5, 4, 0, 1}},
458 {{3, 0, 2, 5, 4, 1}, {0, 4, 1, 2, 3, 5}, {4, 3, 5, 1, 0, 2}},
459 {{1, 5, 2, 0, 4, 3}, {5, 4, 3, 2, 1, 0}, {4, 1, 0, 3, 5, 2}},
460 {{5, 1, 4, 3, 2, 0}, {2, 5, 3, 0, 1, 4}, {1, 2, 0, 4, 5, 3}},
461 {{3, 5, 4, 0, 2, 1}, {5, 2, 1, 4, 3, 0}, {2, 3, 0, 1, 5, 4}},
462 {{5, 3, 2, 1, 4, 0}, {4, 5, 1, 0, 3, 2}, {3, 4, 0, 2, 5, 1}}};
464 if (min_id_index > 7 || sec_min_pos > 2)
465 mooseError(
"The input node index is out of range.");
469 face_rotation = preset_face_indices[min_id_index][sec_min_pos];
470 node_rotation = preset_indices[min_id_index][sec_min_pos];
476 std::vector<unsigned int> & face_rotation,
477 std::vector<unsigned int> & node_rotation)
479 const std::vector<std::vector<unsigned int>> preset_indices = {{0, 1, 2, 3, 4, 5},
486 const std::vector<std::vector<unsigned int>> preset_face_indices = {{0, 1, 2, 3, 4},
493 if (min_id_index > 5)
494 mooseError(
"The input node index is out of range.");
498 face_rotation = preset_face_indices[min_id_index];
499 node_rotation = preset_indices[min_id_index];
505 std::vector<std::vector<unsigned int>> & rotated_tet_face_indices,
506 std::vector<std::vector<const Node *>> & tet_nodes_list)
509 std::vector<dof_id_type> node_ids(6);
510 for (
unsigned int i = 0; i < 6; i++)
511 node_ids[i] = prism_nodes[i]->
id();
513 const unsigned int min_node_id_index = std::distance(
514 std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
519 std::vector<unsigned int> face_rotation;
520 std::vector<unsigned int> rotated_indices;
522 std::vector<const Node *> rotated_prism_nodes;
523 for (
unsigned int i = 0; i < 6; i++)
524 rotated_prism_nodes.push_back(prism_nodes[rotated_indices[i]]);
526 std::vector<const Node *> key_quad_nodes = {rotated_prism_nodes[1],
527 rotated_prism_nodes[2],
528 rotated_prism_nodes[5],
529 rotated_prism_nodes[4]};
536 std::vector<std::vector<unsigned int>> tet_face_indices;
537 const auto tet_nodes_set =
tetNodesForPrism(diagonal_direction, tet_face_indices);
538 for (
const auto & tet_face_index : tet_face_indices)
540 rotated_tet_face_indices.push_back(std::vector<unsigned int>());
541 for (
const auto & face_index : tet_face_index)
544 rotated_tet_face_indices.back().push_back(face_rotation[face_index]);
546 rotated_tet_face_indices.back().push_back(5);
550 for (
const auto & tet_nodes : tet_nodes_set)
552 tet_nodes_list.push_back(std::vector<const Node *>());
553 for (
const auto & tet_node : tet_nodes)
554 tet_nodes_list.back().push_back(rotated_prism_nodes[tet_node]);
558 std::vector<std::vector<unsigned int>>
560 std::vector<std::vector<unsigned int>> & tet_face_indices)
563 if (diagonal_direction)
565 tet_face_indices = {{4, 3, 5, 1}, {2, 1, 5, 5}, {2, 5, 3, 0}};
566 return {{3, 5, 4, 0}, {1, 4, 5, 0}, {1, 5, 2, 0}};
570 tet_face_indices = {{4, 3, 5, 1}, {2, 1, 5, 0}, {2, 5, 5, 3}};
571 return {{3, 5, 4, 0}, {1, 4, 2, 0}, {2, 4, 5, 0}};
577 std::vector<unsigned int> & face_rotation,
578 std::vector<unsigned int> & node_rotation)
580 const std::vector<std::vector<unsigned int>> preset_indices = {
581 {0, 1, 2, 3, 4}, {1, 2, 3, 0, 4}, {2, 3, 0, 1, 4}, {3, 0, 1, 2, 4}};
583 const std::vector<std::vector<unsigned int>> preset_face_indices = {
584 {0, 1, 2, 3, 4}, {1, 2, 3, 0, 4}, {2, 3, 0, 1, 4}, {3, 0, 1, 2, 4}};
586 if (min_id_index > 3)
587 mooseError(
"The input node index is out of range.");
591 face_rotation = preset_face_indices[min_id_index];
592 node_rotation = preset_indices[min_id_index];
598 std::vector<std::vector<unsigned int>> & rotated_tet_face_indices,
599 std::vector<std::vector<const Node *>> & tet_nodes_list)
602 std::vector<dof_id_type> node_ids(4);
603 for (
unsigned int i = 0; i < 4; i++)
604 node_ids[i] = pyramid_nodes[i]->
id();
606 const unsigned int min_node_id_index = std::distance(
607 std::begin(node_ids), std::min_element(std::begin(node_ids), std::end(node_ids)));
612 std::vector<unsigned int> face_rotation;
613 std::vector<unsigned int> rotated_indices;
615 std::vector<const Node *> rotated_pyramid_nodes;
616 for (
unsigned int i = 0; i < 5; i++)
617 rotated_pyramid_nodes.push_back(pyramid_nodes[rotated_indices[i]]);
620 const std::vector<std::vector<unsigned int>> tet_nodes_set = {{0, 1, 2, 4}, {0, 2, 3, 4}};
621 const std::vector<std::vector<unsigned int>> tet_face_indices = {{4, 0, 1, 5}, {4, 5, 2, 3}};
625 for (
const auto & tet_face_index : tet_face_indices)
627 rotated_tet_face_indices.push_back(std::vector<unsigned int>());
628 for (
const auto & face_index : tet_face_index)
631 rotated_tet_face_indices.back().push_back(face_rotation[face_index]);
633 rotated_tet_face_indices.back().push_back(5);
637 for (
const auto & tet_nodes : tet_nodes_set)
639 tet_nodes_list.push_back(std::vector<const Node *>());
640 for (
const auto & tet_node : tet_nodes)
641 tet_nodes_list.back().push_back(rotated_pyramid_nodes[tet_node]);
647 const std::vector<std::pair<dof_id_type, bool>> & elems_to_process,
648 std::vector<dof_id_type> & converted_elems_ids_to_track,
650 const bool delete_block_to_remove)
653 "This method only supports serial meshes. If you are calling this method with a " 654 "distributed mesh, please serialize it first.");
655 std::vector<dof_id_type> converted_elems_ids_to_retain;
659 for (
const auto & elem_to_process : elems_to_process)
666 elem_to_process.first,
667 elem_to_process.second ? converted_elems_ids_to_track
668 : converted_elems_ids_to_retain);
671 case ElemType::PYRAMID5:
674 elem_to_process.first,
675 elem_to_process.second ? converted_elems_ids_to_track
676 : converted_elems_ids_to_retain);
679 case ElemType::PRISM6:
682 elem_to_process.first,
683 elem_to_process.second ? converted_elems_ids_to_track
684 : converted_elems_ids_to_retain);
687 case ElemType::C0POLYHEDRON:
690 elem_to_process.first,
691 elem_to_process.second ? converted_elems_ids_to_track
692 : converted_elems_ids_to_retain);
696 if (elem_to_process.second)
697 converted_elems_ids_to_track.push_back(elem_to_process.first);
699 converted_elems_ids_to_retain.push_back(elem_to_process.first);
706 if (delete_block_to_remove)
708 for (
auto elem_it =
mesh.active_subdomain_elements_begin(block_id_to_remove);
709 elem_it !=
mesh.active_subdomain_elements_end(block_id_to_remove);
722 "This method only supports serial meshes. If you are calling this method with a " 723 "distributed mesh, please serialize it first.");
725 std::set<subdomain_id_type> subdomain_ids_set;
729 std::vector<std::pair<dof_id_type, bool>> original_elems;
731 for (
auto elem_it =
mesh.active_elements_begin(); elem_it !=
mesh.active_elements_end();
734 if ((*elem_it)->default_order() != Order::FIRST)
735 mooseError(
"Only first order elements are supported for cutting.");
736 original_elems.push_back(std::make_pair((*elem_it)->id(),
false));
739 std::vector<dof_id_type> converted_elems_ids_to_track;
742 mesh, original_elems, converted_elems_ids_to_track, block_id_to_remove,
true);
748 const unsigned short n_elem_sides,
749 std::vector<std::vector<boundary_id_type>> & elem_side_list)
751 elem_side_list.resize(n_elem_sides);
752 const auto selected_bdry_side_list =
753 std::equal_range(bdry_side_list.begin(), bdry_side_list.end(), elem_id,
BCTupleKeyComp{});
754 for (
auto selected_bdry_side = selected_bdry_side_list.first;
755 selected_bdry_side != selected_bdry_side_list.second;
756 ++selected_bdry_side)
758 elem_side_list[std::get<1>(*selected_bdry_side)].push_back(std::get<2>(*selected_bdry_side));
765 const std::vector<unsigned int> & side_indices,
766 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
788 "The provided element type '" + std::to_string(elem_type) +
789 "' is not supported and is not supposed to be passed to this function. " 790 "Only HEX8, PRISM6 and PYRAMID5 are supported.");
797 const std::vector<unsigned int> & side_indices,
798 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
809 if (
std::find(side_indices.begin(), side_indices.end(), i_side) != side_indices.end())
811 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
814 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
821 const unsigned int & side_index,
822 const Node * new_node,
823 const std::vector<boundary_id_type> & side_info,
826 auto new_elem = std::make_unique<Pyramid5>();
831 new_elem->set_node(4, const_cast<Node *>(new_node));
835 for (
const auto & bid : side_info)
842 const unsigned int & side_index,
843 const Node * new_node,
844 const std::vector<boundary_id_type> & side_info,
849 unsigned int lid_index = 0;
857 auto new_elem_0 = std::make_unique<Tet4>();
858 new_elem_0->set_node(0,
862 new_elem_0->set_node(1,
866 new_elem_0->set_node(2,
870 new_elem_0->set_node(3, const_cast<Node *>(new_node));
872 auto new_elem_ptr_0 =
mesh.
add_elem(std::move(new_elem_0));
875 auto new_elem_1 = std::make_unique<Tet4>();
876 new_elem_1->set_node(0,
880 new_elem_1->set_node(1,
884 new_elem_1->set_node(2,
888 new_elem_1->set_node(3, const_cast<Node *>(new_node));
890 auto new_elem_ptr_1 =
mesh.
add_elem(std::move(new_elem_1));
893 for (
const auto & bid : side_info)
903 const std::vector<unsigned int> & side_indices,
904 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
914 if (i_side % 4 == 0 ||
915 std::find(side_indices.begin(), side_indices.end(), i_side) != side_indices.end())
917 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
920 mesh, elem_id, i_side, new_node, elem_side_info[i_side], subdomain_id_shift_base);
927 const unsigned int & side_index,
928 const Node * new_node,
929 const std::vector<boundary_id_type> & side_info,
936 bool is_side_quad = (side_index % 4 != 0);
937 unsigned int lid_index = 0;
946 auto new_elem_0 = std::make_unique<Tet4>();
947 new_elem_0->set_node(0,
951 new_elem_0->set_node(1,
955 new_elem_0->set_node(2,
959 new_elem_0->set_node(3, const_cast<Node *>(new_node));
961 auto new_elem_ptr_0 =
mesh.
add_elem(std::move(new_elem_0));
964 Elem * new_elem_ptr_1 =
nullptr;
967 auto new_elem_1 = std::make_unique<Tet4>();
972 new_elem_1->set_node(1,
976 new_elem_1->set_node(2,
980 new_elem_1->set_node(3, const_cast<Node *>(new_node));
986 for (
const auto & bid : side_info)
997 const unsigned int & side_index,
998 const Node * new_node,
999 const std::vector<boundary_id_type> & side_info,
1004 mesh, elem_id, side_index, new_node, side_info, subdomain_id_shift_base);
1010 const std::vector<std::vector<boundary_id_type>> & elem_side_info,
1014 unsigned int lid_index = 0;
1021 auto new_elem_0 = std::make_unique<Tet4>();
1022 new_elem_0->set_node(
1025 new_elem_0->set_node(
1028 new_elem_0->set_node(
1033 auto new_elem_ptr_0 =
mesh.
add_elem(std::move(new_elem_0));
1036 auto new_elem_1 = std::make_unique<Tet4>();
1037 new_elem_1->set_node(
1040 new_elem_1->set_node(
1043 new_elem_1->set_node(
1048 auto new_elem_ptr_1 =
mesh.
add_elem(std::move(new_elem_1));
1051 for (
const auto & bid : elem_side_info[0])
1053 for (
const auto & bid : elem_side_info[1])
1058 for (
const auto & bid : elem_side_info[2])
1060 for (
const auto & bid : elem_side_info[3])
1065 for (
const auto & bid : elem_side_info[4])
1082 const std::vector<BoundaryName> & boundary_names,
1083 const unsigned int conversion_element_layer_number,
1084 const bool external_boundaries_checking)
1087 "This method only supports serial meshes. If you are calling this method with a " 1088 "distributed mesh, please serialize it first.");
1100 std::vector<boundary_id_type> boundary_ids;
1101 for (
const auto &
sideset : boundary_names)
1112 std::vector<std::pair<dof_id_type, std::vector<unsigned int>>> elems_list;
1113 std::vector<std::set<dof_id_type>> layered_elems_list;
1114 layered_elems_list.push_back(std::set<dof_id_type>());
1118 for (
const auto & side_info : side_list)
1120 if (std::get<2>(side_info) == uniform_tmp_bid)
1130 "The provided boundary set contains non-linear side elements, which is not supported.");
1131 const auto side_type =
1133 layered_elems_list.back().emplace(std::get<0>(side_info));
1137 const auto neighbor_ptr =
1141 if (external_boundaries_checking)
1143 "The provided boundary contains non-external sides, which is required when " 1144 "external_boundaries_checking is enabled.");
1146 layered_elems_list.back().emplace(neighbor_ptr->id());
1149 if (conversion_element_layer_number == 1)
1151 if (side_type ==
TRI3)
1153 else if (side_type ==
QUAD4)
1155 auto pit = std::find_if(elems_list.begin(),
1157 [elem_id = std::get<0>(side_info)](
const auto & p)
1158 {
return p.first == elem_id; });
1159 if (elems_list.size() && pit != elems_list.end())
1161 pit->second.push_back(std::get<1>(side_info));
1164 elems_list.push_back(std::make_pair(
1165 std::get<0>(side_info), std::vector<unsigned int>({std::get<1>(side_info)})));
1168 auto sit = std::find_if(elems_list.begin(),
1170 [elem_id = neighbor_ptr->id()](
const auto & p)
1171 {
return p.first == elem_id; });
1172 if (elems_list.size() && sit != elems_list.end())
1174 sit->second.push_back(
1175 neighbor_ptr->which_neighbor_am_i(
mesh.
elem_ptr(std::get<0>(side_info))));
1179 elems_list.push_back(std::make_pair(
1181 std::vector<unsigned int>(
1182 {neighbor_ptr->which_neighbor_am_i(
mesh.
elem_ptr(std::get<0>(side_info)))})));
1187 throw MooseException(
"The provided boundary set contains C0POLYGON side elements, which " 1188 "is not supported.");
1191 "Impossible scenario: a linear non-polygon side element that is neither TRI3 " 1197 if (conversion_element_layer_number > 1)
1199 std::set<dof_id_type> total_elems_set(layered_elems_list.back());
1201 while (layered_elems_list.back().size() &&
1202 layered_elems_list.size() < conversion_element_layer_number)
1204 layered_elems_list.push_back(std::set<dof_id_type>());
1205 for (
const auto & elem_id : *(layered_elems_list.end() - 2))
1212 if (total_elems_set.find(neighbor_id) == total_elems_set.end())
1214 layered_elems_list.back().emplace(neighbor_id);
1215 total_elems_set.emplace(neighbor_id);
1224 if (layered_elems_list.back().empty())
1225 layered_elems_list.pop_back();
1227 if (conversion_element_layer_number > layered_elems_list.size())
1228 throw MooseException(
"There is fewer layers of elements in the input mesh than the requested " 1229 "number of layers to convert.");
1231 std::vector<std::pair<dof_id_type, bool>> original_elems;
1234 const unsigned int n_layer_conversion = layered_elems_list.size() - 1;
1235 for (
unsigned int i = 0; i < n_layer_conversion; ++i)
1236 for (
const auto & elem_id : layered_elems_list[i])
1242 original_elems.push_back(std::make_pair(elem_id,
false));
1249 std::vector<dof_id_type> converted_elems_ids_to_track;
1251 mesh, original_elems, converted_elems_ids_to_track, block_id_to_remove,
false);
1256 if (n_layer_conversion)
1258 for (
const auto & elem_id : layered_elems_list[n_layer_conversion])
1263 layered_elems_list[n_layer_conversion - 1].count(
1266 if (elems_list.size() && elems_list.back().first == elem_id)
1267 elems_list.back().second.push_back(i_side);
1269 elems_list.push_back(std::make_pair(elem_id, std::vector<unsigned int>({i_side})));
1276 for (
const auto & elem_info : elems_list)
1279 std::vector<std::vector<boundary_id_type>> elem_side_info(
1281 auto side_range = sideset_map.equal_range(
mesh.
elem_ptr(elem_info.first));
1282 for (
auto i = side_range.first; i != side_range.second; ++i)
1283 elem_side_info[i->second.first].push_back(i->second.second);
1286 mesh, elem_info.first, elem_info.second, elem_side_info, sid_shift_base);
1290 for (
const auto & elem_info : elems_list)
1292 for (
auto elem_it =
mesh.active_subdomain_elements_begin(block_id_to_remove);
1293 elem_it !=
mesh.active_subdomain_elements_end(block_id_to_remove);
1306 const std::set<subdomain_id_type> & original_subdomain_ids,
1308 const SubdomainName & tet_suffix,
1309 const SubdomainName & pyramid_suffix)
1316 for (
const auto & subdomain_id : original_subdomain_ids)
1320 const SubdomainName new_name =
1326 "This suffix for converted TET4 elements results in a subdomain name, " + new_name +
1327 ", that already exists in the mesh. Please choose a different suffix.");
1332 const SubdomainName new_name =
1335 '_' + pyramid_suffix;
1338 "This suffix for converted PYRAMID5 elements results in a subdomain name, " + new_name +
1339 ", 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
R poly(const C &c, const T x, const bool derivative=false)
Evaluate a polynomial with the coefficients c at x.
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)
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true, const bool assert_valid=true)=0
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 polyhedronElemSplitter(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)
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
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
bool has_cached_elem_data
Preparation preparation() 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 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
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...
virtual dof_id_type max_node_id() const=0
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