21 #include "libmesh/boundary_info.h" 22 #include "libmesh/ghosting_functor.h" 23 #include "libmesh/ghost_point_neighbors.h" 24 #include "libmesh/unstructured_mesh.h" 25 #include "libmesh/libmesh_logging.h" 26 #include "libmesh/elem.h" 27 #include "libmesh/elem_range.h" 28 #include "libmesh/mesh_tools.h" 29 #include "libmesh/parallel.h" 30 #include "libmesh/remote_elem.h" 31 #include "libmesh/namebased_io.h" 32 #include "libmesh/partitioner.h" 33 #include "libmesh/enum_order.h" 34 #include "libmesh/mesh_communication.h" 35 #include "libmesh/enum_to_string.h" 36 #include "libmesh/mesh_serializer.h" 37 #include "libmesh/utility.h" 39 #ifdef LIBMESH_HAVE_NANOFLANN 40 #include "libmesh/nanoflann.hpp" 50 #include <unordered_map> 53 #include "libmesh/periodic_boundaries.h" 54 #include "libmesh/periodic_boundary.h" 62 std::map<std::vector<dof_id_type>,
Node *>::iterator
63 map_hi_order_node(
unsigned int hon,
65 std::map<std::vector<dof_id_type>,
Node *> & adj_vertices_to_ho_nodes)
72 const unsigned int n_adjacent_vertices =
75 std::vector<dof_id_type> adjacent_vertices_ids(n_adjacent_vertices);
77 for (
unsigned int v=0; v<n_adjacent_vertices; v++)
78 adjacent_vertices_ids[v] =
87 std::sort(adjacent_vertices_ids.begin(),
88 adjacent_vertices_ids.end());
92 return adj_vertices_to_ho_nodes.try_emplace(adjacent_vertices_ids,
nullptr).first;
95 void transfer_elem(
Elem & lo_elem,
96 std::unique_ptr<Elem> hi_elem,
97 #ifdef LIBMESH_ENABLE_UNIQUE_ID
102 std::map<std::vector<dof_id_type>,
Node *> & adj_vertices_to_ho_nodes,
103 std::unordered_map<
Elem *, std::vector<Elem *>> & exterior_children_of)
105 libmesh_assert_equal_to (lo_elem.
n_vertices(), hi_elem->n_vertices());
118 const unsigned int hon_begin = lo_elem.
n_nodes();
119 const unsigned int hon_end = hi_elem->n_nodes();
121 for (
unsigned int hon=hon_begin; hon<hon_end; hon++)
123 auto pos = map_hi_order_node(hon, *hi_elem, adj_vertices_to_ho_nodes);
128 const auto & adjacent_vertices_ids = pos->first;
137 Point new_location = 0;
138 for (
dof_id_type vertex_id : adjacent_vertices_ids)
141 new_location /=
static_cast<Real>(adjacent_vertices_ids.size());
174 #ifdef LIBMESH_ENABLE_UNIQUE_ID 176 max_new_nodes_per_elem * lo_elem.
id() +
188 pos->second = hi_node;
190 hi_elem->set_node(hon, hi_node);
195 Node * hi_node = pos->second;
199 hi_elem->set_node(hon, hi_node);
214 chosen_pid == my_pid)
236 libmesh_assert_equal_to (neigh->
level(), 0);
244 hi_elem->set_neighbor(s, neigh);
257 if (
auto parent_exterior_it = exterior_children_of.find(interior_p);
258 parent_exterior_it != exterior_children_of.end())
260 auto & exteriors = parent_exterior_it->second;
262 if (exteriors[i] == &lo_elem)
264 exteriors[i] = hi_elem.get();
273 if (
auto exterior_it = exterior_children_of.find(&lo_elem);
274 exterior_it != exterior_children_of.end())
276 for (
Elem * exterior_elem : exterior_it->second)
302 hi_elem->set_id(lo_elem.
id());
303 #ifdef LIBMESH_ENABLE_UNIQUE_ID 304 hi_elem->set_unique_id(lo_elem.
unique_id());
308 hi_elem->add_extra_integers(nei);
309 for (
unsigned int i=0; i != nei; ++i)
312 hi_elem->inherit_data_from(lo_elem);
318 template <
typename ElemTypeConverter>
322 const unsigned int max_new_nodes_per_elem,
323 const ElemTypeConverter & elem_type_converter)
359 auto is_higher_order = [&elem_type_converter](
const Elem * elem) {
361 ElemType new_type = elem_type_converter(old_type);
362 return old_type == new_type;
365 bool already_higher_order =
366 std::all_of(range.
begin(), range.
end(), is_higher_order);
370 if (already_higher_order)
388 std::map<std::vector<dof_id_type>,
Node *> adj_vertices_to_ho_nodes;
396 std::unordered_map<Elem *, std::vector<Elem *>> exterior_children_of;
404 #ifdef LIBMESH_ENABLE_UNIQUE_ID 415 n_partitioned_elem = 0;
431 auto track_if_necessary = [&adj_vertices_to_ho_nodes,
432 &exterior_children_of,
433 &elem_type_converter](
Elem * elem) {
436 if (elem->default_order() !=
FIRST)
437 for (
unsigned int hon :
make_range(elem->n_vertices(), elem->n_nodes()))
439 auto pos = map_hi_order_node(hon, *elem, adj_vertices_to_ho_nodes);
440 pos->second = elem->node_ptr(hon);
443 const ElemType old_type = elem->type();
444 const ElemType new_type = elem_type_converter(old_type);
445 if (old_type != new_type)
446 exterior_children_of.emplace(elem, std::vector<Elem *>());
452 if (range.
begin() ==
mesh.elements_begin() &&
453 range.
end() ==
mesh.elements_end())
455 for (
auto & elem : range)
456 track_if_necessary(elem);
463 point_neighbor_finder(range.
begin(), range.
end(),
465 point_neighbor_elements);
467 for (
auto & [elem, coupling_map] : point_neighbor_elements)
470 track_if_necessary(const_cast<Elem *>(elem));
478 for (
auto & elem :
mesh.element_ptr_range())
479 if (
auto exterior_map_it = exterior_children_of.find(elem->interior_parent());
480 exterior_map_it != exterior_children_of.end())
481 exterior_map_it->second.push_back(elem);
489 for (
auto & lo_elem : range)
494 const ElemType new_type = elem_type_converter(old_type);
496 if (old_type == new_type)
500 libmesh_assert_equal_to (lo_elem->
level(), 0);
503 ++n_unpartitioned_elem;
505 ++n_partitioned_elem;
513 libmesh_assert_equal_to (lo_elem->
n_vertices(), ho_elem->n_vertices());
519 for (
unsigned int v=0, lnn=lo_elem->
n_nodes(); v < lnn; v++)
520 ho_elem->set_node(v, lo_elem->
node_ptr(v));
522 transfer_elem(*lo_elem, std::move(ho_elem),
523 #ifdef LIBMESH_ENABLE_UNIQUE_ID
524 max_unique_id, max_new_nodes_per_elem,
526 mesh, adj_vertices_to_ho_nodes,
527 exterior_children_of);
531 adj_vertices_to_ho_nodes.clear();
533 #ifdef LIBMESH_ENABLE_UNIQUE_ID 547 dof_id_type max_unpartitioned_elem = n_unpartitioned_elem;
549 if (max_unpartitioned_elem)
557 libmesh_not_implemented();
589 const std::vector<std::pair<Point, dof_id_type>>
_nodes;
608 libmesh_assert_less (
idx,
_nodes.size());
609 libmesh_assert_less (
dim, 3);
613 if (
dim==0)
return p(0);
614 if (
dim==1)
return p(1);
621 template <
class BBOX>
646 const bool skip_find_neighbors,
650 #ifdef LIBMESH_ENABLE_UNIQUE_ID
654 std::unordered_map<subdomain_id_type, subdomain_id_type> *
656 const bool skip_preparation)
658 LOG_SCOPE(
"copy_nodes_and_elements()",
"UnstructuredMesh");
664 std::pair<std::vector<unsigned int>, std::vector<unsigned int>>
667 const unsigned int n_old_node_ints = extra_int_maps.second.size(),
669 n_old_elem_ints = extra_int_maps.first.size(),
695 for (
const auto & oldn : other_mesh.node_ptr_range())
698 (wrap_proc_ids ? oldn->processor_id() % this->
n_processors() : oldn->processor_id());
703 oldn->id() + node_id_offset,
707 for (
unsigned int i = 0; i != n_old_node_ints; ++i)
708 newn->set_extra_integer(extra_int_maps.second[i],
709 oldn->get_extra_integer(i));
711 #ifdef LIBMESH_ENABLE_UNIQUE_ID 712 newn->set_unique_id(oldn->unique_id() + unique_id_offset);
723 typedef std::unordered_map<const Elem *, Elem *> map_type;
724 map_type old_elems_to_new_elems, ip_map;
727 for (
const auto & old : other_mesh.element_ptr_range())
731 this->
elem_ptr(old->parent()->id() + element_id_offset) :
734 el->set_parent(newparent);
739 auto remapping_it = id_remapping->find(sbd_id);
740 if (remapping_it != id_remapping->end())
741 sbd_id = remapping_it->second;
743 el->subdomain_id() = sbd_id;
747 if (old->interior_parent())
748 ip_map[old] = el.get();
750 #ifdef LIBMESH_ENABLE_AMR 751 if (old->has_children())
752 for (
unsigned int c = 0, nc = old->n_children(); c != nc; ++c)
754 el->add_child(const_cast<RemoteElem *>(
remote_elem), c);
759 unsigned int oldc = old->parent()->which_child_am_i(old);
764 el->set_refinement_flag(old->refinement_flag());
768 el->hack_p_level(old->p_level());
770 el->set_p_refinement_flag(old->p_refinement_flag());
771 #endif // #ifdef LIBMESH_ENABLE_AMR 774 for (
auto i : el->node_index_range())
776 this->node_ptr(old->node_id(i) + node_id_offset));
779 el->processor_id() = cast_int<processor_id_type>
780 (wrap_proc_ids ? old->processor_id() % this->
n_processors() : old->processor_id());
783 el->set_id(old->id() + element_id_offset);
785 el->add_extra_integers(n_new_elem_ints);
786 for (
unsigned int i = 0; i != n_old_elem_ints; ++i)
787 el->set_extra_integer(extra_int_maps.first[i],
788 old->get_extra_integer(i));
790 #ifdef LIBMESH_ENABLE_UNIQUE_ID 791 el->set_unique_id(old->unique_id() + unique_id_offset);
795 if (!skip_find_neighbors)
797 for (
auto s : old->side_index_range())
799 el->set_neighbor(s, const_cast<RemoteElem *>(
remote_elem));
805 old_elems_to_new_elems[old] = new_el;
817 std::atomic<bool> existing_interior_parents{
false};
821 [&existing_interior_parents](
const ElemRange & range)
823 for (
Elem * elem : range)
824 if (elem->interior_parent())
826 existing_interior_parents =
true;
837 if (!existing_interior_parents)
839 if (other_interior_mesh == &other_mesh)
845 if (other_interior_mesh == &other_mesh &&
847 for (
auto & elem_pair : ip_map)
848 elem_pair.second->set_interior_parent(
849 this->
elem_ptr(elem_pair.first->interior_parent()->id() + element_id_offset));
851 for (
auto & elem_pair : ip_map)
853 Elem * ip =
const_cast<Elem *
>(elem_pair.first->interior_parent());
855 ip == other_interior_mesh->elem_ptr(ip->
id()));
856 elem_pair.second->set_interior_parent(ip);
859 libmesh_error_msg(
"Cannot copy boundary elements between meshes with different interior meshes");
863 if (skip_find_neighbors)
867 for (
const auto & old_elem : other_mesh.element_ptr_range())
869 Elem * new_elem = old_elems_to_new_elems[old_elem];
870 for (
auto s : old_elem->side_index_range())
873 Elem * new_neighbor = old_elems_to_new_elems[old_neighbor];
880 #ifdef LIBMESH_ENABLE_UNIQUE_ID 891 if (!skip_preparation)
924 if (skip_find_neighbors ||
956 const bool reset_current_list,
957 const bool assert_valid)
965 parallel_object_only();
967 LOG_SCOPE(
"find_neighbors()",
"Mesh");
970 if (reset_current_list)
973 [reset_remote_elements](
const ElemRange & range)
975 for (
Elem * e : range)
976 for (
auto s : e->side_index_range())
977 if (e->neighbor_ptr(s) !=
remote_elem || reset_remote_elements)
978 e->set_neighbor(s,
nullptr);
987 typedef std::pair<Elem *, unsigned char> val_type;
988 typedef std::unordered_multimap<key_type, val_type> map_type;
991 map_type side_to_elem_map;
994 std::unique_ptr<Elem> my_side, their_side;
996 for (
const auto & element : this->element_ptr_range())
998 for (
auto ms : element->side_index_range())
1004 if (element->neighbor_ptr(ms) ==
nullptr ||
1010 const dof_id_type key = element->low_order_key(ms);
1013 auto bounds = side_to_elem_map.equal_range(key);
1017 if (bounds.first != bounds.second)
1020 element->side_ptr(my_side, ms);
1023 while (bounds.first != bounds.second)
1026 Elem * neighbor = bounds.first->second.first;
1029 const unsigned int ns = bounds.first->second.second;
1030 neighbor->
side_ptr(their_side, ns);
1041 if ((*my_side == *their_side) &&
1042 (element->level() == neighbor->
level()))
1050 if (element->subactive() ==
1055 element->set_neighbor (ms,neighbor);
1058 else if (element->subactive())
1060 element->set_neighbor(ms,neighbor);
1066 side_to_elem_map.erase (bounds.first);
1078 side_to_elem_map.emplace
1079 (key, std::make_pair(element, cast_int<unsigned char>(ms)));
1085 #ifdef LIBMESH_ENABLE_PERIODIC 1094 for (
const auto & element : this->element_ptr_range())
1096 for (
auto ms : element->side_index_range())
1099 if (element->neighbor_ptr(ms) !=
nullptr &&
1103 for (
const auto & [
id, boundary_ptr] : *db)
1108 unsigned int neigh_side;
1109 const Elem * neigh =
1110 db->neighbor(
id, *point_locator, element, ms, &neigh_side);
1112 if (neigh && neigh !=
remote_elem && neigh != element)
1114 auto neigh_changeable = this->
elem_ptr(neigh->
id());
1116 neigh_changeable->set_neighbor(neigh_side, element);
1122 #endif // LIBMESH_ENABLE_PERIODIC 1124 #ifdef LIBMESH_ENABLE_AMR 1154 for (
unsigned int level = 1; level <
n_levels; ++level)
1156 for (
auto & current_elem :
as_range(level_elements_begin(level),
1157 level_elements_end(level)))
1164 for (
auto s : current_elem->side_index_range())
1166 if (current_elem->neighbor_ptr(s) ==
nullptr ||
1183 (neigh->
level()+1) == current_elem->level())))
1189 bool neigh_has_remote_children =
false;
1192 neigh_has_remote_children =
true;
1197 if (current_elem->active())
1198 libmesh_assert_not_equal_to (current_elem->processor_id(),
1206 else if (neigh && (current_elem->subactive() &&
1219 bool found_neigh =
false;
1220 for (
unsigned int c = 0, nc = neigh->
n_children();
1221 !found_neigh && c != nc; ++c)
1246 if ((!neigh->
active()) && (!current_elem->subactive()))
1250 libMesh::err <<
"Bad element ID = " << current_elem->id()
1251 <<
", Side " << s <<
", Bad neighbor ID = " << neigh->
id() << std::endl;
1252 libMesh::err <<
"Bad element proc_ID = " << current_elem->processor_id()
1253 <<
", Bad neighbor proc_ID = " << neigh->
processor_id() << std::endl;
1254 libMesh::err <<
"Bad element size = " << current_elem->hmin()
1255 <<
", Bad neighbor size = " << neigh->
hmin() << std::endl;
1256 libMesh::err <<
"Bad element center = " << current_elem->vertex_average()
1257 <<
", Bad neighbor center = " << neigh->
vertex_average() << std::endl;
1259 << (current_elem->active()?
"Active":
"Ancestor")
1260 <<
" Element at level " 1261 << current_elem->level() << std::endl;
1263 << (parent->
active()?
"active":
1264 (parent->
subactive()?
"subactive":
"ancestor"))
1266 << (neigh->
subactive()?
"subactive":
"ancestor")
1267 <<
" neighbor at level " << neigh->
level()
1270 libmesh_error_msg(
"Problematic mesh written to bad_mesh.gmv.");
1278 if (current_elem->dim() >= LIBMESH_DIM)
1282 current_elem->set_interior_parent(
nullptr);
1310 current_elem->set_interior_parent
1315 bool child_contains_our_nodes =
true;
1316 for (
auto & n : current_elem->node_ref_range())
1318 bool child_contains_this_node =
false;
1319 for (
auto & cn : child.node_ref_range())
1320 if (cn.absolute_fuzzy_equals
1321 (n, node_tolerance))
1323 child_contains_this_node =
true;
1326 if (!child_contains_this_node)
1328 child_contains_our_nodes =
false;
1332 if (child_contains_our_nodes)
1334 current_elem->set_interior_parent(&child);
1350 !reset_remote_elements);
1364 bool skip_renumber_nodes_and_elements,
1365 bool skip_find_neighbors,
1366 bool skip_detect_interior_parents)
1379 if (skip_renumber_nodes_and_elements)
1382 libmesh_deprecated();
1403 LOG_SCOPE(
"write()",
"Mesh");
1411 const std::vector<Number> & v,
1412 const std::vector<std::string> & vn)
const 1414 LOG_SCOPE(
"write()",
"Mesh");
1436 <<
"mesh for a processor id (=" 1438 <<
") greater than " 1439 <<
"the number of processors available for " 1440 <<
"the calculation. (=" 1448 this->active_pid_elements_begin(pid),
1449 this->active_pid_elements_end(pid));
1476 libmesh_assert_not_equal_to (this->
n_nodes(), 0);
1477 libmesh_assert_not_equal_to (this->
n_elem(), 0);
1480 std::vector<boundary_id_type> bc_ids;
1486 for (
const auto & old_elem :
as_range(it, it_end))
1490 auto uelem = old_elem->disconnected_clone();
1495 for (
auto n : old_elem->node_index_range())
1497 const dof_id_type this_node_id = old_elem->node_id(n);
1505 old_elem->node_ptr(n)->processor_id());
1508 for (
unsigned int i = 0; i != n_node_ints; ++i)
1511 #ifdef LIBMESH_ENABLE_UNIQUE_ID 1521 for (
auto s : old_elem->side_index_range())
1534 #ifdef LIBMESH_ENABLE_AMR 1537 LOG_SCOPE (
"contract()",
"Mesh");
1540 bool mesh_changed =
false;
1543 for (
const auto & elem : this->element_ptr_range())
1544 libmesh_assert(elem->active() || elem->subactive() || elem->ancestor());
1548 for (
auto & elem : this->element_ptr_range())
1551 if (elem->subactive())
1565 mesh_changed =
true;
1592 return mesh_changed;
1594 #endif // #ifdef LIBMESH_ENABLE_AMR 1600 LOG_SCOPE(
"all_first_order()",
"Mesh");
1605 std::vector<bool> node_touched_by_me(this->
max_node_id(),
false);
1610 for (
auto & so_elem : element_ptr_range())
1620 (so_elem->type()), so_elem->parent());
1622 const unsigned short n_sides = so_elem->n_sides();
1624 for (
unsigned short s=0; s != n_sides; ++s)
1628 #ifdef LIBMESH_ENABLE_AMR 1632 if (so_elem->has_children())
1633 for (
unsigned int c = 0, nc = so_elem->n_children(); c != nc; ++c)
1644 if (so_elem->parent())
1647 so_elem->parent()->which_child_am_i(so_elem);
1659 libmesh_assert_equal_to (lo_elem->
n_vertices(), so_elem->n_vertices());
1666 for (
unsigned int v=0, snv=so_elem->n_vertices(); v < snv; v++)
1668 lo_elem->
set_node(v, so_elem->node_ptr(v));
1669 node_touched_by_me[lo_elem->
node_id(v)] =
true;
1676 for (
unsigned short s=0; s != n_sides; s++)
1696 lo_elem->
set_id(so_elem->id());
1697 #ifdef LIBMESH_ENABLE_UNIQUE_ID 1701 const unsigned int nei = so_elem->n_extra_integers();
1703 for (
unsigned int i=0; i != nei; ++i)
1712 for (
const auto & node : this->node_ptr_range())
1713 if (!node_touched_by_me[node->id()])
1733 const bool full_ordered)
1735 LOG_SCOPE(
"all_second_order_range()",
"Mesh");
1742 unsigned int max_new_nodes_per_elem;
1758 max_new_nodes_per_elem = 3 - 2;
1760 (1.5*static_cast<double>(this->
n_nodes())));
1768 max_new_nodes_per_elem = 9 - 4;
1770 (2*static_cast<double>(this->
n_nodes())));
1781 max_new_nodes_per_elem = 27 - 8;
1783 (2.5*static_cast<double>(this->
n_nodes())));
1788 libmesh_error_msg(
"Unknown mesh dimension " << this->
mesh_dimension());
1792 all_increased_order_range(*
this, range, max_new_nodes_per_elem,
1802 LOG_SCOPE(
"all_complete_order()",
"Mesh");
1809 unsigned int max_new_nodes_per_elem;
1825 max_new_nodes_per_elem = 3 - 2;
1827 (1.5*static_cast<double>(this->
n_nodes())));
1836 max_new_nodes_per_elem = 9 - 4;
1838 (2*static_cast<double>(this->
n_nodes())));
1850 max_new_nodes_per_elem = 27 - 8;
1852 (2.5*static_cast<double>(this->
n_nodes())));
1857 libmesh_error_msg(
"Unknown mesh dimension " << this->
mesh_dimension());
1861 all_increased_order_range(*
this, range, max_new_nodes_per_elem,
1873 bool clear_stitched_boundary_ids,
1875 bool use_binary_search,
1876 bool enforce_all_nodes_match_on_boundaries,
1877 bool merge_boundary_nodes_all_or_nothing,
1878 bool remap_subdomain_ids,
1879 bool prepare_after_stitching)
1881 LOG_SCOPE(
"stitch_meshes()",
"UnstructuredMesh");
1883 this_mesh_boundary_id,
1884 other_mesh_boundary_id,
1886 clear_stitched_boundary_ids,
1889 enforce_all_nodes_match_on_boundaries,
1891 merge_boundary_nodes_all_or_nothing,
1892 remap_subdomain_ids,
1893 prepare_after_stitching);
1901 bool clear_stitched_boundary_ids,
1903 bool use_binary_search,
1904 bool enforce_all_nodes_match_on_boundaries,
1905 bool merge_boundary_nodes_all_or_nothing,
1906 bool prepare_after_stitching)
1913 clear_stitched_boundary_ids,
1916 enforce_all_nodes_match_on_boundaries,
1918 merge_boundary_nodes_all_or_nothing,
1920 prepare_after_stitching);
1929 bool clear_stitched_boundary_ids,
1931 bool use_binary_search,
1932 bool enforce_all_nodes_match_on_boundaries,
1933 bool skip_find_neighbors,
1934 bool merge_boundary_nodes_all_or_nothing,
1935 bool remap_subdomain_ids,
1936 bool prepare_after_stitching)
1943 bool is_valid_disjoint_pair_to_stitch =
false;
1945 #ifdef LIBMESH_ENABLE_PERIODIC 1948 const bool have_disc_bdys =
1949 (this_db && !this_db->empty()) || (other_db && !other_db->empty());
1958 return db ? db->
boundary(
id) :
nullptr;
1962 const auto * pb_this_a = get_pb(this_db, a);
1963 const auto * pb_this_b = get_pb(this_db,
b);
1964 const bool in_this =
1965 (pb_this_a && pb_this_a->pairedboundary ==
b) ||
1966 (pb_this_b && pb_this_b->pairedboundary == a);
1969 const auto * pb_other_b = get_pb(other_db,
b);
1970 const auto * pb_other_a = get_pb(other_db, a);
1971 const bool in_other =
1972 (pb_other_b && pb_other_b->pairedboundary == a) ||
1973 (pb_other_a && pb_other_a->pairedboundary ==
b);
1978 if (!in_this && (pb_this_a || pb_this_b) && in_other)
1979 libmesh_error_msg(
"Disjoint neighbor boundary pairing mismatch: on 'this' mesh, " 1980 "boundary (" << a <<
" or " <<
b 1981 <<
") exists but is not paired; on 'other' mesh the pair is present.");
1985 if (!in_other && (pb_other_a || pb_other_b) && in_this)
1986 libmesh_error_msg(
"Disjoint neighbor boundary pairing mismatch: on 'other' mesh, " 1987 "boundary (" << a <<
" or " <<
b 1988 <<
") exists but is not paired; on 'this' mesh the pair is present.");
1991 if (in_this || in_other)
1992 is_valid_disjoint_pair_to_stitch =
true;
1994 #endif // LIBMESH_ENABLE_PERIODIC 2005 std::unique_ptr<MeshSerializer> serialize_other;
2007 serialize_other = std::make_unique<MeshSerializer>
2008 (*
const_cast<MeshBase *
>(other_mesh));
2010 std::map<dof_id_type, dof_id_type> node_to_node_map, other_to_this_node_map;
2011 std::map<dof_id_type, std::vector<dof_id_type>> node_to_elems_map;
2014 typedef std::pair<const Elem *, unsigned char> val_type;
2015 typedef std::pair<key_type, val_type> key_val_pair;
2016 typedef std::unordered_multimap<key_type, val_type> map_type;
2018 map_type side_to_elem_map;
2029 LOG_SCOPE(
"stitch_meshes node merging",
"UnstructuredMesh");
2034 Real h_min = std::numeric_limits<Real>::max();
2035 bool h_min_updated =
false;
2038 std::set<dof_id_type> this_boundary_node_ids, other_boundary_node_ids;
2041 std::unique_ptr<const Elem> side;
2045 boundary_id_type id_array[2] = {this_mesh_boundary_id, other_mesh_boundary_id};
2046 std::set<dof_id_type> * set_array[2] = {&this_boundary_node_ids, &other_boundary_node_ids};
2047 const MeshBase * mesh_array[2] = {
this, other_mesh};
2049 for (
unsigned i=0; i<2; ++i)
2063 if (node_bc_id == id_array[i])
2066 set_array[i]->insert( this_node_id );
2072 std::vector<boundary_id_type> bc_ids;
2079 std::vector<const Elem *> boundary_node_elems;
2081 for (
auto & el : mesh_array[i]->element_ptr_range())
2084 for (
auto side_id : el->side_index_range())
2086 bool should_stitch_this_side =
2087 (el->neighbor_ptr(
side_id) ==
nullptr) ||
2088 (is_valid_disjoint_pair_to_stitch &&
2091 if (should_stitch_this_side)
2096 if (std::find(bc_ids.begin(), bc_ids.end(), id_array[i]) != bc_ids.end())
2098 el->build_side_ptr(side,
side_id);
2099 for (
auto & n : side->node_ref_range())
2100 set_array[i]->insert(n.id());
2102 h_min = std::min(h_min, side->hmin());
2103 h_min_updated =
true;
2106 if (skip_find_neighbors && (i==0))
2108 key_type key = el->low_order_key(
side_id);
2111 val.second = cast_int<unsigned char>(
side_id);
2116 side_to_elem_map.insert (kvp);
2123 for (
auto edge_id : el->edge_index_range())
2125 if (el->is_edge_on_side(edge_id,
side_id))
2130 if (std::find(bc_ids.begin(), bc_ids.end(), id_array[i]) != bc_ids.end())
2132 std::unique_ptr<const Elem> edge (el->build_edge_ptr(edge_id));
2133 for (
auto & n : edge->node_ref_range())
2134 set_array[i]->insert( n.id() );
2136 h_min = std::min(h_min, edge->hmin());
2137 h_min_updated =
true;
2152 if (std::find(bc_ids.begin(), bc_ids.end(), id_array[i]) != bc_ids.end())
2154 boundary_node_elems.push_back(el);
2165 const auto N = boundary_node_elems.size();
2167 for (
auto node_elem_j :
make_range(node_elem_i+1, N))
2170 (boundary_node_elems[node_elem_i]->point(0) - boundary_node_elems[node_elem_j]->point(0)).
norm();
2177 h_min = std::min(h_min, node_sep);
2178 h_min_updated =
true;
2187 libMesh::out <<
"In UnstructuredMesh::stitch_meshes:\n" 2188 <<
"This mesh has " << this_boundary_node_ids.size()
2189 <<
" nodes on boundary `" 2191 <<
"' (" << this_mesh_boundary_id <<
").\n" 2192 <<
"Other mesh has " << other_boundary_node_ids.size()
2193 <<
" nodes on boundary `" 2195 <<
"' (" << other_mesh_boundary_id <<
").\n";
2199 libMesh::out <<
"Minimum edge length on both surfaces is " << h_min <<
".\n";
2203 libMesh::out <<
"No minimum edge length determined on specified surfaces." << std::endl;
2211 libmesh_error_msg_if(h_min < std::numeric_limits<Real>::epsilon(),
2212 "Coincident nodes detected on source and/or target " 2213 "surface, stitching meshes is not possible.");
2218 if (use_binary_search)
2220 #ifndef LIBMESH_HAVE_NANOFLANN 2221 use_binary_search =
false;
2222 libmesh_warning(
"The use_binary_search option in the " 2223 "UnstructuredMesh stitching algorithms requires nanoflann " 2224 "support. Falling back on N^2 search algorithm.");
2228 if (!this_boundary_node_ids.empty())
2230 if (use_binary_search)
2232 #ifdef LIBMESH_HAVE_NANOFLANN 2233 typedef nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<Real, VectorOfNodesAdaptor>,
2237 std::vector<std::pair<Point, dof_id_type>> this_mesh_nodes(this_boundary_node_ids.size());
2239 for (
auto [it, ctr] = std::make_tuple(this_boundary_node_ids.begin(), 0u);
2240 it != this_boundary_node_ids.end(); ++it, ++ctr)
2242 this_mesh_nodes[ctr].first = this->
point(*it);
2243 this_mesh_nodes[ctr].second = *it;
2248 kd_tree_t this_kd_tree(3, vec_nodes_adaptor, 10);
2249 this_kd_tree.buildIndex();
2252 std::size_t ret_index;
2256 for (
const auto & node_id : other_boundary_node_ids)
2258 const auto & p = other_mesh->
point(node_id);
2259 const Real query_pt[] = {p(0), p(1), p(2)};
2260 this_kd_tree.knnSearch(&query_pt[0], 1, &ret_index, &ret_dist_sqr);
2267 node_to_node_map[this_mesh_nodes[ret_index].second] = node_id;
2268 other_to_this_node_map[node_id] = this_mesh_nodes[ret_index].second;
2276 libmesh_error_msg_if(node_to_node_map.size() != other_to_this_node_map.size(),
2277 "Error: Found multiple matching nodes in stitch_meshes");
2290 libmesh_warning(
"No valid h_min value was found, falling back on " 2291 "absolute distance check in the N^2 search algorithm.");
2298 for (
const auto & this_node_id : this_boundary_node_ids)
2302 bool found_matching_nodes =
false;
2304 for (
const auto & other_node_id : other_boundary_node_ids)
2306 const Node & other_node = other_mesh->
node_ref(other_node_id);
2308 Real node_distance = (this_node - other_node).
norm();
2310 if (node_distance < tol*h_min)
2313 libmesh_error_msg_if(found_matching_nodes,
2314 "Error: Found multiple matching nodes in stitch_meshes");
2316 node_to_node_map[this_node_id] = other_node_id;
2317 other_to_this_node_map[other_node_id] = this_node_id;
2319 found_matching_nodes =
true;
2327 for (
auto & el : other_mesh->element_ptr_range())
2334 for (
auto & n : el->node_ref_range())
2335 if (
const auto it = other_to_this_node_map.find(n.id());
2336 it != other_to_this_node_map.end())
2337 node_to_elems_map[it->second].push_back( el->id() );
2342 libMesh::out <<
"In UnstructuredMesh::stitch_meshes:\n" 2343 <<
"Found " << node_to_node_map.size()
2344 <<
" matching nodes.\n" 2348 if (enforce_all_nodes_match_on_boundaries)
2350 std::size_t n_matching_nodes = node_to_node_map.size();
2351 std::size_t this_mesh_n_nodes = this_boundary_node_ids.size();
2352 std::size_t other_mesh_n_nodes = other_boundary_node_ids.size();
2353 libmesh_error_msg_if((n_matching_nodes != this_mesh_n_nodes) || (n_matching_nodes != other_mesh_n_nodes),
2354 "Error: We expected the number of nodes to match.");
2357 if (merge_boundary_nodes_all_or_nothing)
2359 std::size_t n_matching_nodes = node_to_node_map.size();
2360 std::size_t this_mesh_n_nodes = this_boundary_node_ids.size();
2361 std::size_t other_mesh_n_nodes = other_boundary_node_ids.size();
2362 if ((n_matching_nodes != this_mesh_n_nodes) || (n_matching_nodes != other_mesh_n_nodes))
2367 "UnstructuredMesh::stitch_meshes because not " 2368 "all boundary nodes were matched." 2371 node_to_node_map.clear();
2372 other_to_this_node_map.clear();
2373 node_to_elems_map.clear();
2381 libMesh::out <<
"Skip node merging in UnstructuredMesh::stitch_meshes:" << std::endl;
2389 #ifdef LIBMESH_ENABLE_UNIQUE_ID 2397 if (
this!=other_mesh)
2399 LOG_SCOPE(
"stitch_meshes copying",
"UnstructuredMesh");
2401 #ifdef LIBMESH_ENABLE_PERIODIC 2404 if (other_db && !other_db->empty())
2406 for (
const auto & [bdy_id, pb_ptr] : *other_db)
2408 const auto & pb = *pb_ptr;
2415 if (
const auto * existing_pb = this_db->boundary(a))
2416 if ((existing_pb->myboundary == a && existing_pb->pairedboundary ==
b) ||
2417 (existing_pb->myboundary ==
b && existing_pb->pairedboundary == a))
2422 const bool a_exists = bdy_ids.count(a);
2423 const bool b_exists = bdy_ids.count(
b);
2426 if (a_exists && b_exists && !this_db->boundary(a))
2427 libmesh_error_msg(
"Conflict: boundaries " << a <<
" and " <<
b 2428 <<
" already exist on this mesh but are not paired.");
2434 #endif // LIBMESH_ENABLE_PERIODIC 2439 for (
auto & pr : node_to_node_map)
2440 pr.second += node_delta;
2442 for (
auto & pr : node_to_elems_map)
2443 for (
auto & entry : pr.second)
2444 entry += elem_delta;
2466 std::unordered_map<subdomain_id_type, subdomain_id_type> id_remapping;
2467 if (remap_subdomain_ids)
2471 std::unordered_map<std::string, subdomain_id_type> other_map_reversed;
2472 for (
auto & [sid, sname] : other_map)
2473 other_map_reversed.emplace(sname, sid);
2475 std::unordered_map<std::string, subdomain_id_type> this_map_reversed;
2476 for (
auto & [sid, sname] : this_map)
2477 this_map_reversed.emplace(sname, sid);
2482 std::set<subdomain_id_type> all_subdomains;
2483 for (
auto & el :
mesh.element_ptr_range())
2484 all_subdomains.insert(el->subdomain_id());
2485 return all_subdomains;
2488 const auto this_subdomains = get_subdomains(*
this);
2489 const auto other_subdomains = get_subdomains(*other_mesh);
2491 for (
auto & [sid, sname] : this_map)
2496 if (
const auto other_reverse_it = other_map_reversed.find(sname);
2497 other_reverse_it != other_map_reversed.end() && other_reverse_it->second != sid)
2498 id_remapping[other_reverse_it->second] = sid;
2503 if (other_subdomains.count(sid) && !other_map.count(sid))
2504 libmesh_error_msg(
"Can't safely stitch with a mesh sharing subdomain id " 2505 << sid <<
" but not subdomain name " << sname);
2510 if (!this_subdomains.empty())
2511 next_free_id = *this_subdomains.rbegin() + 1;
2512 if (!other_subdomains.empty())
2514 std::max(next_free_id,
2515 cast_int<subdomain_id_type>
2516 (*other_subdomains.rbegin() + 1));
2518 for (
auto & [sid, sname] : other_map)
2523 if (!this_map_reversed.count(sname))
2527 if (this_subdomains.count(sid))
2531 if (!this_map.count(sid))
2532 libmesh_error_msg(
"Can't safely stitch with a mesh sharing subdomain id " 2533 << sid <<
" but under subdomain name " << sname);
2542 libmesh_error_msg_if ((!this_subdomains.empty() &&
2543 next_free_id < *this_subdomains.rbegin()) ||
2544 (!other_subdomains.empty() &&
2545 next_free_id < *other_subdomains.rbegin()),
2546 "Subdomain id overflow");
2548 id_remapping[sid] = next_free_id++;
2562 elem_delta, node_delta,
2563 unique_delta, &id_remapping);
2571 boundary.
add_node(std::get<0>(t) + node_delta,
2575 boundary.
add_side(std::get<0>(t) + elem_delta,
2580 boundary.
add_edge(std::get<0>(t) + elem_delta,
2591 ns_id_to_name.insert(other_ns_id_to_name.begin(), other_ns_id_to_name.end());
2595 ss_id_to_name.insert(other_ss_id_to_name.begin(), other_ss_id_to_name.end());
2599 es_id_to_name.insert(other_es_id_to_name.begin(), other_es_id_to_name.end());
2609 other_mesh->
get_elemsets(elemset_code, other_id_set_to_fill);
2618 this_elemset_codes.end(),
2621 if (it != this_elemset_codes.end())
2629 libmesh_error_msg_if(other_id_set_to_fill != this_id_set_to_fill,
2630 "Attempted to stitch together meshes with conflicting elemset codes.");
2649 LOG_SCOPE(
"stitch_meshes node updates",
"UnstructuredMesh");
2652 std::vector<boundary_id_type> bc_ids;
2654 for (
const auto & [target_node_id, elem_vec] : node_to_elems_map)
2656 dof_id_type other_node_id = node_to_node_map[target_node_id];
2659 std::size_t n_elems = elem_vec.size();
2660 for (std::size_t i=0; i<n_elems; i++)
2666 unsigned int local_node_index = el->
local_node(other_node_id);
2672 el->
set_node(local_node_index, &target_node);
2679 LOG_SCOPE(
"stitch_meshes node deletion",
"UnstructuredMesh");
2680 for (
const auto & [other_node_id, this_node_id] : node_to_node_map)
2684 if ((
this == other_mesh) && (this_node_id == other_node_id))
2698 if (skip_find_neighbors)
2700 LOG_SCOPE(
"stitch_meshes neighbor fixes",
"UnstructuredMesh");
2703 std::unique_ptr<const Elem> my_side, their_side;
2705 std::set<dof_id_type> fixed_elems;
2706 for (
const auto & pr : node_to_elems_map)
2708 std::size_t n_elems = pr.second.size();
2709 for (std::size_t i=0; i<n_elems; i++)
2712 if (!fixed_elems.count(elem_id))
2715 fixed_elems.insert(elem_id);
2718 bool has_real_neighbor = (el->
neighbor_ptr(s) !=
nullptr);
2719 bool has_disdjoint_neighbor = is_valid_disjoint_pair_to_stitch &&
2723 if (!has_real_neighbor || has_disdjoint_neighbor)
2726 auto bounds = side_to_elem_map.equal_range(key);
2728 if (bounds.first != bounds.second)
2734 while (bounds.first != bounds.second)
2737 Elem * neighbor =
const_cast<Elem *
>(bounds.first->second.first);
2740 const unsigned int ns = bounds.first->second.second;
2741 neighbor->
side_ptr(their_side, ns);
2753 if ((*my_side == *their_side) &&
2755 ((el->
dim() != 1) || (ns != s)))
2786 side_to_elem_map.erase (bounds.first);
2800 #ifdef LIBMESH_ENABLE_PERIODIC 2805 if (is_valid_disjoint_pair_to_stitch)
2809 if (prepare_after_stitching)
2827 if (clear_stitched_boundary_ids)
2829 LOG_SCOPE(
"stitch_meshes clear bcids",
"UnstructuredMesh");
2832 this_mesh_boundary_id, other_mesh_boundary_id,
true);
2836 return node_to_node_map.size();
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
GhostingFunctorIterator ghosting_functors_begin() const
Beginning of range of ghosting functors.
void set_p_level(const unsigned int p)
Sets the value of the p-refinement level for the element.
void parallel_for(const Range &range, const Body &body, unsigned int n_threads=libMesh::n_threads())
Execute the provided function object in parallel on the specified range.
bool closed()
Checks that the library has been closed.
ElemType
Defines an enum for geometric element types.
The SimpleRange templated class is intended to make it easy to construct ranges from pairs of iterato...
This class supports simple reads and writes in any libMesh-supported format, by dispatching to one of...
virtual void reserve_nodes(const dof_id_type nn)=0
Reserves space for a known number of nodes.
std::vector< BCTuple > build_shellface_list() const
Create a list of (element_id, shellface_id, boundary_id) tuples for all relevant shellfaces.
const Elem * parent() const
virtual void all_complete_order_range(const SimpleRange< element_iterator > &range) override
Converts a (conforming, non-refined) mesh with linear elements into a mesh with "complete" order elem...
In parallel meshes where a ghost element has neighbors which do not exist on the local processor...
static constexpr processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
virtual Node *& set_node(const unsigned int i)
A Node is like a Point, but with more information.
bool is_ancestor_of(const Elem *descendant) const
const MeshBase & interior_mesh() const
static ElemType complete_order_equivalent_type(const ElemType et)
virtual unique_id_type parallel_max_unique_id() const =0
void set_interior_mesh(MeshBase &int_mesh)
Sets the interior mesh.
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
void set_parent(Elem *p)
Sets the pointer to the element's parent.
std::vector< std::string > _elem_integer_names
The array of names for integer data associated with each element in the mesh.
std::unique_ptr< PointLocatorBase > sub_point_locator() const
const Elem * interior_parent() const
std::vector< dof_id_type > get_elemset_codes() const
Return a vector of all elemset codes defined on the mesh.
virtual void read(const std::string &mesh_file) override
This method implements reading a mesh from a specified file.
IntRange< unsigned short > side_index_range() const
bool ends_with(std::string_view superstring, std::string_view suffix)
Look for a substring at the very end of a string.
The definition of the const_element_iterator struct.
static constexpr Real TOLERANCE
MeshBase * _interior_mesh
Defaulting to this, a pointer to the mesh used to generate boundary elements on this.
We're using a class instead of a typedef to allow forward declarations and future flexibility...
static void set_node_processor_ids(MeshBase &mesh)
This function is called after partitioning to set the processor IDs for the nodes.
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const =0
bool allow_detect_interior_parents() const
size_t kdtree_get_point_count() const
Must return the number of data points.
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly created (or read) mesh for use.
virtual dof_id_type low_order_key(const unsigned int s) const =0
const boundary_id_type side_id
VectorOfNodesAdaptor(const std::vector< std::pair< Point, dof_id_type >> &nodes)
void add_elemset_code(dof_id_type code, MeshBase::elemset_type id_set)
Tabulate a user-defined "code" for elements which belong to the element sets specified in id_set...
const std::map< boundary_id_type, std::string > & get_sideset_name_map() const
This is the base class from which all geometric element types are derived.
PeriodicBoundaryBase * boundary(boundary_id_type id)
void add_child(Elem *elem)
Adds a child pointer to the array of children of this element.
void set_refinement_flag(const RefinementState rflag)
Sets the value of the refinement flag for the element.
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true, const bool assert_valid=true) override
Other functions from MeshBase requiring re-definition.
unique_id_type unique_id() const
const Parallel::Communicator & comm() const
virtual unsigned int n_children() const =0
void boundary_ids(const Node *node, std::vector< boundary_id_type > &vec_to_fill) const
Fills a user-provided std::vector with the boundary ids associated with Node node.
std::map< const Elem *, const CouplingMatrix *, CompareDofObjectsByPIDAndThenID > map_type
What elements do we care about and what variables do we care about on each element?
virtual void own_node(Node &)
Takes ownership of node n on this partition of a distributed mesh, by setting n.processor_id() to thi...
virtual void all_first_order() override
Converts a mesh with higher-order elements into a mesh with linear elements.
The StoredRange class defines a contiguous, divisible set of objects.
GhostingFunctorIterator ghosting_functors_end() const
End of range of ghosting functors.
virtual void set_next_unique_id(unique_id_type id)=0
Sets the next available unique id to be used.
The libMesh namespace provides an interface to certain functionality in the library.
void create_pid_mesh(UnstructuredMesh &pid_mesh, const processor_id_type pid) const
Generates a new mesh containing all the elements which are assigned to processor pid.
std::size_t stitching_helper(const MeshBase *other_mesh, boundary_id_type boundary_id_1, boundary_id_type boundary_id_2, Real tol, bool clear_stitched_boundary_ids, bool verbose, bool use_binary_search, bool enforce_all_nodes_match_on_boundaries, bool skip_find_neighbors, bool merge_boundary_nodes_all_or_nothing, bool remap_subdomain_ids, bool prepare_after_stitching)
Helper function for stitch_meshes and stitch_surfaces that does the mesh stitching.
void allow_detect_interior_parents(bool allow)
If false is passed then this mesh will no longer work to detect interior parents when being prepared ...
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
std::vector< std::string > _node_integer_names
The array of names for integer data associated with each node in the mesh.
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
virtual void all_second_order_range(const SimpleRange< element_iterator > &range, const bool full_ordered=true) override
Converts a (conforming, non-refined) mesh with linear elements into a mesh with second-order elements...
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
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
void set_interior_parent(Elem *p)
Sets the pointer to the element's interior_parent.
uint8_t processor_id_type
This is the MeshBase class.
SimpleRange< ChildRefIter > child_ref_range()
Returns a range with all children of a parent element, usable in range-based for loops.
void get_elemsets(dof_id_type elemset_code, MeshBase::elemset_type &id_set_to_fill) const
Look up the element sets for a given elemset code and vice-versa.
virtual bool contract() override
Delete subactive (i.e.
uint8_t processor_id_type
std::map< boundary_id_type, std::string > & set_sideset_name_map()
void replace_child(Elem *elem, unsigned int c)
Replaces the child pointer at the specified index in the child array.
processor_id_type n_processors() const
virtual bool is_serial() const
void libmesh_ignore(const Args &...)
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
void add_disjoint_neighbor_boundary_pairs(const boundary_id_type b1, const boundary_id_type b2, const RealVectorValue &translation)
Register a pair of boundaries as disjoint neighbor boundary pairs.
const std::map< boundary_id_type, std::string > & get_nodeset_name_map() const
static const boundary_id_type invalid_id
Number used for internal use.
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
This is the MeshCommunication class.
void min(const T &r, T &o, Request &req) const
const std::map< subdomain_id_type, std::string > & get_subdomain_name_map() const
virtual Real hmin() const
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
virtual unsigned int n_nodes() const =0
const ElemRange & element_stored_range()
The UnstructuredMesh class is derived from the MeshBase class.
unsigned int which_neighbor_am_i(const Elem *e) const
This function tells you which neighbor e is.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
PeriodicBoundaries * get_disjoint_neighbor_boundary_pairs()
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
virtual const Node * query_node_ptr(const dof_id_type i) const =0
const std::map< boundary_id_type, std::string > & get_edgeset_name_map() const
virtual dof_id_type max_elem_id() const =0
void clear_point_locator()
Releases the current PointLocator object.
bool allow_find_neighbors() const
virtual void write(const std::string &mesh_file) override
This method implements writing a mesh to a specified file.
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
std::vector< BCTuple > build_edge_list() const
Create a list of (element_id, edge_id, boundary_id) tuples for all relevant edges.
virtual void delete_node(Node *n)=0
Removes the Node n from the mesh.
std::pair< std::vector< unsigned int >, std::vector< unsigned int > > merge_extra_integer_names(const MeshBase &other)
Merge extra-integer arrays from an other mesh.
std::string & subdomain_name(subdomain_id_type id)
void allow_find_neighbors(bool allow)
If false is passed then this mesh will no longer work to find element neighbors when being prepared f...
virtual std::unique_ptr< Elem > disconnected_clone() const
virtual unsigned int n_second_order_adjacent_vertices(const unsigned int n) const
bool allow_remote_element_removal() const
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
virtual void write_nodal_data(const std::string &, const std::vector< Number > &, const std::vector< std::string > &) override
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
void regenerate_id_sets()
Clears and regenerates the cached sets of ids.
virtual void clear()
Deletes all the element and node data that is currently stored.
static ElemType second_order_equivalent_type(const ElemType et, const bool full_ordered=true)
unsigned int which_child_am_i(const Elem *e) const
bool skip_partitioning() const
const std::set< boundary_id_type > & get_boundary_ids() const
unsigned int n_partitions() const
virtual const Elem * elem_ptr(const dof_id_type i) const =0
UnstructuredMesh(const Parallel::Communicator &comm_in, unsigned char dim=1)
Constructor.
Real kdtree_get_pt(const size_t idx, int dim) const
virtual Elem * insert_elem(Elem *e)=0
Insert elem e to the element array, preserving its id and replacing/deleting any existing element wit...
const Elem * neighbor_ptr(unsigned int i) const
Preparation _preparation
Flags indicating in what ways this mesh has been prepared.
std::set< elemset_id_type > elemset_type
Typedef for the "set" container used to store elemset ids.
unsigned int level() const
void set_unique_id(unique_id_type new_id)
Sets the unique_id for this DofObject.
virtual unsigned int n_vertices() const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const std::vector< std::pair< Point, dof_id_type > > _nodes
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
virtual ~UnstructuredMesh()
Destructor.
timpi_pure bool verify(const T &r) const
void copy_boundary_ids(const BoundaryInfo &old_boundary_info, const Elem *const old_elem, const Elem *const new_elem)
void max(const T &r, T &o, Request &req) const
virtual unsigned short dim() const =0
Temporarily serialize a DistributedMesh for non-distributed-mesh capable code paths.
const Node * node_ptr(const unsigned int i) const
std::map< boundary_id_type, std::string > & set_nodeset_name_map()
void clear_stitched_boundary_side_ids(boundary_id_type sideset_id, boundary_id_type other_sideset_id, bool clear_nodeset_data=false)
Clear sideset information along a stitched mesh interface.
void make_nodes_parallel_consistent(MeshBase &)
Copy processor_ids and ids on ghost nodes from their local processors.
virtual bool is_replicated() const
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure...
const std::string & get_sideset_name(boundary_id_type id) const
virtual unsigned short int second_order_adjacent_vertex(const unsigned int n, const unsigned int v) const
void add_shellface(const dof_id_type elem, const unsigned short int shellface, const boundary_id_type id)
Add shell face shellface of element number elem with boundary id id to the boundary information data ...
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
void add_extra_integers(const unsigned int n_integers)
Assigns a set of extra integers to this DofObject.
ForwardIterator binary_find(ForwardIterator first, ForwardIterator last, const T &value)
The STL provides std::binary_search() which returns true or false depending on whether the searched-f...
virtual void copy_nodes_and_elements(const MeshBase &other_mesh, const bool skip_find_neighbors=false, dof_id_type element_id_offset=0, dof_id_type node_id_offset=0, unique_id_type unique_id_offset=0, std::unordered_map< subdomain_id_type, subdomain_id_type > *id_remapping=nullptr, const bool skip_preparation=false)
Deep copy of nodes and elements from another mesh object (used by subclass copy constructors and by m...
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false, bool skip_detect_interior_parents=false) override
Reads the file specified by name.
unsigned int mesh_dimension() const
bool initialized()
Checks that library initialization has been done.
unsigned int n_extra_integers() const
Returns how many extra integers are associated to the DofObject.
std::size_t stitch_surfaces(boundary_id_type boundary_id_1, boundary_id_type boundary_id_2, Real tol=TOLERANCE, bool clear_stitched_boundary_ids=false, bool verbose=true, bool use_binary_search=true, bool enforce_all_nodes_match_on_boundaries=false, bool merge_boundary_nodes_all_or_nothing=false, bool prepare_after_stitching=true)
Similar to stitch_meshes, except that we stitch two adjacent surfaces within this mesh...
virtual const Node & node_ref(const dof_id_type i) const
virtual const Point & point(const dof_id_type i) const =0
unsigned int local_node(const dof_id_type i) const
std::vector< NodeBCTuple > build_node_list(NodeBCTupleSortBy sort_by=NodeBCTupleSortBy::NODE_ID) const
void edge_boundary_ids(const Elem *const elem, const unsigned short int edge, std::vector< boundary_id_type > &vec_to_fill) const
SimpleRange< NeighborPtrIter > neighbor_ptr_range()
Returns a range with all neighbors of an element, usable in range-based for loops.
void set_p_refinement_flag(const RefinementState pflag)
Sets the value of the p-refinement flag for the element.
bool allow_renumbering() const
void inherit_data_from(const Elem &src)
A helper function for copying generic element data (mapping, subdomain, processor) from an element to...
virtual void delete_remote_elements()
When supported, deletes all nonlocal elements of the mesh except for "ghosts" which touch a local ele...
virtual dof_id_type max_node_id() const =0
void remove_disjoint_boundary_pair(const boundary_id_type b1, const boundary_id_type b2)
virtual dof_id_type n_elem() const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
processor_id_type processor_id() const
bool kdtree_get_bbox(BBOX &) const
static ElemType first_order_equivalent_type(const ElemType et)
processor_id_type processor_id() const
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
dof_id_type node_id(const unsigned int i) const
virtual void reserve_elem(const dof_id_type ne)=0
Reserves space for a known number of elements.
bool has_children() const
virtual void write(const std::string &name) const override
Write the file specified by name.
void unset_is_prepared()
Tells this we have done some operation where we should no longer consider ourself prepared...
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
void set_extra_integer(const unsigned int index, const dof_id_type value)
Sets the value on this object of the extra integer associated with index, which should have been obta...
virtual void renumber_nodes_and_elements()=0
After partitioning a mesh it is useful to renumber the nodes and elements so that they lie in contigu...
virtual dof_id_type n_nodes() const =0
This class implements the original default geometry ghosting requirements in libMesh: point neighbors...
std::size_t stitch_meshes(const MeshBase &other_mesh, boundary_id_type this_mesh_boundary, boundary_id_type other_mesh_boundary, Real tol=TOLERANCE, bool clear_stitched_boundary_ids=false, bool verbose=true, bool use_binary_search=true, bool enforce_all_nodes_match_on_boundaries=false, bool merge_boundary_nodes_all_or_nothing=false, bool remap_subdomain_ids=false, bool prepare_after_stitching=true)
Stitch other_mesh to this mesh so that this mesh is the union of the two meshes.
void create_submesh(UnstructuredMesh &new_mesh, const const_element_iterator &it, const const_element_iterator &it_end) const
Constructs a mesh called "new_mesh" from the current mesh by iterating over the elements between it a...
Point vertex_average() const
dof_id_type get_extra_integer(const unsigned int index) const
Gets the value on this object of the extra integer associated with index, which should have been obta...
const Elem * child_ptr(unsigned int i) const
std::map< boundary_id_type, std::string > & set_edgeset_name_map()
void add_edge(const dof_id_type elem, const unsigned short int edge, const boundary_id_type id)
Add edge edge of element number elem with boundary id id to the boundary information data structure...
const RemoteElem * remote_elem