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"
62std::map<std::vector<dof_id_type>,
Node *>::iterator
63map_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;
95void 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 libmesh_assert_less (hon_begin, hon_end);
122 libmesh_assert_less_equal
123 (hon_end-hon_begin, max_new_nodes_per_elem);
125 for (
unsigned int hon=hon_begin; hon<hon_end; hon++)
127 auto pos = map_hi_order_node(hon, *hi_elem, adj_vertices_to_ho_nodes);
132 const auto & adjacent_vertices_ids = pos->first;
141 Point new_location = 0;
142 for (
dof_id_type vertex_id : adjacent_vertices_ids)
143 new_location +=
mesh.point(vertex_id);
145 new_location /=
static_cast<Real>(adjacent_vertices_ids.size());
178#ifdef LIBMESH_ENABLE_UNIQUE_ID
180 max_new_nodes_per_elem * lo_elem.
id() +
192 pos->second = hi_node;
194 hi_elem->set_node(hon, hi_node);
199 Node * hi_node = pos->second;
203 hi_elem->set_node(hon, hi_node);
218 chosen_pid == my_pid)
231 for (
auto s : lo_elem.side_index_range())
240 libmesh_assert_equal_to (neigh->
level(), 0);
248 hi_elem->set_neighbor(s, neigh);
261 if (
auto parent_exterior_it = exterior_children_of.find(interior_p);
262 parent_exterior_it != exterior_children_of.end())
264 auto & exteriors = parent_exterior_it->second;
266 if (exteriors[i] == &lo_elem)
268 exteriors[i] = hi_elem.get();
277 if (
auto exterior_it = exterior_children_of.find(&lo_elem);
278 exterior_it != exterior_children_of.end())
280 for (
Elem * exterior_elem : exterior_it->second)
283 exterior_elem->set_interior_parent(hi_elem.get());
306 hi_elem->set_id(lo_elem.
id());
307#ifdef LIBMESH_ENABLE_UNIQUE_ID
308 hi_elem->set_unique_id(lo_elem.
unique_id());
312 hi_elem->add_extra_integers(nei);
313 for (
unsigned int i=0; i != nei; ++i)
316 hi_elem->inherit_data_from(lo_elem);
322template <
typename ElemTypeConverter>
326 const unsigned int max_new_nodes_per_elem,
327 const ElemTypeConverter & elem_type_converter)
362 auto is_higher_order = [&elem_type_converter](
const Elem * elem) {
364 ElemType new_type = elem_type_converter(old_type);
365 return old_type == new_type;
368 bool already_higher_order =
369 std::all_of(range.
begin(), range.
end(), is_higher_order);
373 if (already_higher_order)
391 std::map<std::vector<dof_id_type>,
Node *> adj_vertices_to_ho_nodes;
399 std::unordered_map<Elem *, std::vector<Elem *>> exterior_children_of;
407#ifdef LIBMESH_ENABLE_UNIQUE_ID
433 auto track_if_necessary = [&adj_vertices_to_ho_nodes,
434 &exterior_children_of,
435 &elem_type_converter](
Elem * elem) {
438 if (elem->default_order() !=
FIRST)
441 auto pos = map_hi_order_node(hon, *elem, adj_vertices_to_ho_nodes);
442 pos->second = elem->node_ptr(hon);
445 const ElemType old_type = elem->type();
446 const ElemType new_type = elem_type_converter(old_type);
447 if (old_type != new_type)
448 exterior_children_of.emplace(elem, std::vector<Elem *>());
454 if (range.
begin() ==
mesh.elements_begin() &&
455 range.
end() ==
mesh.elements_end())
457 for (
auto & elem : range)
458 track_if_necessary(elem);
465 point_neighbor_finder(range.
begin(), range.
end(),
467 point_neighbor_elements);
469 for (
auto & [elem, coupling_map] : point_neighbor_elements)
472 track_if_necessary(
const_cast<Elem *
>(elem));
480 for (
auto & elem :
mesh.element_ptr_range())
481 if (auto exterior_map_it = exterior_children_of.find(elem->interior_parent());
482 exterior_map_it != exterior_children_of.end())
483 exterior_map_it->second.push_back(elem);
491 for (
auto & lo_elem : range)
496 const ElemType new_type = elem_type_converter(old_type);
498 if (old_type == new_type)
502 libmesh_assert_equal_to (lo_elem->
level(), 0);
505 ++n_unpartitioned_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,
706 newn->add_extra_integers(n_new_node_ints);
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) :
733 auto el = old->disconnected_clone();
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)
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());
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())
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());
1115 element->set_neighbor(ms, neigh_changeable);
1116 neigh_changeable->set_neighbor(neigh_side, element);
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(),
1199 this->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;
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;
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.");
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();
void max(const T &r, T &o, Request &req) const
void min(const T &r, T &o, Request &req) const
timpi_pure bool verify(const T &r) const
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
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 ...
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.
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
std::vector< NodeBCTuple > build_node_list(NodeBCTupleSortBy sort_by=NodeBCTupleSortBy::NODE_ID) const
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
void edge_boundary_ids(const Elem *const elem, const unsigned short int edge, std::vector< boundary_id_type > &vec_to_fill) const
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.
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.
std::map< boundary_id_type, std::string > & set_sideset_name_map()
std::vector< BCTuple > build_shellface_list() const
Create a list of (element_id, shellface_id, boundary_id) tuples for all relevant shellfaces.
void copy_boundary_ids(const BoundaryInfo &old_boundary_info, const Elem *const old_elem, const Elem *const new_elem)
const std::set< boundary_id_type > & get_boundary_ids() const
const std::string & get_sideset_name(boundary_id_type id) const
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
static const boundary_id_type invalid_id
Number used for internal use.
std::map< boundary_id_type, std::string > & set_edgeset_name_map()
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.
void regenerate_id_sets()
Clears and regenerates the cached sets of ids.
std::vector< BCTuple > build_edge_list() const
Create a list of (element_id, edge_id, boundary_id) tuples for all relevant edges.
const std::map< boundary_id_type, std::string > & get_edgeset_name_map() const
const std::map< boundary_id_type, std::string > & get_nodeset_name_map() const
std::map< boundary_id_type, std::string > & set_nodeset_name_map()
const std::map< boundary_id_type, std::string > & get_sideset_name_map() 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...
unsigned int n_extra_integers() const
Returns how many extra integers are associated to the DofObject.
processor_id_type processor_id() const
void add_extra_integers(const unsigned int n_integers)
Assigns a set of extra integers to this DofObject.
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
unique_id_type unique_id() const
static constexpr processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
void set_unique_id(unique_id_type new_id)
Sets the unique_id for this DofObject.
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...
This is the base class from which all geometric element types are derived.
virtual Node *& set_node(const unsigned int i)
void set_p_refinement_flag(const RefinementState pflag)
Sets the value of the p-refinement flag for the element.
SimpleRange< NeighborPtrIter > neighbor_ptr_range()
Returns a range with all neighbors of an element, usable in range-based for loops.
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const =0
bool is_ancestor_of(const Elem *descendant) const
virtual unsigned int n_vertices() const =0
bool has_children() const
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
virtual unsigned int n_nodes() const =0
const Elem * parent() const
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
static ElemType complete_order_equivalent_type(const ElemType et)
const Elem * child_ptr(unsigned int i) const
unsigned int which_neighbor_am_i(const Elem *e) const
This function tells you which neighbor e is.
virtual dof_id_type low_order_key(const unsigned int s) const =0
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
void set_interior_parent(Elem *p)
Sets the pointer to the element's interior_parent.
static ElemType first_order_equivalent_type(const ElemType et)
virtual unsigned int n_second_order_adjacent_vertices(const unsigned int n) const
unsigned int local_node(const dof_id_type i) const
unsigned int which_child_am_i(const Elem *e) const
virtual Real hmin() const
static ElemType second_order_equivalent_type(const ElemType et, const bool full_ordered=true)
virtual unsigned short dim() const =0
SimpleRange< ChildRefIter > child_ref_range()
Returns a range with all children of a parent element, usable in range-based for loops.
unsigned int level() const
void set_parent(Elem *p)
Sets the pointer to the element's parent.
const Node * node_ptr(const unsigned int i) const
void add_child(Elem *elem)
Adds a child pointer to the array of children of this element.
void replace_child(Elem *elem, unsigned int c)
Replaces the child pointer at the specified index in the child array.
virtual unsigned int n_children() const =0
virtual ElemType type() const =0
const Elem * interior_parent() const
void set_refinement_flag(const RefinementState rflag)
Sets the value of the refinement flag for the element.
dof_id_type node_id(const unsigned int i) const
virtual unsigned short int second_order_adjacent_vertex(const unsigned int n, const unsigned int v) const
void set_p_level(const unsigned int p)
Sets the value of the p-refinement level for the element.
const Elem * neighbor_ptr(unsigned int i) const
Point vertex_average() const
IntRange< unsigned short > side_index_range() const
void inherit_data_from(const Elem &src)
A helper function for copying generic element data (mapping, subdomain, processor) from an element to...
This class implements the original default geometry ghosting requirements in libMesh: point neighbors...
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?
This is the MeshBase class.
void set_subdomain_name(subdomain_id_type id, const std::string &name, bool synchronous=false)
Sets the name for the provided id.
virtual const Node & node_ref(const dof_id_type i) const
virtual const Point & point(const dof_id_type i) const =0
virtual bool is_serial() const
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
bool allow_renumbering() const
virtual const Node * node_ptr(const dof_id_type i) const =0
unsigned int mesh_dimension() const
virtual dof_id_type n_elem() const =0
virtual bool is_replicated() const
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 Elem * insert_elem(Elem *e)=0
Insert elem e to the element array, preserving its id and replacing/deleting any existing element wit...
bool skip_partitioning() const
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...
bool allow_detect_interior_parents() const
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...
PeriodicBoundaries * get_disjoint_neighbor_boundary_pairs()
const std::map< subdomain_id_type, std::string > & get_subdomain_name_map() const
virtual void delete_node(Node *n)=0
Removes the Node n from the mesh.
const ElemRange & element_stored_range()
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.
std::vector< dof_id_type > get_elemset_codes() const
Return a vector of all elemset codes defined on the mesh.
virtual dof_id_type n_nodes() const =0
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
virtual dof_id_type max_node_id() const =0
virtual const Node * query_node_ptr(const dof_id_type i) const =0
GhostingFunctorIterator ghosting_functors_begin() const
Beginning of range of ghosting functors.
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.
virtual const Elem * elem_ptr(const dof_id_type i) const =0
std::vector< std::string > _elem_integer_names
The array of names for integer data associated with each element in the mesh.
unsigned int n_partitions() const
virtual void set_next_unique_id(unique_id_type id)=0
Sets the next available unique id to be used.
virtual dof_id_type max_elem_id() const =0
virtual void delete_remote_elements()
When supported, deletes all nonlocal elements of the mesh except for "ghosts" which touch a local ele...
MeshBase * _interior_mesh
Defaulting to this, a pointer to the mesh used to generate boundary elements on this.
virtual void clear()
Deletes all the element and node data that is currently stored.
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.
const MeshBase & interior_mesh() const
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.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
bool allow_remote_element_removal() const
bool allow_find_neighbors() const
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.
void remove_disjoint_boundary_pair(const boundary_id_type b1, const boundary_id_type b2)
void clear_point_locator()
Releases the current PointLocator object.
virtual void reserve_elem(const dof_id_type ne)=0
Reserves space for a known number of elements.
GhostingFunctorIterator ghosting_functors_end() const
End of range of ghosting functors.
std::set< elemset_id_type > elemset_type
Typedef for the "set" container used to store elemset ids.
std::vector< std::string > _node_integer_names
The array of names for integer data associated with each node in the mesh.
std::unique_ptr< PointLocatorBase > sub_point_locator() const
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.
virtual void update_parallel_id_counts()=0
Updates parallel caches so that methods like n_elem() accurately reflect changes on other processors.
Preparation _preparation
Flags indicating in what ways this mesh has been prepared.
void set_interior_mesh(MeshBase &int_mesh)
Sets the interior mesh.
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 ...
virtual void reserve_nodes(const dof_id_type nn)=0
Reserves space for a known number of nodes.
void unset_is_prepared()
Tells this we have done some operation where we should no longer consider ourself prepared.
virtual unique_id_type parallel_max_unique_id() const =0
This is the MeshCommunication class.
void make_nodes_parallel_consistent(MeshBase &)
Copy processor_ids and ids on ghost nodes from their local processors.
Temporarily serialize a DistributedMesh for non-distributed-mesh capable code paths.
This class supports simple reads and writes in any libMesh-supported format, by dispatching to one of...
virtual void read(const std::string &mesh_file) override
This method implements reading a mesh from a specified file.
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...
virtual void write(const std::string &mesh_file) override
This method implements writing a mesh to a specified file.
A Node is like a Point, but with more information.
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
static void set_node_processor_ids(MeshBase &mesh)
This function is called after partitioning to set the processor IDs for the nodes.
We're using a class instead of a typedef to allow forward declarations and future flexibility.
PeriodicBoundaryBase * boundary(boundary_id_type id)
A Point defines a location in LIBMESH_DIM dimensional Real space.
In parallel meshes where a ghost element has neighbors which do not exist on the local processor,...
The SimpleRange templated class is intended to make it easy to construct ranges from pairs of iterato...
The StoredRange class defines a contiguous, divisible set of objects.
The UnstructuredMesh class is derived from the MeshBase class.
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 void all_first_order() override
Converts a mesh with higher-order elements into a mesh with linear elements.
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.
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 write(const std::string &name) const override
Write the file specified by name.
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.
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.
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...
virtual bool contract() override
Delete subactive (i.e.
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.
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 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...
UnstructuredMesh(const Parallel::Communicator &comm_in, unsigned char dim=1)
Constructor.
virtual ~UnstructuredMesh()
Destructor.
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.
Real kdtree_get_pt(const size_t idx, int dim) const
size_t kdtree_get_point_count() const
Must return the number of data points.
VectorOfNodesAdaptor(const std::vector< std::pair< Point, dof_id_type > > &nodes)
bool kdtree_get_bbox(BBOX &) const
const std::vector< std::pair< Point, dof_id_type > > _nodes
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.
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...
bool ends_with(std::string_view superstring, std::string_view suffix)
Look for a substring at the very end of a string.
The libMesh namespace provides an interface to certain functionality in the library.
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
bool closed()
Checks that the library has been closed.
ElemType
Defines an enum for geometric element types.
void libmesh_ignore(const Args &...)
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
const RemoteElem * remote_elem
bool initialized()
Checks that library initialization has been done.
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
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...
const boundary_id_type side_id
The definition of the const_element_iterator struct.
const dof_id_type n_nodes