Skip to content

Commit 7941173

Browse files
authored
Merge pull request #2725 from lindsayad/ghost-periodic-point-neighbors
Ghost periodic point neighbors in GhostPointNeighbors
2 parents 1040ed2 + 14490ef commit 7941173

File tree

6 files changed

+182
-34
lines changed

6 files changed

+182
-34
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: 43 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,27 @@ 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+
// We do not simply want to copy over the other's periodic bcs because
64+
// they may very well correspond to periodic bcs from a \p DofMap entirely
65+
// unrelated to any \p DofMaps that depend on this objects ghosting
66+
_periodic_bcs(nullptr)
67+
#endif
68+
{}
5169

5270
/**
5371
* A clone() is needed because GhostingFunctor can not be shared between
@@ -56,6 +74,24 @@ class GhostPointNeighbors : public GhostingFunctor
5674
virtual std::unique_ptr<GhostingFunctor> clone () const override
5775
{ return libmesh_make_unique<GhostPointNeighbors>(*this); }
5876

77+
#ifdef LIBMESH_ENABLE_PERIODIC
78+
// Set PeriodicBoundaries to couple
79+
void set_periodic_boundaries(const PeriodicBoundaries * periodic_bcs) override
80+
{ _periodic_bcs = periodic_bcs; }
81+
#endif
82+
83+
/**
84+
* If we have periodic boundaries, then we'll need the mesh to have
85+
* an updated point locator whenever we're about to query them.
86+
*/
87+
virtual void mesh_reinit () override;
88+
89+
virtual void redistribute () override
90+
{ this->mesh_reinit(); }
91+
92+
virtual void delete_remote_elements() override
93+
{ this->mesh_reinit(); }
94+
5995
/**
6096
* For the specified range of active elements, find their point
6197
* neighbors and interior_parent elements, ignoring those on
@@ -65,6 +101,11 @@ class GhostPointNeighbors : public GhostingFunctor
65101
const MeshBase::const_element_iterator & range_end,
66102
processor_id_type p,
67103
map_type & coupled_elements) override;
104+
105+
private:
106+
#ifdef LIBMESH_ENABLE_PERIODIC
107+
const PeriodicBoundaries * _periodic_bcs;
108+
#endif
68109
};
69110

70111
} // 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: 100 additions & 0 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,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

src/mesh/mesh_base.C

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -104,39 +104,39 @@ MeshBase::MeshBase (const MeshBase & other_mesh) :
104104
_default_ghosting(libmesh_make_unique<GhostPointNeighbors>(*this)),
105105
_point_locator_close_to_point_tol(other_mesh._point_locator_close_to_point_tol)
106106
{
107-
for (const auto & gf : other_mesh._ghosting_functors )
108-
{
109-
std::shared_ptr<GhostingFunctor> clone_gf = gf->clone();
110-
// Some subclasses of GhostingFunctor might not override the
111-
// clone function yet. If this is the case, GhostingFunctor will
112-
// return nullptr by default. The clone function should be overridden
113-
// in all derived classes. This following code ("else") is written
114-
// for API upgrade. That will allow users gradually to update their code.
115-
// Once the API upgrade is done, we will come back and delete "else."
116-
if (clone_gf)
117-
{
118-
clone_gf->set_mesh(this);
119-
add_ghosting_functor(clone_gf);
120-
}
121-
else
122-
{
123-
libmesh_deprecated();
124-
add_ghosting_functor(*gf);
125-
}
126-
}
127-
128-
// Make sure we don't accidentally delete the other mesh's default
129-
// ghosting functor; we'll use our own if that's needed.
130-
if (other_mesh._ghosting_functors.count(other_mesh._default_ghosting.get()))
107+
const GhostingFunctor * const other_default_ghosting = other_mesh._default_ghosting.get();
108+
109+
for (GhostingFunctor * const gf : other_mesh._ghosting_functors)
131110
{
132-
_ghosting_functors.erase(other_mesh._default_ghosting.get());
133-
_ghosting_functors.insert(_default_ghosting.get());
111+
// If the other mesh is using default ghosting, then we will use our own
112+
// default ghosting
113+
if (gf == other_default_ghosting)
114+
{
115+
_ghosting_functors.insert(_default_ghosting.get());
116+
continue;
117+
}
118+
119+
std::shared_ptr<GhostingFunctor> clone_gf = gf->clone();
120+
// Some subclasses of GhostingFunctor might not override the
121+
// clone function yet. If this is the case, GhostingFunctor will
122+
// return nullptr by default. The clone function should be overridden
123+
// in all derived classes. This following code ("else") is written
124+
// for API upgrade. That will allow users gradually to update their code.
125+
// Once the API upgrade is done, we will come back and delete "else."
126+
if (clone_gf)
127+
{
128+
clone_gf->set_mesh(this);
129+
add_ghosting_functor(clone_gf);
130+
}
131+
else
132+
{
133+
libmesh_deprecated();
134+
add_ghosting_functor(*gf);
135+
}
134136
}
135137

136138
if (other_mesh._partitioner.get())
137-
{
138-
_partitioner = other_mesh._partitioner->clone();
139-
}
139+
_partitioner = other_mesh._partitioner->clone();
140140
}
141141

142142

0 commit comments

Comments
 (0)