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;