Skip to content

Commit a8a8602

Browse files
committed
Map-based disconnected neighbor ghosting base on ptr + fixing internal interface support
This change introduces correct handling of intentionally disconnected interfaces (e.g., CZM or jump conditions) on distributed meshes: - Replace ID-based lookup in `MapBasedDisconnectedGhosting` with direct `Elem*` neighbor mapping to avoid invalid lookups post-renumbering. - Register the disconnected ghosting functor in `find_neighbors()` so ghosting stays consistent with the neighbor graph established by `prepare_for_use()`. - Extend `BoundaryInfo::side_with_boundary_id()` to optionally allow internal/logical boundaries when explicitly requested by the caller. - Fix face FE assembly under `--disable-deprecated` by explicitly requesting shape and map computations before reinit() calls. - Remove older per-test ghosting setup now handled by the mesh.
1 parent b33e052 commit a8a8602

File tree

5 files changed

+33
-25
lines changed

5 files changed

+33
-25
lines changed

include/ghosting/map_based_disconnected_ghosting.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ class MapBasedDisconnectedGhosting : public GhostingFunctor
2323
{
2424
public:
2525

26-
// Map from (local element ID, local side number) to neighbor element ID.
26+
// Map from (local element ptr) to neighbor element ptr.
2727
using DisconnectedMap =
28-
std::map<dof_id_type, dof_id_type>;
28+
std::unordered_map<const Elem *, const Elem *>;
2929

3030
/**
3131
* @brief Constructor.

src/ghosting/map_based_disconnected_ghosting.C

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,12 @@ MapBasedDisconnectedGhosting::operator() (
4040
coupled_elements.emplace(elem, nullcm);
4141

4242
// Look up this element's neighbor in the map
43-
auto it = _map.find(elem->id());
43+
auto it = _map.find(elem);
4444
if (it == _map.end())
4545
continue;
4646

4747
// Get the neighbor's ID
48-
const dof_id_type neighbor_id = it->second;
49-
50-
const Elem * neighbor_ptr = _mesh->query_elem_ptr(neighbor_id);
48+
const Elem * neighbor_ptr = it->second;
5149

5250
// If the neighbor pointer is valid (meaning it's local or ghosted)
5351
// AND it's not on processor 'p', add it to the couplings.

src/mesh/boundary_info.C

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2323,25 +2323,27 @@ unsigned int BoundaryInfo::side_with_boundary_id(const Elem * const elem,
23232323
{
23242324
// If we're on this external boundary then we share this
23252325
// external boundary id
2326-
if (elem->neighbor_ptr(side) == nullptr || include_internal_boundary)
2326+
if (elem->neighbor_ptr(side) == nullptr)
23272327
return side;
23282328

23292329
// If we're on an internal boundary then we need to be sure
23302330
// it's the same internal boundary as our top_parent
2331-
const Elem * p = elem;
2332-
2331+
bool aligned_with_parent = false;
23332332
#ifdef LIBMESH_ENABLE_AMR
2334-
2333+
const Elem * p = elem;
23352334
while (p != nullptr)
23362335
{
23372336
const Elem * parent = p->parent();
23382337
if (parent && !parent->is_child_on_side(parent->which_child_am_i(p), side))
23392338
break;
23402339
p = parent;
23412340
}
2341+
aligned_with_parent = (p == nullptr);
23422342
#endif
2343-
// We're on that side of our top_parent; return it
2344-
if (!p)
2343+
// Two valid cases:
2344+
// 1. The internal face is geometrically aligned with the parent's boundary side (original behavior)
2345+
// 2. The caller explicitly allows logical/internal boundaries (e.g. CZM interfaces)
2346+
if (aligned_with_parent || include_internal_boundary)
23452347
return side;
23462348
}
23472349
// Otherwise we need to check if the child's ancestors have something on

src/mesh/unstructured_mesh.C

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
// for disconnected neighbors
5151
#include "libmesh/periodic_boundaries.h"
5252
#include "libmesh/periodic_boundary.h"
53+
#include <libmesh/map_based_disconnected_ghosting.h>
5354

5455
namespace {
5556

@@ -1003,6 +1004,7 @@ void UnstructuredMesh::find_neighbors (const bool reset_remote_elements,
10031004

10041005
if (db)
10051006
{
1007+
MapBasedDisconnectedGhosting::DisconnectedMap disconnected_map;
10061008
// Obtain a point locator
10071009
std::unique_ptr<PointLocatorBase> point_locator = this->sub_point_locator();
10081010

@@ -1026,12 +1028,19 @@ void UnstructuredMesh::find_neighbors (const bool reset_remote_elements,
10261028

10271029
if (neigh && neigh != remote_elem && neigh != element)
10281030
{
1029-
element->set_neighbor(ms, this->elem_ptr(neigh->id()));
1030-
this->elem_ptr(neigh->id())->set_neighbor(neigh_side, element);
1031+
auto neigh_changeable = this->elem_ptr(neigh->id());
1032+
element->set_neighbor(ms, neigh_changeable);
1033+
neigh_changeable->set_neighbor(neigh_side, element);
1034+
disconnected_map.emplace(element, neigh_changeable);
1035+
disconnected_map.emplace(neigh_changeable, element);
10311036
}
10321037
}
10331038
}
10341039
}
1040+
// Now add the ghosting functor to keep these neighbors in sync
1041+
auto map_ghosting =
1042+
std::make_shared<MapBasedDisconnectedGhosting>(*this, disconnected_map);
1043+
this->add_ghosting_functor(map_ghosting);
10351044
}
10361045
#endif // LIBMESH_ENABLE_PERIODIC
10371046

tests/systems/disconnected_neighbor_test.C

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ void assemble_temperature_jump(EquationSystems &es,
9696
Fe.zero();
9797

9898
// --- Volume contribution ---
99+
fe->get_dphi(); // sets calculate_dphi = true
100+
fe->get_JxW(); // sets calculate_map = true
99101
fe->reinit(elem);
100102
const auto &JxW_vol = fe->get_JxW();
101103
const auto &dphi_vol = fe->get_dphi();
@@ -109,13 +111,17 @@ void assemble_temperature_jump(EquationSystems &es,
109111
unsigned int side = boundary.side_with_boundary_id(elem, interface_left_id, true /*include_internal_boundary*/);
110112
if (side != libMesh::invalid_uint)
111113
{
114+
fe_face_L->get_phi(); // sets calculate_phi = true
115+
fe_face_L->get_JxW(); // sets calculate_map = true
112116
fe_face_L->reinit(elem, side);
113117
const auto &phi_L = fe_face_L->get_phi();
114118
const auto &JxW_face = fe_face_L->get_JxW();
115119

116120
const Elem *neighbor = elem->neighbor_ptr(side);
117121
libmesh_assert(neighbor);
118122
unsigned int n_side = neighbor->which_neighbor_am_i(elem);
123+
fe_face_R->get_phi();
124+
fe_face_R->get_JxW();
119125
fe_face_R->reinit(neighbor, n_side);
120126
const auto &phi_R = fe_face_R->get_phi();
121127

@@ -145,13 +151,17 @@ void assemble_temperature_jump(EquationSystems &es,
145151
side = boundary.side_with_boundary_id(elem, interface_right_id, true /*include_internal_boundary*/);
146152
if (side != libMesh::invalid_uint)
147153
{
154+
fe_face_R->get_phi(); // sets calculate_phi = true
155+
fe_face_R->get_JxW(); // sets calculate_map = true
148156
fe_face_R->reinit(elem, side);
149157
const auto &phi_R = fe_face_R->get_phi();
150158
const auto &JxW_face = fe_face_R->get_JxW();
151159

152160
const Elem *neighbor = elem->neighbor_ptr(side);
153161
libmesh_assert(neighbor);
154162
unsigned int n_side = neighbor->which_neighbor_am_i(elem);
163+
fe_face_L->get_phi();
164+
fe_face_L->get_JxW();
155165
fe_face_L->reinit(neighbor, n_side);
156166
const auto &phi_L = fe_face_L->get_phi();
157167

@@ -267,17 +277,6 @@ private:
267277
// And, in `prepare_for_use()`, libMesh will set up the disconnected neighbor relationships.
268278
mesh.add_disconnected_boundaries(interface_left_id, interface_right_id, RealVectorValue(0.0, 0.0, 0.0));
269279

270-
271-
// new, map-based ghosting functor
272-
MapBasedDisconnectedGhosting::DisconnectedMap disconnected_map;
273-
// Elem 0 connects to Elem 1
274-
disconnected_map[0] = 1;
275-
// Elem 1 connects to Elem 0
276-
disconnected_map[1] = 0;
277-
auto map_ghosting =
278-
std::make_shared<MapBasedDisconnectedGhosting>(mesh, disconnected_map);
279-
mesh.add_ghosting_functor(map_ghosting);
280-
281280
// libMesh shouldn't renumber, or our based-on-initial-id
282281
// assertions later may fail.
283282
mesh.allow_renumbering(false);

0 commit comments

Comments
 (0)