Repository navigation
mpi: Fix halo=0 SubDomain mask at rank edges #3102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -464,6 +464,16 @@ class SpaceDimension(BasicDimension): | |
|
|
||
| is_Space = True | ||
|
|
||
| @cached_property | ||
| def rank_offsets(self): | ||
| """ | ||
| The number of points of `root` owned by the MPI ranks before (`side=LEFT`) | ||
| or after (`side=RIGHT`) this one, that is the offset of this rank from that | ||
| edge of the Grid. Zero without domain decomposition. | ||
| """ | ||
| return tuple(RankOffset(name=f"{self.name}_{s}_ofs", side=s, root=self) | ||
| for s in (LEFT, RIGHT)) | ||
|
|
||
|
|
||
| class TimeDimension(BasicDimension): | ||
|
|
||
|
|
@@ -566,6 +576,7 @@ class Thickness(DataSymbol): | |
| __rkwargs__ = DataSymbol.__rkwargs__ + ('root', 'side', 'local', 'value', 'separated') | ||
|
|
||
| def __new__(cls, *args, root=None, side=None, local=False, separated=False, **kwargs): | ||
| kwargs.setdefault('nonnegative', True) | ||
| newobj = super().__new__(cls, *args, **kwargs) | ||
| newobj._root = root | ||
| newobj._side = side | ||
|
|
@@ -625,6 +636,31 @@ def _arg_check(self, args, *_args, **kwargs): | |
| mpi_raise(error, InvalidArgument, comm=comm) | ||
|
|
||
|
|
||
| class RankOffset(Thickness): | ||
| """ | ||
| The number of points of `root` owned by the MPI ranks before (`side=LEFT`) | ||
| or after (`side=RIGHT`) this one, that is the offset of this rank from that | ||
| edge of the Grid. Zero without domain decomposition. | ||
| """ | ||
|
|
||
| def _arg_values(self, grid=None, **kwargs): | ||
| root = self.root | ||
| if grid is not None: | ||
| root = next((d for d in grid.dimensions if d.name == root.name), root) | ||
|
|
||
| if grid is None or not grid.is_distributed(root): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is essentially just guarding the subsequent if block, ensuring that |
||
| return {self.name: 0} | ||
|
|
||
| dec = grid.distributor.decomposition[root] | ||
| if dec.loc_empty: | ||
| # No iterations run on an empty rank | ||
| return {self.name: 0} | ||
| elif self.side == LEFT: | ||
| return {self.name: dec.loc_abs_min - dec.glb_min} | ||
| else: | ||
| return {self.name: dec.glb_max - dec.loc_abs_max} | ||
|
|
||
|
|
||
| class AbstractSubDimension(DerivedDimension): | ||
|
|
||
| """ | ||
|
|
@@ -670,11 +706,9 @@ def _interval(self): | |
|
|
||
| @memoized_meth | ||
| def _symbolic_thickness(self, **kwargs): | ||
| kwargs = {'dtype': np.int32, 'is_const': True, 'nonnegative': True, | ||
| 'separated': self.separated} | ||
|
|
||
| names = [f"{self.parent.name}_{s}tkn" for s in ('l', 'r')] | ||
| return SubDimensionThickness(*[Thickness(name=n, **kwargs) for n in names]) | ||
| return SubDimensionThickness(*[Thickness(name=n, separated=self.separated) | ||
| for n in names]) | ||
|
|
||
| @cached_property | ||
| def symbolic_min(self): | ||
|
|
@@ -800,9 +834,7 @@ def middle(cls, name, parent, thickness_left, thickness_right, local=False, | |
|
|
||
| @memoized_meth | ||
| def _symbolic_thickness(self, thickness=None): | ||
| kwargs = {'dtype': np.int32, 'is_const': True, 'nonnegative': True, | ||
| 'root': self.root, 'local': self.local, | ||
| 'separated': self.separated} | ||
| kwargs = {'root': self.root, 'local': self.local, 'separated': self.separated} | ||
|
|
||
| names = [f"{self.parent.name}_{s}tkn" for s in ('l', 'r')] | ||
| sides = [LEFT, RIGHT] | ||
|
|
@@ -824,6 +856,27 @@ def _interval(self): | |
|
|
||
| return sympy.Interval(left, right) | ||
|
|
||
| @cached_property | ||
| def _glb_interval(self): | ||
| """ | ||
| The `(min, max)` bounds of this SubDimension in the global Grid, in this | ||
| rank's local indices. Unlike `_interval`, these are not clipped to this | ||
| rank, so with domain decomposition they may lie in the halo or beyond. | ||
| """ | ||
| lofs, rofs = self.root.rank_offsets | ||
|
|
||
| # The global Grid edges | ||
| left = self.parent.symbolic_min - lofs | ||
| right = self.parent.symbolic_max + rofs | ||
|
|
||
| # A tuple, not a `sympy.Interval`, which would collapse with literal bounds | ||
| if self.is_left: | ||
| return (left, left + self.ltkn.value - 1) | ||
| elif self.is_right: | ||
| return (right - self.rtkn.value + 1, right) | ||
| else: | ||
| return (left + self.ltkn.value, right - self.rtkn.value) | ||
|
|
||
| @property | ||
| def local(self): | ||
| return self._local | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks weird
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lifted directly from
Thicknessas far as I can tell. Git blame says @FabioLuporini did it - any idea why?