Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/underworld3/discretisation/discretisation_mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -1933,8 +1933,9 @@ def _surviving_labels(self, subdm, candidates):
Returns
-------
dict
The subset of ``candidates`` present on ``subdm`` with a
non-empty stratum, preserving candidate order.
Candidates with a non-empty stratum anywhere on the DM communicator,
preserving candidate order. Empty ranks retain the same names and
empty labels, so solver boundary registration is rank independent.
"""
present = set()
for i in range(subdm.getNumLabels()):
Expand All @@ -1961,6 +1962,14 @@ def _surviving_labels(self, subdm, candidates):
lsis = lab.getStratumIS(value)
if lsis is not None and lsis.getSize() > 0:
present.add(name)
# A boundary may be absent from this rank while present on its peers.
# Its enum and label must nevertheless exist everywhere: natural BC
# registration and solver setup use the same named boundaries on all ranks.
present = set().union(*subdm.comm.tompi4py().allgather(present))
local_names = {subdm.getLabelName(i) for i in range(subdm.getNumLabels())}
for name in candidates:
if name in present and name not in local_names:
subdm.createLabel(name)
return {name: v for name, v in candidates.items() if name in present}

def extract_region(self, label_name, label_value=None):
Expand Down
31 changes: 31 additions & 0 deletions tests/parallel/test_1085_submesh_boundary_names.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Submesh boundary names must survive on ranks owning no boundary points."""

from petsc4py import PETSc
import underworld3 as uw


def test_surviving_labels_use_global_presence_and_create_empty_local_labels():
dm = PETSc.DMPlex().createBoxMesh([2, 2], simplex=False, comm=uw.mpi.comm)
if uw.mpi.rank == 0:
dm.createLabel('OnlyOnZero')
dm.setLabelValue('OnlyOnZero', dm.getChart()[0], 42)
surviving = uw.discretisation.Mesh._surviving_labels(
None, dm, {'OnlyOnZero': 42, 'AbsentEverywhere': 99}
)
assert surviving == {'OnlyOnZero': 42}
assert dm.getLabel('OnlyOnZero') is not None
assert 'AbsentEverywhere' not in [dm.getLabelName(i) for i in range(dm.getNumLabels())]
if uw.mpi.rank > 0:
values = dm.getLabel('OnlyOnZero').getValueIS()
assert values is None or len(values.getIndices()) == 0
dm.destroy()


def test_extracted_region_boundary_enums_are_identical_on_every_rank():
mesh = uw.meshing.BoxInternalBoundary(
elementRes=(12,12), zelementRes=(10,2), zintCoord=.85,
minCoords=(0.,0.), maxCoords=(1.,1.), simplex=True, qdegree=2)
child = mesh.extract_region('Outer')
names = [(b.name,b.value) for b in child.boundaries]
assert all(other == names for other in uw.mpi.comm.allgather(names))
assert 'Top' in dict(names)
Loading