Skip to content

Commit e354e42

Browse files
committed
Ghost periodic point neighbors in GhostPointNeighbors
This fixes my distributed periodic boundary issue. Currently our periodic constraint algorithm relies on identifying a primary element in charge of constraining (vertex) dofs. That designation is determined by looking at point neighbors and comparing things like ids. If not all the point neighbors are available, then a process may make an invalid determination that it owns a primary elem when in fact the primary elem is off-process. In order to to validly determine primary elems, we must have all the periodic point neighbors available
1 parent 8b72837 commit e354e42

File tree

5 files changed

+161
-27
lines changed

5 files changed

+161
-27
lines changed

include/base/default_coupling.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class DefaultCoupling : public GhostingFunctor
8686

8787
#ifdef LIBMESH_ENABLE_PERIODIC
8888
// Set PeriodicBoundaries to couple
89-
void set_periodic_boundaries(const PeriodicBoundaries * periodic_bcs)
89+
void set_periodic_boundaries(const PeriodicBoundaries * periodic_bcs) override
9090
{ _periodic_bcs = periodic_bcs; }
9191
#endif
9292

include/base/ghost_point_neighbors.h

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626

2727
namespace libMesh
2828
{
29+
#ifdef LIBMESH_ENABLE_PERIODIC
30+
class PeriodicBoundaries;
31+
#endif
2932

3033
/**
3134
* This class implements the original default geometry ghosting
@@ -42,12 +45,24 @@ class GhostPointNeighbors : public GhostingFunctor
4245
/**
4346
* Constructor.
4447
*/
45-
GhostPointNeighbors(const MeshBase & mesh) : GhostingFunctor(mesh) {}
48+
GhostPointNeighbors(const MeshBase & mesh) :
49+
GhostingFunctor(mesh)
50+
#ifdef LIBMESH_ENABLE_PERIODIC
51+
,
52+
_periodic_bcs(nullptr)
53+
#endif
54+
{}
4655

4756
/**
4857
* Constructor.
4958
*/
50-
GhostPointNeighbors(const GhostPointNeighbors & other) : GhostingFunctor(other){}
59+
GhostPointNeighbors(const GhostPointNeighbors & other) :
60+
GhostingFunctor(other)
61+
#ifdef LIBMESH_ENABLE_PERIODIC
62+
,
63+
_periodic_bcs(other._periodic_bcs)
64+
#endif
65+
{}
5166

5267
/**
5368
* A clone() is needed because GhostingFunctor can not be shared between
@@ -56,6 +71,24 @@ class GhostPointNeighbors : public GhostingFunctor
5671
virtual std::unique_ptr<GhostingFunctor> clone () const override
5772
{ return libmesh_make_unique<GhostPointNeighbors>(*this); }
5873

74+
#ifdef LIBMESH_ENABLE_PERIODIC
75+
// Set PeriodicBoundaries to couple
76+
void set_periodic_boundaries(const PeriodicBoundaries * periodic_bcs) override
77+
{ _periodic_bcs = periodic_bcs; }
78+
#endif
79+
80+
/**
81+
* If we have periodic boundaries, then we'll need the mesh to have
82+
* an updated point locator whenever we're about to query them.
83+
*/
84+
virtual void mesh_reinit () override;
85+
86+
virtual void redistribute () override
87+
{ this->mesh_reinit(); }
88+
89+
virtual void delete_remote_elements() override
90+
{ this->mesh_reinit(); }
91+
5992
/**
6093
* For the specified range of active elements, find their point
6194
* neighbors and interior_parent elements, ignoring those on
@@ -65,6 +98,11 @@ class GhostPointNeighbors : public GhostingFunctor
6598
const MeshBase::const_element_iterator & range_end,
6699
processor_id_type p,
67100
map_type & coupled_elements) override;
101+
102+
private:
103+
#ifdef LIBMESH_ENABLE_PERIODIC
104+
const PeriodicBoundaries * _periodic_bcs;
105+
#endif
68106
};
69107

70108
} // namespace libMesh

include/base/ghosting_functor.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ namespace libMesh
3636
// Forward Declarations
3737
class CouplingMatrix;
3838
class Elem;
39-
39+
#ifdef LIBMESH_ENABLE_PERIODIC
40+
class PeriodicBoundaries;
41+
#endif
4042

4143
/**
4244
* This abstract base class defines the interface by which library
@@ -194,6 +196,11 @@ class GhostingFunctor : public ReferenceCountedObject<GhostingFunctor>
194196
*/
195197
virtual void set_mesh(const MeshBase * mesh) { _mesh = mesh; }
196198

199+
#ifdef LIBMESH_ENABLE_PERIODIC
200+
// Set PeriodicBoundaries to couple
201+
virtual void set_periodic_boundaries(const PeriodicBoundaries *) {}
202+
#endif
203+
197204
/**
198205
* Return the mesh associated with ghosting functor
199206
*/

include/base/point_neighbor_coupling.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class PointNeighborCoupling : public GhostingFunctor
8888
// Set PeriodicBoundaries to couple.
8989
//
9090
// FIXME: This capability is not currently implemented.
91-
void set_periodic_boundaries(const PeriodicBoundaries * periodic_bcs)
91+
void set_periodic_boundaries(const PeriodicBoundaries * periodic_bcs) override
9292
{ _periodic_bcs = periodic_bcs; }
9393
#endif
9494

src/base/ghost_point_neighbors.C

Lines changed: 111 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@
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

2834
namespace libMesh
2935
{
@@ -36,6 +42,22 @@ 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+
{
52+
libmesh_assert(_mesh);
53+
point_locator = _mesh->sub_point_locator();
54+
}
55+
56+
std::set<const Elem *> periodic_elems_examined;
57+
const BoundaryInfo & binfo = _mesh->get_boundary_info();
58+
std::vector<boundary_id_type> ppn_bcids;
59+
#endif
60+
3961
// Using a connected_nodes set rather than point_neighbors() would
4062
// give us correct results even in corner cases, such as where two
4163
// elements meet only at a corner. ;-)
@@ -67,30 +89,97 @@ void GhostPointNeighbors::operator()
6789
CouplingMatrix * nullcm = nullptr;
6890

6991
for (const auto & elem : as_range(range_begin, range_end))
92+
{
93+
libmesh_assert(_mesh->query_elem_ptr(elem->id()) == elem);
94+
95+
if (elem->processor_id() != p)
96+
coupled_elements.emplace(elem, nullcm);
97+
98+
std::set<const Elem *> elem_point_neighbors;
99+
elem->find_point_neighbors(elem_point_neighbors);
100+
101+
for (const auto & neigh : elem_point_neighbors)
102+
coupled_elements.emplace(neigh, nullcm);
103+
104+
// An interior_parent isn't on the same manifold so won't be
105+
// found as a point neighbor, and it may not share nodes so we
106+
// can't use a connected_nodes test.
107+
//
108+
// Trying to preserve interior_parent() only works if it's on
109+
// the same Mesh, which is *not* guaranteed! So we'll
110+
// double-check.
111+
const Elem * ip = elem->interior_parent();
112+
if (ip && ip->processor_id() != p &&
113+
_mesh->query_elem_ptr(ip->id()) == ip)
114+
coupled_elements.emplace(ip, nullcm);
115+
116+
#ifdef LIBMESH_ENABLE_PERIODIC
117+
if (check_periodic_bcs)
70118
{
71-
libmesh_assert(_mesh->query_elem_ptr(elem->id()) == elem);
72-
73-
if (elem->processor_id() != p)
74-
coupled_elements.emplace(elem, nullcm);
75-
76-
std::set<const Elem *> elem_point_neighbors;
77-
elem->find_point_neighbors(elem_point_neighbors);
78-
79-
for (const auto & neigh : elem_point_neighbors)
80-
coupled_elements.emplace(neigh, nullcm);
81-
82-
// An interior_parent isn't on the same manifold so won't be
83-
// found as a point neighbor, and it may not share nodes so we
84-
// can't use a connected_nodes test.
85-
//
86-
// Trying to preserve interior_parent() only works if it's on
87-
// the same Mesh, which is *not* guaranteed! So we'll
88-
// double-check.
89-
const Elem * ip = elem->interior_parent();
90-
if (ip && ip->processor_id() != p &&
91-
_mesh->query_elem_ptr(ip->id()) == ip)
92-
coupled_elements.emplace(ip, nullcm);
119+
for (const auto s : elem->side_index_range())
120+
{
121+
if (elem->neighbor_ptr(s))
122+
continue;
123+
124+
const Elem * const periodic_neigh = elem->topological_neighbor
125+
(s, *_mesh, *point_locator, _periodic_bcs);
126+
127+
if (periodic_neigh && periodic_neigh != remote_elem)
128+
{
129+
std::set <const Elem *> periodic_point_neighbors;
130+
131+
// This fills point neighbors *including* periodic_neigh
132+
periodic_neigh->find_point_neighbors(periodic_point_neighbors);
133+
134+
for (const Elem * const ppn : periodic_point_neighbors)
135+
{
136+
// Don't need to ghost RemoteElem or an element we already own or an
137+
// element we've already examined
138+
if (ppn == remote_elem || ppn->processor_id() == _mesh->processor_id() ||
139+
periodic_elems_examined.count(ppn))
140+
continue;
141+
142+
// We only need to keep point neighbors that are along the periodic boundaries
143+
bool on_periodic_boundary = false;
144+
for (const auto ppn_s : ppn->side_index_range())
145+
{
146+
binfo.boundary_ids(ppn, ppn_s, ppn_bcids);
147+
for (const auto & pb_pair : *_periodic_bcs)
148+
if (std::find(ppn_bcids.begin(), ppn_bcids.end(), pb_pair.first) != ppn_bcids.end())
149+
{
150+
on_periodic_boundary = true;
151+
goto jump;
152+
}
153+
}
154+
jump:
155+
if (on_periodic_boundary)
156+
coupled_elements.emplace(ppn, nullcm);
157+
158+
periodic_elems_examined.insert(ppn);
159+
}
160+
}
161+
}
93162
}
163+
#endif // LIBMESH_ENABLE_PERIODIC
164+
}
165+
}
166+
167+
void GhostPointNeighbors::mesh_reinit()
168+
{
169+
// Unless we have periodic boundary conditions, we don't need
170+
// anything precomputed.
171+
#ifdef LIBMESH_ENABLE_PERIODIC
172+
if (!_periodic_bcs || _periodic_bcs->empty())
173+
return;
174+
#endif
175+
176+
// If we do have periodic boundary conditions, we'll need a master
177+
// point locator, so we'd better have a mesh to build it on.
178+
libmesh_assert(_mesh);
179+
180+
// Make sure an up-to-date master point locator has been
181+
// constructed; we'll need to grab sub-locators soon.
182+
_mesh->sub_point_locator();
94183
}
95184

96185
} // namespace libMesh

0 commit comments

Comments
 (0)