2121
2222#include "libmesh/elem.h"
2323#include "libmesh/remote_elem.h"
24+ #ifdef LIBMESH_ENABLE_PERIODIC
25+ #include "libmesh/periodic_boundaries.h"
26+ #include "libmesh/boundary_info.h"
27+ #endif
2428
2529// C++ Includes
2630#include <unordered_set>
31+ #include <set>
32+ #include <vector>
2733
2834namespace libMesh
2935{
@@ -36,6 +42,20 @@ void GhostPointNeighbors::operator()
3642{
3743 libmesh_assert (_mesh );
3844
45+ #ifdef LIBMESH_ENABLE_PERIODIC
46+ bool check_periodic_bcs =
47+ (_periodic_bcs && !_periodic_bcs -> empty ());
48+
49+ std ::unique_ptr < PointLocatorBase > point_locator ;
50+ if (check_periodic_bcs )
51+ point_locator = _mesh -> sub_point_locator ();
52+
53+ std ::set < const Elem * > periodic_elems_examined ;
54+ const BoundaryInfo & binfo = _mesh -> get_boundary_info ();
55+ std ::vector < boundary_id_type > appn_bcids ;
56+ std ::vector < const Elem * > active_periodic_neighbors ;
57+ #endif
58+
3959 // Using a connected_nodes set rather than point_neighbors() would
4060 // give us correct results even in corner cases, such as where two
4161 // elements meet only at a corner. ;-)
@@ -90,7 +110,87 @@ void GhostPointNeighbors::operator()
90110 if (ip && ip -> processor_id () != p &&
91111 _mesh -> query_elem_ptr (ip -> id ()) == ip )
92112 coupled_elements .emplace (ip , nullcm );
113+
114+ #ifdef LIBMESH_ENABLE_PERIODIC
115+ if (check_periodic_bcs )
116+ {
117+ for (const auto s : elem -> side_index_range ())
118+ {
119+ if (elem -> neighbor_ptr (s ))
120+ continue ;
121+
122+ const Elem * const equal_level_periodic_neigh = elem -> topological_neighbor
123+ (s , * _mesh , * point_locator , _periodic_bcs );
124+
125+ if (!equal_level_periodic_neigh || equal_level_periodic_neigh == remote_elem )
126+ continue ;
127+
128+ equal_level_periodic_neigh -> active_family_tree_by_topological_neighbor (
129+ active_periodic_neighbors ,
130+ elem ,
131+ * _mesh ,
132+ * point_locator ,
133+ _periodic_bcs ,
134+ /*reset=*/ true);
135+
136+ for (const Elem * const active_periodic_neigh : active_periodic_neighbors )
137+ {
138+ std ::set < const Elem * > active_periodic_point_neighbors ;
139+
140+ // This fills point neighbors *including*
141+ // active_periodic_neigh. The documentation for this method
142+ // states that this will return *active* point neighbors
143+ active_periodic_neigh -> find_point_neighbors (active_periodic_point_neighbors );
144+
145+ for (const Elem * const appn : active_periodic_point_neighbors )
146+ {
147+ // Don't need to ghost RemoteElem or an element we already own or an
148+ // element we've already examined
149+ if (appn == remote_elem || appn -> processor_id () == p ||
150+ periodic_elems_examined .count (appn ))
151+ continue ;
152+
153+ // We only need to keep point neighbors that are along the periodic boundaries
154+ bool on_periodic_boundary = false;
155+ for (const auto appn_s : appn -> side_index_range ())
156+ {
157+ binfo .boundary_ids (appn , appn_s , appn_bcids );
158+ for (const auto appn_bcid : appn_bcids )
159+ if (_periodic_bcs -> find (appn_bcid ) != _periodic_bcs -> end ())
160+ {
161+ on_periodic_boundary = true;
162+ goto jump ;
163+ }
164+ }
165+ jump :
166+ if (on_periodic_boundary )
167+ coupled_elements .emplace (appn , nullcm );
168+
169+ periodic_elems_examined .insert (appn );
170+ }
171+ }
172+ }
173+ }
174+ #endif // LIBMESH_ENABLE_PERIODIC
93175 }
94176}
95177
178+ void GhostPointNeighbors ::mesh_reinit ()
179+ {
180+ // Unless we have periodic boundary conditions, we don't need
181+ // anything precomputed.
182+ #ifdef LIBMESH_ENABLE_PERIODIC
183+ if (!_periodic_bcs || _periodic_bcs -> empty ())
184+ return ;
185+ #endif
186+
187+ // If we do have periodic boundary conditions, we'll need a master
188+ // point locator, so we'd better have a mesh to build it on.
189+ libmesh_assert (_mesh );
190+
191+ // Make sure an up-to-date master point locator has been
192+ // constructed; we'll need to grab sub-locators soon.
193+ _mesh -> sub_point_locator ();
194+ }
195+
96196} // namespace libMesh
0 commit comments