Forward the location policy on the empty-rank path (#611) - #656
Merged
Conversation
`global_evaluate` deadlocked whenever a query set left some rank with no
points. At np=4 the migration test hung indefinitely -- 900 s with no progress
on a 300-point query -- while passing at np=2.
Native stacks during the hang name both halves:
3 ranks DMSwarmMigrate -> DMSwarmDataExCreate -> MPI_Comm_dup
1 rank DMLocatePoints -> DMGetBoundingBox -> MPI_Allreduce
A mismatched collective, not slowness and not a location failure: every rank
was inside MPI, none in locator code.
The cell-location policy (`mesh._hint_is_authoritative`) decides whether the
barycentric hint may bypass PETSc's `DMLocatePoints`, which is COLLECTIVE on
the mesh DM communicator. The policy is a mesh capability, so all ranks agree
on it -- instrumenting confirmed `auth=True` on all four.
It was then discarded in transit. `create_structure` had no hint array to pass
when a rank held zero points, and passed `hintAuthoritative = 0` HARDCODED
beside the NULL:
ierr = DMInterpolationSetUp_UW(self._ipInfo, dm, 0, 1, NULL, 0)
so that rank alone took the DMLocatePoints branch. Forwarding the caller's
policy is the fix; `petsc_tools.c` additionally has to accept a NULL hint when
there are no points to hint at, since the bypass is trivially correct with
nothing to locate.
Why it hid at np=2: the test biases every point into x > 0.5, and at np=4 one
rank owns solely x < 0.5 and so receives nothing, where at np=2 the coarser
partition leaves both ranks straddling the split. Measured ownership at np=4:
rank 1 gets 0 of the 300 points, and rank 1 is the rank the watchdog roll call
singled out.
Two wrong turns are worth recording so they are not retried. A pre-touch of
`mesh.dm.getBoundingBox()` does nothing -- PETSc does not cache it, so the
later call inside the locator reduces again. And forcing the DMInterpolation
cache decision to be unanimous does nothing here either: instrumenting showed
all four ranks MISS the cache, so it was never the divergence. Both were
reverted rather than shipped.
The docstring on `_location_capability` states the assumption that made this
invisible: "deliberately NOT reduced across ranks: the evaluator runs on
COMM_SELF [...] petsc_interpolate is reached only by ranks holding points".
Both halves are false -- `DMLocatePoints(dm, ...)` uses the mesh DM's
communicator, and a trace shows all ranks entering `petsc_interpolate`,
including one with zero points. The policy does not need reducing (it already
agrees); it needs to survive the call.
Regression covers a query biased so some rank is empty, plus an unbiased
control that passed before the fix -- so a failure there means the ordinary
path broke rather than the empty-rank path being repaired. Green at np=1, 2, 4,
as is the whole of test_0760 which previously hung at np=4.
Underworld development team with AI support from Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #611.
global_evaluatedeadlocked whenever a query set left some rank with no points — 900 s with no progress on a 300-point query at np=4, while passing at np=2.What it actually was
Native stacks during the hang name both halves:
A mismatched collective — every rank inside MPI, none in locator code. So neither slowness (ruled out: 300 points, 900 s) nor a location failure.
The cell-location policy (
mesh._hint_is_authoritative) decides whether the barycentric hint may bypass PETSc'sDMLocatePoints, which is collective on the mesh DM communicator. The policy is a mesh capability, and instrumenting confirmed it agrees on every rank (auth=Trueon all four).It was discarded in transit.
create_structurehad no hint array to pass when a rank held zero points, and passedhintAuthoritative = 0hardcoded beside the NULL:so that rank alone entered the collective. Forwarding the caller's policy is the fix;
petsc_tools.cadditionally accepts a NULL hint whenN == 0, since bypassing is trivially correct with nothing to locate.Why np=2 hid it
The test biases every point into
x > 0.5. At np=4 one rank owns solelyx < 0.5and receives 0 of 300 points — and that is precisely the rank the watchdog roll call singled out. At np=2 the coarser partition leaves both ranks straddling the split, so neither is empty.Two wrong turns, reverted rather than shipped
Recorded because both look plausible:
mesh.dm.getBoundingBox()— useless. PETSc does not cache it, so the later call inside the locator reduces again.A docstring worth correcting separately
_location_capabilitysays it is "deliberately NOT reduced across ranks: the evaluator runs on COMM_SELF [...] petsc_interpolate is reached only by ranks holding points". Both halves are false —DMLocatePoints(dm, ...)uses the mesh DM's communicator, and a trace shows every rank enteringpetsc_interpolate, including one with zero points. The conclusion (don't reduce the policy) is right, but for the wrong reason — and the wrong reason is what made the hardcoded0look harmless. Not changed here to keep the diff to the defect.Tests
New
test_1076_global_evaluate_empty_rank.py: a query biased so some rank is empty, plus an unbiased control that passed before the fix — a failure there means the ordinary path broke rather than the empty-rank path being repaired.test_0760(previously hung at np=4): green at np=1, 2, 4test_0750,test_0755,test_1064at np=2: greenlevel_1 and tier_aserial: 1074 passed, 0 failedUnderworld development team with AI support from Claude Code