14 #include "libmesh/elem.h" 15 #include "libmesh/boundary_info.h" 16 #include "libmesh/mesh_base.h" 17 #include "libmesh/parallel.h" 18 #include "libmesh/parallel_algebra.h" 19 #include "libmesh/face_tri3.h" 28 const std::vector<Real> & bdry_pars,
30 const std::set<subdomain_id_type> & subdomain_ids_set,
33 const std::vector<boundary_id_type> & other_boundaries_to_conform,
34 const bool assign_ext_to_new,
35 const bool side_to_remove)
41 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> slc_bdry_side_list;
42 for (
unsigned int i = 0; i < bdry_side_list.size(); i++)
43 if (std::get<2>(bdry_side_list[i]) == external_boundary_id ||
44 std::find(other_boundaries_to_conform.begin(),
45 other_boundaries_to_conform.end(),
46 std::get<2>(bdry_side_list[i])) != other_boundaries_to_conform.end())
47 slc_bdry_side_list.push_back(bdry_side_list[i]);
51 std::vector<dof_id_type> crossed_elems_to_remove;
52 for (
auto elem_it =
mesh.active_elements_begin(); elem_it !=
mesh.active_elements_end();
56 unsigned short removal_side_count = 0;
57 for (
unsigned int i = 0; i < (*elem_it)->n_vertices(); i++)
60 if (!MooseUtils::absoluteFuzzyEqual((*elem_it)->point(i)(2), 0.0))
62 "MooseMeshXYCuttingUtils::lineRemoverMoveNode() only works for 2D meshes in XY plane.");
64 (*elem_it)->point(i)(1),
71 if (removal_side_count == (*elem_it)->n_vertices())
73 (*elem_it)->subdomain_id() = block_id_to_remove;
78 (*elem_it)->vertex_average()(1),
83 crossed_elems_to_remove.push_back((*elem_it)->id());
86 for (
const auto & elem_id : crossed_elems_to_remove)
88 bool remove_flag =
true;
93 std::find(crossed_elems_to_remove.begin(),
94 crossed_elems_to_remove.end(),
96 crossed_elems_to_remove.end())
113 std::vector<dof_id_type> node_list;
114 for (
auto elem_it =
mesh.active_subdomain_set_elements_begin(subdomain_ids_set);
115 elem_it !=
mesh.active_subdomain_set_elements_end(subdomain_ids_set);
118 for (
unsigned int i = 0; i < (*elem_it)->n_sides(); i++)
120 if ((*elem_it)->neighbor_ptr(i) !=
nullptr)
121 if ((*elem_it)->neighbor_ptr(i)->subdomain_id() == block_id_to_remove)
123 node_list.push_back((*elem_it)->side_ptr(i)->node_ptr(0)->id());
124 node_list.push_back((*elem_it)->side_ptr(i)->node_ptr(1)->id());
125 boundary_info.
add_side(*elem_it, i, trimming_section_boundary_id);
126 if (assign_ext_to_new && trimming_section_boundary_id != external_boundary_id)
127 boundary_info.
add_side(*elem_it, i, external_boundary_id);
132 const auto unique_it = std::unique(node_list.begin(), node_list.end());
133 node_list.resize(std::distance(node_list.begin(), unique_it));
136 std::vector<bool> node_list_flag(node_list.size(),
false);
137 std::vector<Point> node_list_point(node_list.size(),
Point(0.0, 0.0, 0.0));
139 for (
unsigned int i = 0; i < slc_bdry_side_list.size(); i++)
143 ->
side_ptr(std::get<1>(slc_bdry_side_list[i]))
147 ->
side_ptr(std::get<1>(slc_bdry_side_list[i]))
152 !(
std::find(node_list.begin(), node_list.end(), side_id_0) == node_list.end());
154 !(
std::find(node_list.begin(), node_list.end(), side_id_1) == node_list.end());
170 if (side_id_0_in && side_id_1_in)
174 std::get<1>(slc_bdry_side_list[i]),
175 std::get<2>(slc_bdry_side_list[i]));
177 else if (side_id_0_in && (side_node_0_remove != side_node_1_remove))
180 node_list_flag[std::distance(
181 node_list.begin(),
std::find(node_list.begin(), node_list.end(), side_id_0))] =
true;
185 node_list_point[std::distance(node_list.begin(),
186 std::find(node_list.begin(), node_list.end(), side_id_0))] =
190 else if (side_id_1_in && (side_node_0_remove != side_node_1_remove))
193 node_list_flag[std::distance(
194 node_list.begin(),
std::find(node_list.begin(), node_list.end(), side_id_1))] =
true;
198 node_list_point[std::distance(node_list.begin(),
199 std::find(node_list.begin(), node_list.end(), side_id_1))] =
205 for (
unsigned int i = 0; i < node_list.size(); i++)
210 if (node_list_flag[i])
219 (bdry_pars[1] * (bdry_pars[1] * x0 - bdry_pars[0] * y0) - bdry_pars[0] * bdry_pars[2]) /
220 (bdry_pars[0] * bdry_pars[0] + bdry_pars[1] * bdry_pars[1]);
222 (bdry_pars[0] * (-bdry_pars[1] * x0 + bdry_pars[0] * y0) - bdry_pars[1] * bdry_pars[2]) /
223 (bdry_pars[0] * bdry_pars[0] + bdry_pars[1] * bdry_pars[1]);
228 for (
auto elem_it =
mesh.active_subdomain_elements_begin(block_id_to_remove);
229 elem_it !=
mesh.active_subdomain_elements_end(block_id_to_remove);
235 std::vector<dof_id_type> zero_elems;
236 for (
auto elem_it =
mesh.elements_begin(); elem_it !=
mesh.elements_end(); elem_it++)
238 if (MooseUtils::absoluteFuzzyEqual((*elem_it)->volume(), 0.0))
240 for (
unsigned int i = 0; i < (*elem_it)->n_sides(); i++)
242 if ((*elem_it)->neighbor_ptr(i) !=
nullptr)
244 boundary_info.
add_side((*elem_it)->neighbor_ptr(i),
245 ((*elem_it)->neighbor_ptr(i))->which_neighbor_am_i(*elem_it),
246 external_boundary_id);
247 boundary_info.
add_side((*elem_it)->neighbor_ptr(i),
248 ((*elem_it)->neighbor_ptr(i))->which_neighbor_am_i(*elem_it),
249 trimming_section_boundary_id);
252 zero_elems.push_back((*elem_it)->id());
255 for (
const auto & zero_elem : zero_elems)
271 return std::abs(px * param_1 + py * param_2 + param_3) <= dis_tol;
280 const bool direction_param,
283 const Real tmp = px * param_1 + py * param_2 + param_3;
284 return direction_param ? tmp >= dis_tol : tmp <= dis_tol;
296 (param_12 * param_23 - param_22 * param_13) / (param_11 * param_22 - param_21 * param_12),
297 (param_13 * param_21 - param_23 * param_11) / (param_11 * param_22 - param_21 * param_12),
313 pt2(0) * pt1(1) - pt1(0) * pt2(1));
318 const std::set<subdomain_id_type> & subdomain_ids_set,
320 const SubdomainName tri_elem_subdomain_name_suffix)
327 : tri_elem_subdomain_shift;
329 tri_subdomain_id_shift,
330 "The TRI elements subdomain id to be assigned may exceed the numeric limit.");
332 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
333 std::vector<std::tuple<Elem *, unsigned int, bool, bool>> bad_elems_rec;
335 for (
auto & elem :
as_range(
mesh.active_elements_begin(),
mesh.active_elements_end()))
343 if (MooseUtils::absoluteFuzzyEqual(elem_angles.front().first, M_PI, 0.001))
345 bad_elems_rec.push_back(std::make_tuple(elem, elem_angles.front().second,
false,
true));
349 if (MooseUtils::absoluteFuzzyEqual(elem_distances.front().first, 0.0))
351 bad_elems_rec.push_back(std::make_tuple(elem, elem_distances.front().second,
false,
false));
354 std::set<subdomain_id_type> new_subdomain_ids;
356 for (
const auto & bad_elem : bad_elems_rec)
358 std::vector<boundary_id_type> elem_bdry_container_0;
359 std::vector<boundary_id_type> elem_bdry_container_1;
360 std::vector<boundary_id_type> elem_bdry_container_2;
362 Elem * elem_0 = std::get<0>(bad_elem);
363 if (std::get<3>(bad_elem))
371 if ((elem_1 !=
nullptr || elem_2 !=
nullptr))
372 throw MooseException(
"The input mesh has degenerate quad element before trimming.");
376 elem_0, (std::get<1>(bad_elem) + 1) % elem_0->
n_vertices(), elem_bdry_container_1);
378 elem_0, (std::get<1>(bad_elem) + 2) % elem_0->
n_vertices(), elem_bdry_container_2);
380 elem_0, (std::get<1>(bad_elem) + 3) % elem_0->
n_vertices(), elem_bdry_container_0);
389 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
399 for (
auto bdry_id : elem_bdry_container_0)
400 boundary_info.
add_side(elem_Tri3, 2, bdry_id);
401 for (
auto bdry_id : elem_bdry_container_1)
402 boundary_info.
add_side(elem_Tri3, 0, bdry_id);
403 for (
auto bdry_id : elem_bdry_container_2)
404 boundary_info.
add_side(elem_Tri3, 1, bdry_id);
406 elem_Tri3->
subdomain_id() = elem_block_id + tri_subdomain_id_shift;
407 new_subdomain_ids.emplace(elem_block_id + tri_subdomain_id_shift);
409 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
413 for (
auto & nid : new_subdomain_ids)
417 (old_name.empty() ? (SubdomainName)(std::to_string(nid - tri_subdomain_id_shift))
419 "_" + tri_elem_subdomain_name_suffix,
421 throw MooseException(
"The new subdomain name already exists in the mesh.");
423 (old_name.empty() ? (SubdomainName)(std::to_string(nid - tri_subdomain_id_shift))
425 "_" + tri_elem_subdomain_name_suffix;
426 mooseWarning(
"Degenerate QUAD elements have been converted into TRI elements with a new " 430 return bad_elems_rec.size();
433 std::vector<std::pair<Real, unsigned int>>
436 std::vector<std::pair<Real, unsigned int>> angles;
437 const unsigned int n_vertices = elem.
n_vertices();
439 for (
unsigned int i = 0; i < n_vertices; i++)
448 angles.push_back(std::make_pair(acos(tmp), i));
450 std::sort(angles.begin(), angles.end(), std::greater<>());
454 std::vector<std::pair<Real, unsigned int>>
457 std::vector<std::pair<Real, unsigned int>> distances;
458 const unsigned int n_vertices = elem.
n_vertices();
460 for (
unsigned int i = 0; i < n_vertices; i++)
463 distances.push_back(std::make_pair(v1.
norm(), i));
465 std::sort(distances.begin(), distances.end());
472 const unsigned short node_shift,
480 const dof_id_type nid_1 = elem_old->node_ptr((1 + node_shift) % 3)->id();
481 const dof_id_type nid_2 = elem_old->node_ptr((2 + node_shift) % 3)->id();
483 const bool m1_side_flag =
488 const dof_id_type nid_m1 = m1_side_flag ? nid_3 : nid_4;
489 const dof_id_type nid_m2 = m1_side_flag ? nid_4 : nid_3;
494 std::vector<std::vector<boundary_id_type>> elem_side_list;
495 elem_side_list.resize(3);
496 for (
unsigned int i = 0; i < bdry_side_list.size(); i++)
498 if (std::get<0>(bdry_side_list[i]) == elem_id)
500 elem_side_list[(std::get<1>(bdry_side_list[i]) + 3 - node_shift) % 3].push_back(
501 std::get<2>(bdry_side_list[i]));
506 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
508 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
527 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
535 for (
const auto & side_info_0 : elem_side_list[0])
537 boundary_info.
add_side(elem_Tri3_0, 0, side_info_0);
538 boundary_info.
add_side(elem_Tri3_1, 2, side_info_0);
540 for (
const auto & side_info_1 : elem_side_list[1])
541 boundary_info.
add_side(elem_Tri3_2, 2, side_info_1);
542 for (
const auto & side_info_2 : elem_side_list[2])
544 boundary_info.
add_side(elem_Tri3_0, 2, side_info_2);
545 boundary_info.
add_side(elem_Tri3_2, 0, side_info_2);
552 const unsigned short node_shift,
559 const dof_id_type nid_1 = elem_old->node_ptr((1 + node_shift) % 3)->id();
560 const dof_id_type nid_2 = elem_old->node_ptr((2 + node_shift) % 3)->id();
565 std::vector<std::vector<boundary_id_type>> elem_side_list;
566 elem_side_list.resize(3);
567 for (
unsigned int i = 0; i < bdry_side_list.size(); i++)
569 if (std::get<0>(bdry_side_list[i]) == elem_id)
571 elem_side_list[(std::get<1>(bdry_side_list[i]) + 3 - node_shift) % 3].push_back(
572 std::get<2>(bdry_side_list[i]));
577 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
579 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
593 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
600 for (
const auto & side_info_0 : elem_side_list[0])
601 boundary_info.
add_side(elem_Tri3_0, 0, side_info_0);
602 for (
const auto & side_info_1 : elem_side_list[1])
604 boundary_info.
add_side(elem_Tri3_0, 1, side_info_1);
605 boundary_info.
add_side(elem_Tri3_1, 1, side_info_1);
607 for (
const auto & side_info_2 : elem_side_list[2])
608 boundary_info.
add_side(elem_Tri3_1, 2, side_info_2);
620 std::vector<std::vector<boundary_id_type>> elem_side_list;
621 elem_side_list.resize(4);
622 for (
unsigned int i = 0; i < bdry_side_list.size(); i++)
624 if (std::get<0>(bdry_side_list[i]) == elem_id)
626 elem_side_list[std::get<1>(bdry_side_list[i])].push_back(std::get<2>(bdry_side_list[i]));
636 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
638 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
643 if (
std::abs((*node_1 - *node_0).cross(*node_3 - *node_0).
norm() -
644 (*node_1 - *node_2).cross(*node_3 - *node_2).
norm()) >
645 std::abs((*node_0 - *node_1).cross(*node_2 - *node_1).
norm() -
646 (*node_0 - *node_3).cross(*node_2 - *node_3).
norm()))
659 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
666 for (
const auto & side_info_0 : elem_side_list[0])
667 boundary_info.
add_side(elem_Tri3_0, 0, side_info_0);
668 for (
const auto & side_info_1 : elem_side_list[1])
669 boundary_info.
add_side(elem_Tri3_0, 1, side_info_1);
670 for (
const auto & side_info_2 : elem_side_list[2])
671 boundary_info.
add_side(elem_Tri3_1, 1, side_info_2);
672 for (
const auto & side_info_3 : elem_side_list[3])
673 boundary_info.
add_side(elem_Tri3_1, 2, side_info_3);
688 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
695 for (
const auto & side_info_0 : elem_side_list[0])
696 boundary_info.
add_side(elem_Tri3_0, 0, side_info_0);
697 for (
const auto & side_info_1 : elem_side_list[1])
698 boundary_info.
add_side(elem_Tri3_1, 0, side_info_1);
699 for (
const auto & side_info_2 : elem_side_list[2])
700 boundary_info.
add_side(elem_Tri3_1, 1, side_info_2);
701 for (
const auto & side_info_3 : elem_side_list[3])
702 boundary_info.
add_side(elem_Tri3_0, 2, side_info_3);
708 const std::vector<Real> & cut_line_params,
710 const SubdomainName tri_elem_subdomain_name_suffix)
713 std::vector<dof_id_type> cross_elems_quad;
714 std::set<subdomain_id_type> new_subdomain_ids;
715 for (
auto elem_it =
mesh.active_elements_begin(); elem_it !=
mesh.active_elements_end();
718 if ((*elem_it)->n_vertices() == 4)
720 std::vector<unsigned short> node_side_rec;
721 for (
unsigned int i = 0; i < 4; i++)
723 const Point v_point = (*elem_it)->point(i);
725 v_point(0), v_point(1), cut_line_params[0], cut_line_params[1], cut_line_params[2]))
739 const auto num_nodes = std::accumulate(node_side_rec.begin(), node_side_rec.end(), 0);
740 if (num_nodes != (
int)node_side_rec.size() && num_nodes > 0)
742 cross_elems_quad.push_back((*elem_it)->id());
743 new_subdomain_ids.emplace((*elem_it)->subdomain_id() + tri_subdomain_id_shift);
748 for (
const auto & cross_elem_quad : cross_elems_quad)
753 for (
auto & nid : new_subdomain_ids)
757 (old_name.empty() ? (SubdomainName)(std::to_string(nid - tri_subdomain_id_shift))
759 "_" + tri_elem_subdomain_name_suffix,
761 throw MooseException(
"The new subdomain name already exists in the mesh.");
763 (old_name.empty() ? (SubdomainName)(std::to_string(nid - tri_subdomain_id_shift))
765 "_" + tri_elem_subdomain_name_suffix;
766 mooseWarning(
"QUAD elements have been converted into TRI elements with a new " 775 const std::vector<Real> & cut_line_params,
780 std::vector<dof_id_type> cross_elems;
782 std::vector<std::vector<std::pair<dof_id_type, dof_id_type>>> node_pairs_vec;
784 std::vector<std::pair<dof_id_type, dof_id_type>> node_pairs_unique_vec;
785 for (
auto elem_it =
mesh.active_elements_begin(); elem_it !=
mesh.active_elements_end();
788 const auto n_vertices = (*elem_it)->n_vertices();
789 unsigned int n_points_on_line = 0;
790 std::vector<unsigned short> node_side_rec(n_vertices, 0);
791 for (
unsigned int i = 0; i < n_vertices; i++)
794 if (!MooseUtils::absoluteFuzzyEqual((*elem_it)->point(i)(2), 0.0))
795 mooseError(
"MooseMeshXYCuttingUtils::lineRemoverCutElemTri() only works for 2D meshes in " 797 const Point v_point = (*elem_it)->point(i);
799 v_point(0), v_point(1), cut_line_params[0], cut_line_params[1], cut_line_params[2]))
815 const unsigned int num_nodes = std::accumulate(node_side_rec.begin(), node_side_rec.end(), 0);
816 if (num_nodes == node_side_rec.size() - n_points_on_line)
818 (*elem_it)->subdomain_id() = block_id_to_remove;
820 else if (num_nodes > 0)
822 if ((*elem_it)->n_vertices() != 3 || (*elem_it)->n_nodes() != 3)
823 mooseError(
"The element across the cutting line is not TRI3, which is not supported.");
824 cross_elems.push_back((*elem_it)->id());
826 std::vector<std::pair<dof_id_type, dof_id_type>> node_pairs;
827 for (
unsigned int i = 0; i < node_side_rec.size(); i++)
830 if (node_side_rec[i] > 0 && node_side_rec[(i + 1) % node_side_rec.size()] == 0)
833 node_pairs.push_back(
834 std::make_pair((*elem_it)->node_ptr(i)->id(),
835 (*elem_it)->node_ptr((i + 1) % node_side_rec.size())->
id()));
836 node_pairs_unique_vec.push_back(node_pairs.back());
839 else if (node_side_rec[i] == 0 && node_side_rec[(i + 1) % node_side_rec.size()] > 0)
842 node_pairs.push_back(
843 std::make_pair((*elem_it)->node_ptr((i + 1) % node_side_rec.size())->
id(),
844 (*elem_it)->node_ptr(i)->id()));
845 node_pairs_unique_vec.push_back(node_pairs.back());
848 node_pairs_vec.push_back(node_pairs);
851 auto vec_ip = std::unique(node_pairs_unique_vec.begin(), node_pairs_unique_vec.end());
852 node_pairs_unique_vec.resize(std::distance(node_pairs_unique_vec.begin(), vec_ip));
855 std::vector<Node *> nodes_on_line;
857 std::vector<unsigned short> nodes_on_line_overlap;
858 for (
const auto & node_pair : node_pairs_unique_vec)
863 pt1, pt2, cut_line_params[0], cut_line_params[1], cut_line_params[2]);
866 nodes_on_line.push_back(
mesh.
node_ptr(node_pair.first));
867 nodes_on_line_overlap.push_back(1);
871 nodes_on_line.push_back(
mesh.
node_ptr(node_pair.second));
872 nodes_on_line_overlap.push_back(2);
877 nodes_on_line_overlap.push_back(0);
882 for (
unsigned int i = 0; i < cross_elems.size(); i++)
886 auto node_0 = cross_elem->
node_ptr(0);
887 auto node_1 = cross_elem->node_ptr(1);
888 auto node_2 = cross_elem->node_ptr(2);
889 const std::vector<dof_id_type> tri_nodes = {node_0->
id(), node_1->id(), node_2->id()};
891 const auto online_node_index_1 = std::distance(node_pairs_unique_vec.begin(),
893 node_pairs_unique_vec.end(),
894 node_pairs_vec[i][0]));
895 const auto online_node_index_2 = std::distance(node_pairs_unique_vec.begin(),
897 node_pairs_unique_vec.end(),
898 node_pairs_vec[i][1]));
899 auto node_3 = nodes_on_line[online_node_index_1];
900 auto node_4 = nodes_on_line[online_node_index_2];
901 const auto node_3_overlap_flag = nodes_on_line_overlap[online_node_index_1];
902 const auto node_4_overlap_flag = nodes_on_line_overlap[online_node_index_2];
904 if (node_3_overlap_flag == 0 && node_4_overlap_flag == 0)
907 const bool common_node_side = node_pairs_vec[i][0].first == node_pairs_vec[i][1].first;
909 common_node_side ? block_id_to_remove : cross_elem->subdomain_id();
911 common_node_side ? cross_elem->subdomain_id() : block_id_to_remove;
915 common_node_side ? node_pairs_vec[i][0].first : node_pairs_vec[i][0].second;
919 std::distance(tri_nodes.begin(),
920 std::find(tri_nodes.begin(), tri_nodes.end(), common_node_id)),
923 block_id_to_assign_1,
924 block_id_to_assign_2);
928 else if (node_3_overlap_flag > 0 && node_4_overlap_flag > 0)
933 cross_elem->vertex_average()(1),
939 : cross_elem->subdomain_id();
944 const auto node_3_finder = std::distance(
945 tri_nodes.begin(),
std::find(tri_nodes.begin(), tri_nodes.end(), node_3->id()));
946 const auto node_4_finder = std::distance(
947 tri_nodes.begin(),
std::find(tri_nodes.begin(), tri_nodes.end(), node_4->id()));
950 const dof_id_type node_id = node_3_finder < node_4_finder ? node_4->id() : node_3->id();
951 const auto node_finder =
std::min(node_3_finder, node_4_finder);
958 tri_nodes[(node_finder + 1) % 3] == node_pairs_vec[i][node_3_finder > node_4_finder].first
960 : cross_elem->subdomain_id(),
961 tri_nodes[(node_finder + 1) % 3] == node_pairs_vec[i][node_3_finder > node_4_finder].first
962 ? cross_elem->subdomain_id()
963 : block_id_to_remove);
973 for (
auto elem_it =
mesh.active_elements_begin(); elem_it !=
mesh.active_elements_end();
976 if ((*elem_it)->subdomain_id() != block_id_to_remove)
978 for (
unsigned int j = 0; j < (*elem_it)->n_sides(); j++)
980 if ((*elem_it)->neighbor_ptr(j) !=
nullptr)
981 if ((*elem_it)->neighbor_ptr(j)->subdomain_id() == block_id_to_remove)
982 boundary_info.
add_side(*elem_it, j, new_boundary_id);
988 for (
auto elem_it =
mesh.active_subdomain_elements_begin(block_id_to_remove);
989 elem_it !=
mesh.active_subdomain_elements_end(block_id_to_remove);
997 const std::vector<Real> & cut_line_params,
999 const SubdomainName tri_elem_subdomain_name_suffix,
1002 const bool improve_boundary_tri_elems)
1005 quadToTriOnLine(
mesh, cut_line_params, tri_subdomain_id_shift, tri_elem_subdomain_name_suffix);
1010 if (improve_boundary_tri_elems)
1019 "MooseMeshXYCuttingUtils::boundaryTriElemImprover(): The boundary_to_improve provided " 1020 "does not exist in the given mesh.");
1029 std::map<dof_id_type, std::vector<std::tuple<dof_id_type, dof_id_type, dof_id_type>>>
1031 for (
const auto & side : side_list)
1033 if (std::get<2>(side) == boundary_to_improve)
1038 const auto key_node_id = elem->
node_id((std::get<1>(side) + 2) % 3);
1039 const auto value_elem_id = elem->
id();
1040 const auto value_node_id_1 = elem->
node_id(std::get<1>(side));
1041 const auto value_node_id_2 = elem->
node_id((std::get<1>(side) + 1) % 3);
1042 tri3_elem_info[key_node_id].push_back(
1043 std::make_tuple(value_elem_id, value_node_id_1, value_node_id_2));
1048 std::vector<dof_id_type> elems_to_remove;
1050 for (
const auto & tri_group : tri3_elem_info)
1054 std::vector<std::pair<dof_id_type, dof_id_type>> node_assm;
1055 std::vector<dof_id_type> elem_id_list;
1056 for (
const auto & tri : tri_group.second)
1058 node_assm.push_back(std::make_pair(std::get<1>(tri), std::get<2>(tri)));
1059 elem_id_list.push_back(std::get<0>(tri));
1061 std::vector<dof_id_type> ordered_node_list;
1062 std::vector<dof_id_type> ordered_elem_list;
1064 node_assm, elem_id_list, ordered_node_list, ordered_elem_list);
1071 std::vector<std::tuple<subdomain_id_type, std::vector<dof_id_type>,
unsigned int>> blocks_info;
1072 for (
const auto & elem_id : ordered_elem_list)
1074 std::vector<dof_id_type> exist_extra_ids(n_elem_extra_ids);
1076 for (
unsigned int j = 0; j < n_elem_extra_ids; j++)
1078 if (!blocks_info.empty())
1081 exist_extra_ids == std::get<1>(blocks_info.back()))
1083 std::get<2>(blocks_info.back())++;
1087 blocks_info.push_back(
1091 unsigned int side_counter = 0;
1092 for (
const auto & block_info : blocks_info)
1094 const auto node_1 =
mesh.
node_ptr(ordered_node_list[side_counter]);
1096 const auto node_2 =
mesh.
node_ptr(ordered_node_list[side_counter + std::get<2>(block_info)]);
1098 const Point v1 = *node_1 - *node_0;
1099 const Point v2 = *node_2 - *node_0;
1100 const Real angle = std::acos(v1 * v2 / v1.
norm() / v2.
norm()) / M_PI * 180.0;
1101 const std::vector<dof_id_type> block_elems(ordered_elem_list.begin() + side_counter,
1102 ordered_elem_list.begin() + side_counter +
1103 std::get<2>(block_info));
1107 unsigned short side_id_0;
1108 unsigned short side_id_t;
1112 block_elems.front(),
1114 ordered_node_list[side_counter],
1119 ordered_node_list[side_counter + std::get<2>(block_info)],
1124 std::vector<boundary_id_type> side_0_boundary_ids;
1126 mesh.
elem_ptr(block_elems.front()), side_id_0, side_0_boundary_ids);
1127 std::vector<boundary_id_type> side_t_boundary_ids;
1137 if (std::get<2>(block_info) > 1)
1141 ordered_node_list[side_counter],
1142 ordered_node_list[side_counter + std::get<2>(block_info)],
1143 std::get<0>(block_info),
1144 std::get<1>(block_info),
1145 {boundary_to_improve},
1146 side_0_boundary_ids,
1147 side_t_boundary_ids);
1148 elems_to_remove.insert(elems_to_remove.end(), block_elems.begin(), block_elems.end());
1151 else if (angle < 135.0)
1154 const auto node_m =
mesh.
add_point((*node_1 + *node_2) / 2.0);
1157 ordered_node_list[side_counter],
1159 std::get<0>(block_info),
1160 std::get<1>(block_info),
1161 {boundary_to_improve},
1162 side_0_boundary_ids,
1163 std::vector<boundary_id_type>());
1167 ordered_node_list[side_counter + std::get<2>(block_info)],
1168 std::get<0>(block_info),
1169 std::get<1>(block_info),
1170 {boundary_to_improve},
1171 std::vector<boundary_id_type>(),
1172 side_t_boundary_ids);
1173 elems_to_remove.insert(elems_to_remove.end(), block_elems.begin(), block_elems.end());
1177 const auto node_m1 =
mesh.
add_point((*node_1 * 2.0 + *node_2) / 3.0);
1178 const auto node_m2 =
mesh.
add_point((*node_1 + *node_2 * 2.0) / 3.0);
1181 ordered_node_list[side_counter],
1183 std::get<0>(block_info),
1184 std::get<1>(block_info),
1185 {boundary_to_improve},
1186 side_0_boundary_ids,
1187 std::vector<boundary_id_type>());
1192 std::get<0>(block_info),
1193 std::get<1>(block_info),
1194 {boundary_to_improve},
1195 std::vector<boundary_id_type>(),
1196 std::vector<boundary_id_type>());
1200 ordered_node_list[side_counter + std::get<2>(block_info)],
1201 std::get<0>(block_info),
1202 std::get<1>(block_info),
1203 {boundary_to_improve},
1204 std::vector<boundary_id_type>(),
1205 side_t_boundary_ids);
1206 elems_to_remove.insert(elems_to_remove.end(), block_elems.begin(), block_elems.end());
1208 side_counter += std::get<2>(block_info);
1213 for (
const auto & elem_to_remove : elems_to_remove)
1224 const std::vector<dof_id_type> & extra_elem_ids,
1225 const std::vector<boundary_id_type> & boundary_ids_for_side_1,
1226 const std::vector<boundary_id_type> & boundary_ids_for_side_0,
1227 const std::vector<boundary_id_type> & boundary_ids_for_side_2)
1234 for (
const auto & boundary_id_for_side_0 : boundary_ids_for_side_0)
1235 boundary_info.
add_side(elem_Tri3_new, 0, boundary_id_for_side_0);
1236 for (
const auto & boundary_id_for_side_1 : boundary_ids_for_side_1)
1237 boundary_info.
add_side(elem_Tri3_new, 1, boundary_id_for_side_1);
1238 for (
const auto & boundary_id_for_side_2 : boundary_ids_for_side_2)
1239 boundary_info.
add_side(elem_Tri3_new, 2, boundary_id_for_side_2);
1242 for (
unsigned int j = 0; j < extra_elem_ids.size(); j++)
1253 unsigned short & side_id,
1257 for (
unsigned short i = 0; i < elem->
n_sides(); i++)
1259 if (elem->
side_ptr(i)->node_ptr(0)->id() == node_id_0 &&
1260 elem->
side_ptr(i)->node_ptr(1)->id() == node_id_1)
1266 else if (elem->
side_ptr(i)->node_ptr(0)->id() == node_id_1 &&
1267 elem->
side_ptr(i)->node_ptr(1)->id() == node_id_0)
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
void triElemSplitter(libMesh::ReplicatedMesh &mesh, const dof_id_type elem_id, const unsigned short node_shift, const dof_id_type nid_3, const dof_id_type nid_4, const subdomain_id_type single_elem_side_id, const subdomain_id_type double_elem_side_id)
Split a TRI3 element into three TRI3 elements based on two nodes on the two sides of the triangle...
void boundaryTriElemImprover(libMesh::ReplicatedMesh &mesh, const boundary_id_type boundary_to_improve)
Improve the element quality of the boundary TRI3 elements of the given boundary.
void lineRemoverCutElem(libMesh::ReplicatedMesh &mesh, const std::vector< Real > &cut_line_params, const dof_id_type tri_subdomain_id_shift, const SubdomainName tri_elem_subdomain_name_suffix, const subdomain_id_type block_id_to_remove, const boundary_id_type new_boundary_id, const bool improve_boundary_tri_elems=false)
Trim the 2D mesh by removing all the elements on one side of the given line.
std::vector< std::pair< Real, unsigned int > > vertex_angles(const Elem &elem)
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
void makeOrderedNodeList(std::vector< std::pair< dof_id_type, dof_id_type >> &node_assm, std::vector< dof_id_type > &elem_id_list, std::vector< dof_id_type > &midpoint_node_list, std::vector< dof_id_type > &ordered_node_list, std::vector< dof_id_type > &ordered_elem_id_list)
Convert a list of sides in the form of a vector of pairs of node ids into a list of ordered nodes bas...
virtual Node *& set_node(const unsigned int i)
auto norm() const -> decltype(std::norm(Real()))
Point twoPointandLineIntersection(const Point &pt1, const Point &pt2, const Real param_1, const Real param_2, const Real param_3)
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
static constexpr Real TOLERANCE
void makeImprovedTriElement(libMesh::ReplicatedMesh &mesh, const dof_id_type node_id_0, const dof_id_type node_id_1, const dof_id_type node_id_2, const subdomain_id_type subdomain_id, const std::vector< dof_id_type > &extra_elem_ids, const std::vector< boundary_id_type > &boundary_ids_for_side_1=std::vector< boundary_id_type >(), const std::vector< boundary_id_type > &boundary_ids_for_side_0=std::vector< boundary_id_type >(), const std::vector< boundary_id_type > &boundary_ids_for_side_2=std::vector< boundary_id_type >())
Make a TRI3 element with the given node ids and subdomain id with boundary information.
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
const boundary_id_type side_id
unsigned int n_elem_integers() const
void quadElemSplitter(libMesh::ReplicatedMesh &mesh, const dof_id_type elem_id, const subdomain_id_type tri_elem_subdomain_shift)
Split a QUAD4 element into two TRI3 elements.
void lineRemoverMoveNode(libMesh::ReplicatedMesh &mesh, const std::vector< Real > &bdry_pars, const subdomain_id_type block_id_to_remove, const std::set< subdomain_id_type > &subdomain_ids_set, const boundary_id_type trimming_section_boundary_id, const boundary_id_type external_boundary_id, const std::vector< boundary_id_type > &other_boundaries_to_conform=std::vector< boundary_id_type >(), const bool assign_ext_to_new=false, const bool side_to_remove=true)
Removes all the elements on one side of a given line and deforms the elements intercepted by the line...
bool hasBoundaryID(const MeshBase &input_mesh, const BoundaryID id)
Whether a particular boundary ID exists in the mesh.
void boundary_ids(const Node *node, std::vector< boundary_id_type > &vec_to_fill) const
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
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
SubdomainID getSubdomainID(const SubdomainName &subdomain_name, const MeshBase &mesh)
Gets the subdomain ID associated with the given SubdomainName.
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
const SubdomainID INVALID_BLOCK_ID
void clear_boundary_node_ids()
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true)=0
virtual void delete_elem(Elem *e)=0
std::vector< std::pair< Real, unsigned int > > vertex_distances(const Elem &elem)
virtual Elem * add_elem(Elem *e)=0
bool elemSideLocator(libMesh::ReplicatedMesh &mesh, const dof_id_type elem_id, const dof_id_type node_id_0, const dof_id_type node_id_1, unsigned short &side_id, bool &is_inverse)
Check if there is a side in an element that contains the given pair of nodes; if yes, also find the side id and the direction of the two nodes in the side.
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
bool quasiTriElementsFixer(libMesh::ReplicatedMesh &mesh, const std::set< subdomain_id_type > &subdomain_ids_set, const subdomain_id_type tri_elem_subdomain_shift=Moose::INVALID_BLOCK_ID, const SubdomainName tri_elem_subdomain_name_suffix="tri")
Fixes degenerate QUAD elements created by the hexagonal mesh trimming by converting them into TRI ele...
bool pointOnLine(const Real px, const Real py, const Real param_1, const Real param_2, const Real param_3, const Real dis_tol=libMesh::TOLERANCE)
Determines whether a point on XY-plane is on a given line, to within a tolerance. ...
std::string & subdomain_name(subdomain_id_type id)
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
void remove_side(const Elem *elem, const unsigned short int side)
Provides a way for users to bail out of the current solve.
virtual unsigned int n_vertices() const=0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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
bool lineSideDeterminator(const Real px, const Real py, const Real param_1, const Real param_2, const Real param_3, const bool direction_param, const Real dis_tol=libMesh::TOLERANCE)
Determines whether a point on XY-plane is on the side of a given line that needs to be removed...
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
void quadToTriOnLine(libMesh::ReplicatedMesh &mesh, const std::vector< Real > &cut_line_params, const dof_id_type tri_subdomain_id_shift, const SubdomainName tri_elem_subdomain_name_suffix)
Convert all the QUAD4 elements in the mesh that are crossed by the given line into TRI3 elements...
virtual const Node * node_ptr(const dof_id_type i) const=0
auto min(const L &left, const R &right)
virtual ElemType type() const=0
dof_id_type node_id(const unsigned int i) const
void set_extra_integer(const unsigned int index, const dof_id_type value)
dof_id_type get_extra_integer(const unsigned int index) const
Point twoLineIntersection(const Real param_11, const Real param_12, const Real param_13, const Real param_21, const Real param_22, const Real param_23)
Calculates the intersection Point of two given straight lines.
void lineRemoverCutElemTri(libMesh::ReplicatedMesh &mesh, const std::vector< Real > &cut_line_params, const subdomain_id_type block_id_to_remove, const boundary_id_type new_boundary_id)
Trim the 2D mesh by removing all the elements on one side of the given line.