Line data Source code
1 : // The libMesh Finite Element Library. 2 : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 3 : 4 : // This library is free software; you can redistribute it and/or 5 : // modify it under the terms of the GNU Lesser General Public 6 : // License as published by the Free Software Foundation; either 7 : // version 2.1 of the License, or (at your option) any later version. 8 : 9 : // This library is distributed in the hope that it will be useful, 10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 : // Lesser General Public License for more details. 13 : 14 : // You should have received a copy of the GNU Lesser General Public 15 : // License along with this library; if not, write to the Free Software 16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 : 18 : 19 : // Local Includes 20 : #include "libmesh/ghost_point_neighbors.h" 21 : 22 : #include "libmesh/elem.h" 23 : #include "libmesh/remote_elem.h" 24 : #ifdef LIBMESH_ENABLE_PERIODIC 25 : #include "libmesh/periodic_boundaries.h" 26 : #include "libmesh/boundary_info.h" 27 : #endif 28 : 29 : // C++ Includes 30 : #include <unordered_set> 31 : #include <set> 32 : #include <vector> 33 : 34 : namespace libMesh 35 : { 36 : 37 1117280 : void GhostPointNeighbors::operator() 38 : (const MeshBase::const_element_iterator & range_begin, 39 : const MeshBase::const_element_iterator & range_end, 40 : processor_id_type p, 41 : GhostPointNeighbors::map_type & coupled_elements) 42 : { 43 983 : libmesh_assert(_mesh); 44 : 45 : #ifdef LIBMESH_ENABLE_PERIODIC 46 : bool check_periodic_bcs = 47 1117280 : (_periodic_bcs && !_periodic_bcs->empty()); 48 : 49 1116297 : std::unique_ptr<PointLocatorBase> point_locator; 50 983 : if (check_periodic_bcs) 51 0 : point_locator = _mesh->sub_point_locator(); 52 : 53 1966 : std::set<const Elem *> periodic_elems_examined; 54 1117280 : const BoundaryInfo & binfo = _mesh->get_boundary_info(); 55 1966 : std::vector<boundary_id_type> appn_bcids; 56 1966 : std::vector<const Elem *> active_periodic_neighbors; 57 : #endif 58 : 59 : // Using a connected_nodes set rather than point_neighbors() would 60 : // give us correct results even in corner cases, such as where two 61 : // elements meet only at a corner. ;-) 62 : // 63 : // std::unordered_set<const Node *> connected_nodes; 64 : // 65 : // Unfortunately, it's not a *fast* enough test to use on a 66 : // ReplicatedMesh (where it's O(Nprocs) times slower), or as a 67 : // coupling functor (where it's O(Nelem/Nprocs) times slower), or as 68 : // a coupling functor on a ReplicatedMesh (where you might as well 69 : // just give up now) 70 : 71 : // Links between boundary and interior elements on mixed 72 : // dimensional meshes also give us correct ghosting in this way. 73 1966 : std::unordered_set<const Elem *> interior_parents; 74 : 75 : // We also preserve neighbors and their neighboring children for 76 : // active local elements - in most cases this is redundant with the 77 : // node check, but for non-conforming Tet4 meshes and 78 : // non-level-one-conforming 2D+3D meshes it is possible for an 79 : // element and its coarse neighbor to not share any vertices. 80 : // 81 : // We also preserve interior parents for active pid elements 82 : 83 : 84 : // This code is just for geometric coupling, so we use a null 85 : // CouplingMatrix pointer. We'll declare that here so as to avoid 86 : // confusing the insert() calls later. 87 1117280 : CouplingMatrix * nullcm = nullptr; 88 : 89 20981939 : for (const auto & elem : as_range(range_begin, range_end)) 90 : { 91 13484 : libmesh_assert(_mesh->query_elem_ptr(elem->id()) == elem); 92 : 93 9387665 : if (elem->processor_id() != p) 94 5856 : coupled_elements.emplace(elem, nullcm); 95 : 96 26968 : std::set<const Elem *> elem_point_neighbors; 97 9387665 : elem->find_point_neighbors(elem_point_neighbors); 98 : 99 277202051 : for (const auto & neigh : elem_point_neighbors) 100 267814386 : if (neigh->processor_id() != p) 101 87038326 : coupled_elements.emplace(neigh, nullcm); 102 : 103 : // An interior_parent isn't on the same manifold so won't be 104 : // found as a point neighbor, and it may not share nodes so we 105 : // can't use a connected_nodes test. 106 : // 107 : // Trying to preserve interior_parent() only works if it's on 108 : // the same Mesh, which is *not* guaranteed! So we'll 109 : // double-check. 110 9387665 : const Elem * ip = elem->interior_parent(); 111 9387713 : if (ip && ip->processor_id() != p && 112 72 : _mesh->query_elem_ptr(ip->id()) == ip) 113 0 : coupled_elements.emplace(ip, nullcm); 114 : 115 : #ifdef LIBMESH_ENABLE_PERIODIC 116 9387665 : if (check_periodic_bcs) 117 : { 118 0 : for (const auto s : elem->side_index_range()) 119 : { 120 0 : if (elem->neighbor_ptr(s)) 121 0 : continue; 122 : 123 : const Elem * const equal_level_periodic_neigh = elem->topological_neighbor 124 0 : (s, *_mesh, *point_locator, _periodic_bcs); 125 : 126 0 : if (!equal_level_periodic_neigh || equal_level_periodic_neigh == remote_elem) 127 0 : continue; 128 : 129 : #ifdef LIBMESH_ENABLE_AMR 130 0 : equal_level_periodic_neigh->active_family_tree_by_topological_neighbor( 131 : active_periodic_neighbors, 132 : elem, 133 0 : *_mesh, 134 0 : *point_locator, 135 : _periodic_bcs, 136 : /*reset=*/true); 137 : #else 138 : active_periodic_neighbors = { equal_level_periodic_neigh }; 139 : #endif 140 : 141 0 : for (const Elem * const active_periodic_neigh : active_periodic_neighbors) 142 : { 143 0 : std::set <const Elem *> active_periodic_point_neighbors; 144 : 145 : // This fills point neighbors *including* 146 : // active_periodic_neigh. The documentation for this method 147 : // states that this will return *active* point neighbors 148 0 : active_periodic_neigh->find_point_neighbors(active_periodic_point_neighbors); 149 : 150 0 : for (const Elem * const appn : active_periodic_point_neighbors) 151 : { 152 : // Don't need to ghost RemoteElem or an element we already own or an 153 : // element we've already examined 154 0 : if (appn == remote_elem || appn->processor_id() == p || 155 0 : periodic_elems_examined.count(appn)) 156 0 : continue; 157 : 158 : // We only need to keep point neighbors that are along the periodic boundaries 159 0 : bool on_periodic_boundary = false; 160 0 : for (const auto appn_s : appn->side_index_range()) 161 : { 162 0 : binfo.boundary_ids(appn, appn_s, appn_bcids); 163 0 : for (const auto appn_bcid : appn_bcids) 164 0 : if (_periodic_bcs->find(appn_bcid) != _periodic_bcs->end()) 165 : { 166 0 : on_periodic_boundary = true; 167 0 : goto jump; 168 : } 169 : } 170 0 : jump: 171 0 : if (on_periodic_boundary) 172 0 : coupled_elements.emplace(appn, nullcm); 173 : 174 0 : periodic_elems_examined.insert(appn); 175 : } 176 : } 177 : } 178 : } 179 : #endif // LIBMESH_ENABLE_PERIODIC 180 1115314 : } 181 1117280 : } 182 : 183 1396379 : void GhostPointNeighbors::mesh_reinit() 184 : { 185 : // Unless we have periodic boundary conditions, we don't need 186 : // anything precomputed. 187 : #ifdef LIBMESH_ENABLE_PERIODIC 188 1396379 : if (!_periodic_bcs || _periodic_bcs->empty()) 189 25422 : return; 190 : #endif 191 : 192 : // If we do have periodic boundary conditions, we'll need a master 193 : // point locator, so we'd better have a mesh to build it on. 194 0 : libmesh_assert(_mesh); 195 : 196 : // Make sure an up-to-date master point locator has been 197 : // constructed; we'll need to grab sub-locators soon. 198 0 : _mesh->sub_point_locator(); 199 : } 200 : 201 : } // namespace libMesh