Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2026 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 1183783 : 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 1025 : libmesh_assert(_mesh);
44 :
45 : #ifdef LIBMESH_ENABLE_PERIODIC
46 : const bool check_periodic_bcs =
47 1183783 : (_periodic_bcs && !_periodic_bcs->empty());
48 :
49 1183783 : auto * db = _mesh->get_disjoint_neighbor_boundary_pairs();
50 1183783 : const bool check_disjoint_bcs = (db && !db->empty());
51 :
52 1182758 : std::unique_ptr<PointLocatorBase> point_locator;
53 1183783 : if (check_periodic_bcs || check_disjoint_bcs)
54 3328 : point_locator = _mesh->sub_point_locator();
55 :
56 2050 : std::set<const Elem *> periodic_elems_examined;
57 1183783 : const BoundaryInfo & binfo = _mesh->get_boundary_info();
58 2050 : std::vector<boundary_id_type> appn_bcids;
59 2050 : std::vector<const Elem *> active_periodic_neighbors;
60 : #endif
61 :
62 : // Using a connected_nodes set rather than point_neighbors() would
63 : // give us correct results even in corner cases, such as where two
64 : // elements meet only at a corner. ;-)
65 : //
66 : // std::unordered_set<const Node *> connected_nodes;
67 : //
68 : // Unfortunately, it's not a *fast* enough test to use on a
69 : // ReplicatedMesh (where it's O(Nprocs) times slower), or as a
70 : // coupling functor (where it's O(Nelem/Nprocs) times slower), or as
71 : // a coupling functor on a ReplicatedMesh (where you might as well
72 : // just give up now)
73 :
74 : // Links between boundary and interior elements on mixed
75 : // dimensional meshes also give us correct ghosting in this way.
76 2050 : std::unordered_set<const Elem *> interior_parents;
77 :
78 : // We also preserve neighbors and their neighboring children for
79 : // active local elements - in most cases this is redundant with the
80 : // node check, but for non-conforming Tet4 meshes and
81 : // non-level-one-conforming 2D+3D meshes it is possible for an
82 : // element and its coarse neighbor to not share any vertices.
83 : //
84 : // We also preserve interior parents for active pid elements
85 :
86 :
87 : // This code is just for geometric coupling, so we use a null
88 : // CouplingMatrix pointer. We'll declare that here so as to avoid
89 : // confusing the insert() calls later.
90 1183783 : CouplingMatrix * nullcm = nullptr;
91 :
92 21920175 : for (const auto & elem : as_range(range_begin, range_end))
93 : {
94 15102 : libmesh_assert(_mesh->query_elem_ptr(elem->id()) == elem);
95 :
96 9791919 : if (elem->processor_id() != p)
97 5856 : coupled_elements.emplace(elem, nullcm);
98 :
99 30204 : std::set<const Elem *> elem_point_neighbors;
100 9791919 : elem->find_point_neighbors(elem_point_neighbors);
101 :
102 292094227 : for (const auto & neigh : elem_point_neighbors)
103 282302308 : if (neigh->processor_id() != p)
104 93652255 : coupled_elements.emplace(neigh, nullcm);
105 :
106 : // An interior_parent isn't on the same manifold so won't be
107 : // found as a point neighbor, and it may not share nodes so we
108 : // can't use a connected_nodes test.
109 : //
110 : // Trying to preserve interior_parent() only works if it's on
111 : // the same Mesh, which is *not* guaranteed! So we'll
112 : // double-check.
113 9791919 : const Elem * ip = elem->interior_parent();
114 9791967 : if (ip && ip->processor_id() != p &&
115 72 : _mesh->query_elem_ptr(ip->id()) == ip)
116 0 : coupled_elements.emplace(ip, nullcm);
117 :
118 : #ifdef LIBMESH_ENABLE_PERIODIC
119 9791919 : if (check_periodic_bcs)
120 : {
121 0 : for (const auto s : elem->side_index_range())
122 : {
123 0 : if (elem->neighbor_ptr(s))
124 0 : continue;
125 :
126 : const Elem * const equal_level_periodic_neigh = elem->topological_neighbor
127 0 : (s, *_mesh, *point_locator, _periodic_bcs);
128 :
129 0 : if (!equal_level_periodic_neigh || equal_level_periodic_neigh == remote_elem)
130 0 : continue;
131 :
132 : #ifdef LIBMESH_ENABLE_AMR
133 0 : equal_level_periodic_neigh->active_family_tree_by_topological_neighbor(
134 : active_periodic_neighbors,
135 : elem,
136 0 : *_mesh,
137 0 : *point_locator,
138 : _periodic_bcs,
139 : /*reset=*/true);
140 : #else
141 : active_periodic_neighbors = { equal_level_periodic_neigh };
142 : #endif
143 :
144 0 : for (const Elem * const active_periodic_neigh : active_periodic_neighbors)
145 : {
146 0 : std::set <const Elem *> active_periodic_point_neighbors;
147 :
148 : // This fills point neighbors *including*
149 : // active_periodic_neigh. The documentation for this method
150 : // states that this will return *active* point neighbors
151 0 : active_periodic_neigh->find_point_neighbors(active_periodic_point_neighbors);
152 :
153 0 : for (const Elem * const appn : active_periodic_point_neighbors)
154 : {
155 : // Don't need to ghost RemoteElem or an element we already own or an
156 : // element we've already examined
157 0 : if (appn == remote_elem || appn->processor_id() == p ||
158 0 : periodic_elems_examined.count(appn))
159 0 : continue;
160 :
161 : // We only need to keep point neighbors that are along the periodic boundaries
162 0 : bool on_periodic_boundary = false;
163 0 : for (const auto appn_s : appn->side_index_range())
164 : {
165 0 : binfo.boundary_ids(appn, appn_s, appn_bcids);
166 0 : for (const auto appn_bcid : appn_bcids)
167 0 : if (_periodic_bcs->find(appn_bcid) != _periodic_bcs->end())
168 : {
169 0 : on_periodic_boundary = true;
170 0 : goto jump;
171 : }
172 : }
173 0 : jump:
174 0 : if (on_periodic_boundary)
175 0 : coupled_elements.emplace(appn, nullcm);
176 :
177 0 : periodic_elems_examined.insert(appn);
178 : }
179 : }
180 : }
181 : }
182 :
183 9791919 : if (check_disjoint_bcs)
184 : {
185 : // Also ghost their disjoint neighbors
186 1440 : for (auto s : elem->side_index_range())
187 : {
188 4480 : for (const auto & [id, boundary_ptr] : *db)
189 : {
190 3328 : if (!_mesh->get_boundary_info().has_boundary_id(elem, s, id))
191 3024 : continue;
192 :
193 304 : unsigned int neigh_side = invalid_uint;
194 : const Elem * neigh =
195 304 : db->neighbor(id, *point_locator, elem, s, &neigh_side);
196 :
197 304 : if (!neigh || neigh == remote_elem)
198 0 : continue;
199 :
200 304 : if (neigh->processor_id() != p)
201 260 : coupled_elements.emplace(neigh, nullcm);
202 : }
203 : }
204 : }
205 :
206 : #endif // LIBMESH_ENABLE_PERIODIC
207 1181733 : }
208 1183783 : }
209 :
210 1496736 : void GhostPointNeighbors::mesh_reinit()
211 : {
212 : // Unless we have periodic boundary conditions, we don't need
213 : // anything precomputed.
214 : #ifdef LIBMESH_ENABLE_PERIODIC
215 : const bool check_periodic_bcs =
216 1496736 : (_periodic_bcs && !_periodic_bcs->empty());
217 :
218 1496736 : auto * db = _mesh->get_disjoint_neighbor_boundary_pairs();
219 1496736 : const bool check_disjoint_bcs = (db && !db->empty());
220 :
221 1496736 : if (!check_periodic_bcs && !check_disjoint_bcs)
222 27040 : return;
223 : #endif
224 :
225 : // If we do have periodic boundary conditions, we'll need a master
226 : // point locator, so we'd better have a mesh to build it on.
227 50 : libmesh_assert(_mesh);
228 :
229 : // Make sure an up-to-date master point locator has been
230 : // constructed; we'll need to grab sub-locators soon.
231 3409 : _mesh->sub_point_locator();
232 : }
233 :
234 : } // namespace libMesh
|