21 #include "libmesh/boundary_info.h"
22 #include "libmesh/elem.h"
23 #include "libmesh/libmesh_logging.h"
24 #include "libmesh/metis_partitioner.h"
25 #include "libmesh/replicated_mesh.h"
26 #include "libmesh/utility.h"
27 #include "libmesh/parallel.h"
28 #include "libmesh/point.h"
29 #ifdef LIBMESH_HAVE_NANOFLANN
30 #include "libmesh/nanoflann.hpp"
34 #include <unordered_map>
35 #include <unordered_set>
46 const std::vector<std::pair<Point, dof_id_type>>
_nodes;
66 libmesh_assert_less (
dim, 3);
70 if (
dim==0)
return p(0);
71 if (
dim==1)
return p(1);
89 #ifdef LIBMESH_ENABLE_UNIQUE_ID
116 this_boundary_info = other_boundary_info;
121 std::vector<boundary_id_type> side_boundaries;
122 other_boundary_info.build_side_boundary_ids(side_boundaries);
125 for (
const auto & side_bnd_id : side_boundaries)
126 this_boundary_info.sideset_name(side_bnd_id) =
127 other_boundary_info.get_sideset_name(side_bnd_id);
130 std::vector<boundary_id_type> node_boundaries;
131 other_boundary_info.build_node_boundary_ids(node_boundaries);
133 for (
const auto & node_bnd_id : node_boundaries)
134 this_boundary_info.nodeset_name(node_bnd_id) =
135 other_boundary_info.get_nodeset_name(node_bnd_id);
137 #ifdef LIBMESH_ENABLE_UNIQUE_ID
151 this_boundary_info = other_boundary_info;
156 std::vector<boundary_id_type> side_boundaries;
157 other_boundary_info.build_side_boundary_ids(side_boundaries);
160 for (
const auto & side_bnd_id : side_boundaries)
161 this_boundary_info.sideset_name(side_bnd_id) =
162 other_boundary_info.get_sideset_name(side_bnd_id);
165 std::vector<boundary_id_type> node_boundaries;
166 other_boundary_info.build_node_boundary_ids(node_boundaries);
168 for (
const auto & node_bnd_id : node_boundaries)
169 this_boundary_info.nodeset_name(node_bnd_id) =
170 other_boundary_info.get_nodeset_name(node_bnd_id);
184 libmesh_assert_less (i, this->
n_nodes());
186 libmesh_assert_equal_to (
_nodes[i]->
id(), i);
196 libmesh_assert_less (i, this->
n_nodes());
198 libmesh_assert_equal_to (
_nodes[i]->
id(), i);
234 libmesh_assert_less (i, this->
n_elem());
236 libmesh_assert_equal_to (
_elements[i]->
id(), i);
246 libmesh_assert_less (i, this->
n_elem());
248 libmesh_assert_equal_to (
_elements[i]->
id(), i);
294 #ifdef LIBMESH_ENABLE_UNIQUE_ID
330 #ifdef LIBMESH_ENABLE_UNIQUE_ID
336 libmesh_assert_less (eid,
_elements.size());
341 libmesh_assert_equal_to (oldelem->id(), eid);
365 std::vector<Elem *>::iterator pos =
_elements.end();
376 std::advance(pos, e->
id());
438 _nodes.push_back (static_cast<Node *>(
nullptr));
448 cast_int<dof_id_type>(
_nodes.size()-1) :
id).release();
453 #ifdef LIBMESH_ENABLE_UNIQUE_ID
480 #ifdef LIBMESH_ENABLE_UNIQUE_ID
497 libmesh_error_msg(
"Error, attempting to insert nullptr node.");
500 libmesh_error_msg(
"Error, cannot insert node with invalid id.");
511 libmesh_error_msg(
"Error, cannot insert node on top of existing node.");
521 #ifdef LIBMESH_ENABLE_UNIQUE_ID
542 libmesh_assert_less (n->
id(),
_nodes.size());
546 std::vector<Node *>::iterator pos;
554 std::advance(pos, n->
id());
558 pos = std::find (
_nodes.begin(),
621 #ifdef LIBMESH_ENABLE_UNIQUE_ID
628 #ifdef LIBMESH_ENABLE_UNIQUE_ID
632 parallel_object_only();
635 this->
comm().max(max_local);
644 LOG_SCOPE(
"renumber_nodes_and_elem()",
"Mesh");
651 std::unordered_set<Node *> connected_nodes;
658 std::vector<Elem *>::iterator in =
_elements.begin();
659 std::vector<Elem *>::iterator out_iter =
_elements.begin();
660 const std::vector<Elem *>::iterator
end =
_elements.end();
662 for (; in !=
end; ++in)
671 el->
set_id (next_free_elem++);
677 connected_nodes.insert(&n);
686 if (n.id() == next_free_node)
689 else if (n.id() > next_free_node)
704 if (
_nodes[src_idx] !=
nullptr)
705 _nodes[src_idx]->set_id (src_idx);
706 _nodes[dst_idx]->set_id (dst_idx);
725 std::vector<Node *>::iterator in =
_nodes.begin();
726 std::vector<Node *>::iterator out_iter =
_nodes.begin();
727 const std::vector<Node *>::iterator
end =
_nodes.end();
729 for (; in !=
end; ++in)
736 if (connected_nodes.find(nd) != connected_nodes.end())
742 nd->
set_id (next_free_node++);
765 std::vector<Node *>::iterator nd =
_nodes.begin();
766 const std::vector<Node *>::iterator
end =
_nodes.end();
768 std::advance (nd, next_free_node);
790 libmesh_assert_equal_to (next_free_elem,
_elements.size());
791 libmesh_assert_equal_to (next_free_node,
_nodes.size());
802 if (this->
_nodes[n] !=
nullptr)
803 this->
_nodes[n]->set_id() = cast_int<dof_id_type>(n);
808 this->
_elements[e]->set_id() = cast_int<dof_id_type>(e);
816 bool clear_stitched_boundary_ids,
818 bool use_binary_search,
819 bool enforce_all_nodes_match_on_boundaries)
821 LOG_SCOPE(
"stitch_meshes()",
"ReplicatedMesh");
823 this_mesh_boundary_id,
824 other_mesh_boundary_id,
826 clear_stitched_boundary_ids,
829 enforce_all_nodes_match_on_boundaries,
836 bool clear_stitched_boundary_ids,
838 bool use_binary_search,
839 bool enforce_all_nodes_match_on_boundaries)
845 clear_stitched_boundary_ids,
848 enforce_all_nodes_match_on_boundaries,
856 bool clear_stitched_boundary_ids,
858 bool use_binary_search,
859 bool enforce_all_nodes_match_on_boundaries,
860 bool skip_find_neighbors)
862 std::map<dof_id_type, dof_id_type> node_to_node_map, other_to_this_node_map;
863 std::map<dof_id_type, std::vector<dof_id_type>> node_to_elems_map;
866 typedef std::pair<Elem *, unsigned char> val_type;
867 typedef std::pair<key_type, val_type> key_val_pair;
868 typedef std::unordered_multimap<key_type, val_type> map_type;
870 map_type side_to_elem_map;
881 LOG_SCOPE(
"stitch_meshes node merging",
"ReplicatedMesh");
886 Real h_min = std::numeric_limits<Real>::max();
887 bool h_min_updated =
false;
890 std::set<dof_id_type> this_boundary_node_ids, other_boundary_node_ids;
893 std::unique_ptr<Elem> side;
897 boundary_id_type id_array[2] = {this_mesh_boundary_id, other_mesh_boundary_id};
898 std::set<dof_id_type> * set_array[2] = {&this_boundary_node_ids, &other_boundary_node_ids};
901 for (
unsigned i=0; i<2; ++i)
912 if (node_bc_id == id_array[i])
915 set_array[i]->insert( this_node_id );
927 if (current_h_min > 0.)
929 h_min = current_h_min;
930 h_min_updated =
true;
940 h_min_updated =
true;
949 std::vector<boundary_id_type> bc_ids;
954 for (
auto side_id : el->side_index_range())
955 if (el->neighbor_ptr(side_id) ==
nullptr)
960 if (std::find(bc_ids.begin(), bc_ids.end(), id_array[i]) != bc_ids.end())
962 el->build_side_ptr(side, side_id);
963 for (
auto & n : side->node_ref_range())
964 set_array[i]->insert(n.id());
966 h_min = std::min(h_min, side->hmin());
967 h_min_updated =
true;
970 if (skip_find_neighbors && (i==0))
972 key_type key = el->key(side_id);
975 val.second = cast_int<unsigned char>(side_id);
980 side_to_elem_map.insert (kvp);
987 for (
auto edge_id : el->edge_index_range())
989 if (el->is_edge_on_side(edge_id, side_id))
994 if (std::find(bc_ids.begin(), bc_ids.end(), id_array[i]) != bc_ids.end())
996 std::unique_ptr<Elem> edge (el->build_edge_ptr(edge_id));
997 for (
auto & n : edge->node_ref_range())
998 set_array[i]->insert( n.id() );
1000 h_min = std::min(h_min, edge->hmin());
1001 h_min_updated =
true;
1013 <<
"This mesh has " << this_boundary_node_ids.size()
1014 <<
" nodes on boundary " << this_mesh_boundary_id <<
".\n"
1015 <<
"Other mesh has " << other_boundary_node_ids.size()
1016 <<
" nodes on boundary " << other_mesh_boundary_id <<
".\n";
1020 libMesh::out <<
"Minimum edge length on both surfaces is " << h_min <<
".\n";
1024 libMesh::out <<
"No elements on specified surfaces." << std::endl;
1031 if (use_binary_search)
1033 #ifndef LIBMESH_HAVE_NANOFLANN
1034 use_binary_search =
false;
1035 libmesh_warning(
"The use_binary_search option in the "
1036 "ReplicatedMesh stitching algorithms requires nanoflann "
1037 "support. Falling back on N^2 search algorithm.");
1041 if (this_boundary_node_ids.size())
1043 if (use_binary_search)
1045 #ifdef LIBMESH_HAVE_NANOFLANN
1046 typedef nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<Real, VectorOfNodesAdaptor>,
VectorOfNodesAdaptor, 3> kd_tree_t;
1049 std::vector<std::pair<Point, dof_id_type>> this_mesh_nodes(this_boundary_node_ids.size());
1050 std::set<dof_id_type>::iterator current_node = this_boundary_node_ids.begin(),
1051 node_ids_end = this_boundary_node_ids.end();
1052 for (
unsigned int ctr = 0; current_node != node_ids_end; ++current_node, ++ctr)
1054 this_mesh_nodes[ctr].first = this->
point(*current_node);
1055 this_mesh_nodes[ctr].second = *current_node;
1060 kd_tree_t this_kd_tree(3, vec_nodes_adaptor, 10);
1061 this_kd_tree.buildIndex();
1064 std::vector<size_t> ret_index(1);
1065 std::vector<Real> ret_dist_sqr(1);
1068 for (
auto node : other_boundary_node_ids)
1071 this_kd_tree.knnSearch(&query_pt[0], 1, &ret_index[0], &ret_dist_sqr[0]);
1074 node_to_node_map[this_mesh_nodes[ret_index[0]].second] =
node;
1075 other_to_this_node_map[
node] = this_mesh_nodes[ret_index[0]].second;
1082 if (node_to_node_map.size() != other_to_this_node_map.size())
1083 libmesh_error_msg(
"Error: Found multiple matching nodes in stitch_meshes");
1096 libmesh_warning(
"No valid h_min value was found, falling back on "
1097 "absolute distance check in the N^2 search algorithm.");
1104 for (
const auto & this_node_id : this_boundary_node_ids)
1108 bool found_matching_nodes =
false;
1110 for (
const auto & other_node_id : other_boundary_node_ids)
1112 const Node & other_node = other_mesh->
node_ref(other_node_id);
1114 Real node_distance = (this_node - other_node).
norm();
1116 if (node_distance < tol*h_min)
1119 if (found_matching_nodes)
1120 libmesh_error_msg(
"Error: Found multiple matching nodes in stitch_meshes");
1122 node_to_node_map[this_node_id] = other_node_id;
1123 other_to_this_node_map[other_node_id] = this_node_id;
1125 found_matching_nodes =
true;
1140 for (
auto & n : el->node_ref_range())
1143 std::map<dof_id_type, dof_id_type>::iterator it =
1144 other_to_this_node_map.find(other_node_id);
1146 if (it != other_to_this_node_map.end())
1149 node_to_elems_map[this_node_id].push_back( el->id() );
1157 <<
"Found " << node_to_node_map.size()
1158 <<
" matching nodes.\n"
1162 if (enforce_all_nodes_match_on_boundaries)
1164 std::size_t n_matching_nodes = node_to_node_map.size();
1165 std::size_t this_mesh_n_nodes = this_boundary_node_ids.size();
1166 std::size_t other_mesh_n_nodes = other_boundary_node_ids.size();
1167 if ((n_matching_nodes != this_mesh_n_nodes) || (n_matching_nodes != other_mesh_n_nodes))
1168 libmesh_error_msg(
"Error: We expected the number of nodes to match.");
1175 libMesh::out <<
"Skip node merging in ReplicatedMesh::stitch_meshes:" << std::endl;
1183 #ifdef LIBMESH_ENABLE_UNIQUE_ID
1191 if (
this!=other_mesh)
1193 LOG_SCOPE(
"stitch_meshes copying",
"ReplicatedMesh");
1197 for (
auto & pr : node_to_node_map)
1198 pr.second += node_delta;
1200 for (
auto & pr : node_to_elems_map)
1201 for (
auto & entry : pr.second)
1202 entry += elem_delta;
1207 elem_delta, node_delta,
1216 boundary.
add_node(std::get<0>(t) + node_delta,
1220 boundary.
add_side(std::get<0>(t) + elem_delta,
1225 boundary.
add_edge(std::get<0>(t) + elem_delta,
1244 LOG_SCOPE(
"stitch_meshes node updates",
"ReplicatedMesh");
1247 std::vector<boundary_id_type> bc_ids;
1249 for (
const auto & pr : node_to_elems_map)
1252 dof_id_type other_node_id = node_to_node_map[target_node_id];
1255 std::size_t n_elems = pr.second.size();
1256 for (std::size_t i=0; i<n_elems; i++)
1262 unsigned int local_node_index = el->
local_node(other_node_id);
1268 el->
set_node(local_node_index) = &target_node;
1275 LOG_SCOPE(
"stitch_meshes node deletion",
"ReplicatedMesh");
1276 for (
const auto & pr : node_to_node_map)
1280 if ((
this == other_mesh) && (pr.second == pr.first))
1295 if (skip_find_neighbors)
1297 LOG_SCOPE(
"stitch_meshes neighbor fixes",
"ReplicatedMesh");
1300 std::unique_ptr<Elem> my_side, their_side;
1302 std::set<dof_id_type> fixed_elems;
1303 for (
const auto & pr : node_to_elems_map)
1305 std::size_t n_elems = pr.second.size();
1306 for (std::size_t i=0; i<n_elems; i++)
1309 if (fixed_elems.find(elem_id) == fixed_elems.end())
1312 fixed_elems.insert(elem_id);
1317 key_type key = el->
key(s);
1318 auto bounds = side_to_elem_map.equal_range(key);
1320 if (bounds.first != bounds.second)
1326 while (bounds.first != bounds.second)
1329 Elem * neighbor = bounds.first->second.first;
1332 const unsigned int ns = bounds.first->second.second;
1333 neighbor->
side_ptr(their_side, ns);
1345 if ((*my_side == *their_side) &&
1347 ((el->
dim() != 1) || (ns != s)))
1378 side_to_elem_map.erase (bounds.first);
1396 if (clear_stitched_boundary_ids)
1398 LOG_SCOPE(
"stitch_meshes clear bcids",
"ReplicatedMesh");
1401 std::vector<boundary_id_type> bc_ids;
1404 for (
auto side_id : el->side_index_range())
1405 if (el->neighbor_ptr(side_id) !=
nullptr)
1411 if (std::find(bc_ids.begin(), bc_ids.end(), this_mesh_boundary_id) != bc_ids.end() ||
1412 std::find(bc_ids.begin(), bc_ids.end(), other_mesh_boundary_id) != bc_ids.end())
1430 std::vector<dof_id_type>
1434 std::vector<dof_id_type> representative_elem_ids;
1439 std::vector<subdomain_id_type> subdomains;
1450 std::vector<Elem *> list;
1461 list.push_back(
elem);
1462 (*subdomain_ids)[
elem->
id()] = subdomain_counter;
1468 dof_id_type min_id = std::numeric_limits<dof_id_type>::max();
1469 while (list.size() > 0)
1472 Elem *
elem = list.back(); list.pop_back(); ++visited;
1474 min_id = std::min(
elem->
id(), min_id);
1483 list.push_back(neighbor);
1484 (*subdomain_ids)[neighbor->
id()] = subdomain_counter;
1489 representative_elem_ids.push_back(min_id);
1490 subdomain_counter++;
1492 while (visited != n_active);
1494 return representative_elem_ids;
1497 std::unordered_map<dof_id_type, std::vector<std::vector<Point>>>
1501 libmesh_error_msg(
"Error: get_boundary_points only works for 2D now");
1505 std::vector<subdomain_id_type> subdomains;
1508 std::unordered_map<dof_id_type, std::vector<std::vector<Point>>> boundary_points;
1512 struct boundary_side_compare
1514 bool operator()(
const std::pair<const Elem *, unsigned int> & lhs,
1515 const std::pair<const Elem *, unsigned int> & rhs)
const
1517 if (lhs.first->id() < rhs.first->id())
1519 else if (lhs.first->id() == rhs.first->id())
1521 if (lhs.second < rhs.second)
1527 std::set<std::pair<const Elem *, unsigned int>, boundary_side_compare> boundary_elements;
1531 boundary_elements.insert(std::pair<const Elem *, unsigned int>(
elem, s));
1533 while (!boundary_elements.empty())
1536 const Elem * eseed = boundary_elements.begin()->first;
1537 unsigned int sseed = boundary_elements.begin()->second;
1543 std::vector<Point> bpoints;
1545 unsigned int s = sseed;
1549 std::pair<const Elem *, unsigned int> side(
elem, s);
1550 libmesh_assert(boundary_elements.find(side) != boundary_elements.end());
1551 boundary_elements.erase(side);
1556 bpoints.push_back(*static_cast<const Point *>(
elem->
node_ptr(local_side_nodes[i])));
1560 std::set<const Elem *> neighbors;
1564 if (neighbors.size() != 1)
1565 neighbors.erase(
elem);
1569 for (
const auto & neighbor : neighbors)
1571 for (
auto ss : neighbor->side_index_range())
1572 if (neighbor->neighbor_ptr(ss) ==
nullptr && !(
elem == neighbor && s == ss))
1574 local_side_nodes = neighbor->nodes_on_side(ss);
1576 if (neighbor->node_ptr(local_side_nodes[0]) ==
node)
1583 else if (neighbor->node_ptr(local_side_nodes[1]) ==
node)
1589 auto temp(local_side_nodes);
1590 local_side_nodes[0] = temp[1];
1591 local_side_nodes[1] = temp[0];
1592 for (
unsigned int i = 2; i < temp.size(); ++i)
1593 local_side_nodes[temp.size() + 1 - i] = temp[i];
1601 libmesh_error_msg(
"ERROR: mesh topology error on visiting boundary sides");
1604 if (
elem == eseed && s == sseed)
1607 boundary_points[elem_ids[subdomain_id]].push_back(bpoints);
1610 return boundary_points;