xref: /petsc/src/dm/impls/plex/plexdistribute.c (revision 053abcdfeaa3c4bf7b7c01a7334c7edc5567db03)
1 #include <petsc/private/dmpleximpl.h>  /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/dmlabelimpl.h> /*I      "petscdmlabel.h"  I*/
3 #include <petsc/private/partitionerimpl.h>
4 
5 /*@C
6   DMPlexSetAdjacencyUser - Define adjacency in the mesh using a user-provided callback
7 
8   Input Parameters:
9 + dm   - The DM object
10 . user - The user callback, may be `NULL` (to clear the callback)
11 - ctx  - context for callback evaluation, may be `NULL`
12 
13   Level: advanced
14 
15   Notes:
16   The caller of `DMPlexGetAdjacency()` may need to arrange that a large enough array is available for the adjacency.
17 
18   Any setting here overrides other configuration of `DMPLEX` adjacency determination.
19 
20 .seealso: `DMPLEX`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexGetAdjacency()`, `DMPlexGetAdjacencyUser()`
21 @*/
22 PetscErrorCode DMPlexSetAdjacencyUser(DM dm, PetscErrorCode (*user)(DM, PetscInt, PetscInt *, PetscInt[], void *), void *ctx)
23 {
24   DM_Plex *mesh = (DM_Plex *)dm->data;
25 
26   PetscFunctionBegin;
27   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28   mesh->useradjacency    = user;
29   mesh->useradjacencyctx = ctx;
30   PetscFunctionReturn(PETSC_SUCCESS);
31 }
32 
33 /*@C
34   DMPlexGetAdjacencyUser - get the user-defined adjacency callback
35 
36   Input Parameter:
37 . dm - The `DM` object
38 
39   Output Parameters:
40 + user - The callback
41 - ctx  - context for callback evaluation
42 
43   Level: advanced
44 
45 .seealso: `DMPLEX`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexGetAdjacency()`, `DMPlexSetAdjacencyUser()`
46 @*/
47 PetscErrorCode DMPlexGetAdjacencyUser(DM dm, PetscErrorCode (**user)(DM, PetscInt, PetscInt *, PetscInt[], void *), void **ctx)
48 {
49   DM_Plex *mesh = (DM_Plex *)dm->data;
50 
51   PetscFunctionBegin;
52   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
53   if (user) *user = mesh->useradjacency;
54   if (ctx) *ctx = mesh->useradjacencyctx;
55   PetscFunctionReturn(PETSC_SUCCESS);
56 }
57 
58 /*@
59   DMPlexSetAdjacencyUseAnchors - Define adjacency in the mesh using the point-to-point constraints.
60 
61   Input Parameters:
62 + dm         - The `DM` object
63 - useAnchors - Flag to use the constraints.  If PETSC_TRUE, then constrained points are omitted from DMPlexGetAdjacency(), and their anchor points appear in their place.
64 
65   Level: intermediate
66 
67 .seealso: `DMPLEX`, `DMGetAdjacency()`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexSetAnchors()`
68 @*/
69 PetscErrorCode DMPlexSetAdjacencyUseAnchors(DM dm, PetscBool useAnchors)
70 {
71   DM_Plex *mesh = (DM_Plex *)dm->data;
72 
73   PetscFunctionBegin;
74   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
75   mesh->useAnchors = useAnchors;
76   PetscFunctionReturn(PETSC_SUCCESS);
77 }
78 
79 /*@
80   DMPlexGetAdjacencyUseAnchors - Query whether adjacency in the mesh uses the point-to-point constraints.
81 
82   Input Parameter:
83 . dm - The `DM` object
84 
85   Output Parameter:
86 . useAnchors - Flag to use the closure.  If PETSC_TRUE, then constrained points are omitted from DMPlexGetAdjacency(), and their anchor points appear in their place.
87 
88   Level: intermediate
89 
90 .seealso: `DMPLEX`, `DMPlexSetAdjacencyUseAnchors()`, `DMSetAdjacency()`, `DMGetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexSetAnchors()`
91 @*/
92 PetscErrorCode DMPlexGetAdjacencyUseAnchors(DM dm, PetscBool *useAnchors)
93 {
94   DM_Plex *mesh = (DM_Plex *)dm->data;
95 
96   PetscFunctionBegin;
97   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
98   PetscAssertPointer(useAnchors, 2);
99   *useAnchors = mesh->useAnchors;
100   PetscFunctionReturn(PETSC_SUCCESS);
101 }
102 
103 static PetscErrorCode DMPlexGetAdjacency_Cone_Internal(DM dm, PetscInt p, PetscInt *adjSize, PetscInt adj[])
104 {
105   const PetscInt *cone   = NULL;
106   PetscInt        numAdj = 0, maxAdjSize = *adjSize, coneSize, c;
107 
108   PetscFunctionBeginHot;
109   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
110   PetscCall(DMPlexGetCone(dm, p, &cone));
111   for (c = 0; c <= coneSize; ++c) {
112     const PetscInt  point   = !c ? p : cone[c - 1];
113     const PetscInt *support = NULL;
114     PetscInt        supportSize, s, q;
115 
116     PetscCall(DMPlexGetSupportSize(dm, point, &supportSize));
117     PetscCall(DMPlexGetSupport(dm, point, &support));
118     for (s = 0; s < supportSize; ++s) {
119       for (q = 0; q < numAdj || ((void)(adj[numAdj++] = support[s]), 0); ++q) {
120         if (support[s] == adj[q]) break;
121       }
122       PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize);
123     }
124   }
125   *adjSize = numAdj;
126   PetscFunctionReturn(PETSC_SUCCESS);
127 }
128 
129 static PetscErrorCode DMPlexGetAdjacency_Support_Internal(DM dm, PetscInt p, PetscInt *adjSize, PetscInt adj[])
130 {
131   const PetscInt *support = NULL;
132   PetscInt        numAdj = 0, maxAdjSize = *adjSize, supportSize, s;
133 
134   PetscFunctionBeginHot;
135   PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
136   PetscCall(DMPlexGetSupport(dm, p, &support));
137   for (s = 0; s <= supportSize; ++s) {
138     const PetscInt  point = !s ? p : support[s - 1];
139     const PetscInt *cone  = NULL;
140     PetscInt        coneSize, c, q;
141 
142     PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
143     PetscCall(DMPlexGetCone(dm, point, &cone));
144     for (c = 0; c < coneSize; ++c) {
145       for (q = 0; q < numAdj || ((void)(adj[numAdj++] = cone[c]), 0); ++q) {
146         if (cone[c] == adj[q]) break;
147       }
148       PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize);
149     }
150   }
151   *adjSize = numAdj;
152   PetscFunctionReturn(PETSC_SUCCESS);
153 }
154 
155 static PetscErrorCode DMPlexGetAdjacency_Transitive_Internal(DM dm, PetscInt p, PetscBool useClosure, PetscInt *adjSize, PetscInt adj[])
156 {
157   PetscInt *star   = NULL;
158   PetscInt  numAdj = 0, maxAdjSize = *adjSize, starSize, s;
159 
160   PetscFunctionBeginHot;
161   PetscCall(DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, &star));
162   for (s = 0; s < starSize * 2; s += 2) {
163     const PetscInt *closure = NULL;
164     PetscInt        closureSize, c, q;
165 
166     PetscCall(DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **)&closure));
167     for (c = 0; c < closureSize * 2; c += 2) {
168       for (q = 0; q < numAdj || ((void)(adj[numAdj++] = closure[c]), 0); ++q) {
169         if (closure[c] == adj[q]) break;
170       }
171       PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize);
172     }
173     PetscCall(DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **)&closure));
174   }
175   PetscCall(DMPlexRestoreTransitiveClosure(dm, p, useClosure, &starSize, &star));
176   *adjSize = numAdj;
177   PetscFunctionReturn(PETSC_SUCCESS);
178 }
179 
180 // Returns the maximum number of adjacent points in the DMPlex
181 PetscErrorCode DMPlexGetMaxAdjacencySize_Internal(DM dm, PetscBool useAnchors, PetscInt *max_adjacency_size)
182 {
183   PetscInt depth, maxC, maxS, maxP, pStart, pEnd, asiz, maxAnchors = 1;
184 
185   PetscFunctionBeginUser;
186   if (useAnchors) {
187     PetscSection aSec = NULL;
188     IS           aIS  = NULL;
189     PetscInt     aStart, aEnd;
190     PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
191     if (aSec) {
192       PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchors));
193       maxAnchors = PetscMax(1, maxAnchors);
194       PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
195     }
196   }
197 
198   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
199   PetscCall(DMPlexGetDepth(dm, &depth));
200   depth = PetscMax(depth, -depth);
201   PetscCall(DMPlexGetMaxSizes(dm, &maxC, &maxS));
202   maxP = maxS * maxC;
203   /* Adjacency can be as large as supp(cl(cell)) or cl(supp(vertex)),
204           supp(cell) + supp(maxC faces) + supp(maxC^2 edges) + supp(maxC^3 vertices)
205         = 0 + maxS*maxC + maxS^2*maxC^2 + maxS^3*maxC^3
206         = \sum^d_{i=0} (maxS*maxC)^i - 1
207         = (maxS*maxC)^{d+1} - 1 / (maxS*maxC - 1) - 1
208     We could improve this by getting the max by strata:
209           supp[d](cell) + supp[d-1](maxC[d] faces) + supp[1](maxC[d]*maxC[d-1] edges) + supp[0](maxC[d]*maxC[d-1]*maxC[d-2] vertices)
210         = 0 + maxS[d-1]*maxC[d] + maxS[1]*maxC[d]*maxC[d-1] + maxS[0]*maxC[d]*maxC[d-1]*maxC[d-2]
211     and the same with S and C reversed
212   */
213   if ((depth == 3 && maxP > 200) || (depth == 2 && maxP > 580)) asiz = pEnd - pStart;
214   else asiz = (maxP > 1) ? ((PetscPowInt(maxP, depth + 1) - 1) / (maxP - 1)) : depth + 1;
215   asiz *= maxAnchors;
216   *max_adjacency_size = PetscMin(asiz, pEnd - pStart);
217   PetscFunctionReturn(PETSC_SUCCESS);
218 }
219 
220 // Returns Adjacent mesh points to the selected point given specific criteria
221 //
222 // + adjSize - Number of adjacent points
223 // - adj - Array of the adjacent points
224 PetscErrorCode DMPlexGetAdjacency_Internal(DM dm, PetscInt p, PetscBool useCone, PetscBool useTransitiveClosure, PetscBool useAnchors, PetscInt *adjSize, PetscInt *adj[])
225 {
226   static PetscInt asiz   = 0;
227   PetscInt        aStart = -1, aEnd = -1;
228   PetscInt        maxAdjSize;
229   PetscSection    aSec = NULL;
230   IS              aIS  = NULL;
231   const PetscInt *anchors;
232   DM_Plex        *mesh = (DM_Plex *)dm->data;
233 
234   PetscFunctionBeginHot;
235   if (useAnchors) {
236     PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
237     if (aSec) {
238       PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
239       PetscCall(ISGetIndices(aIS, &anchors));
240     }
241   }
242   if (!*adj) {
243     PetscCall(DMPlexGetMaxAdjacencySize_Internal(dm, useAnchors, &asiz));
244     PetscCall(PetscMalloc1(asiz, adj));
245   }
246   if (*adjSize < 0) *adjSize = asiz;
247   maxAdjSize = *adjSize;
248   if (mesh->useradjacency) {
249     PetscCall((*mesh->useradjacency)(dm, p, adjSize, *adj, mesh->useradjacencyctx));
250   } else if (useTransitiveClosure) {
251     PetscCall(DMPlexGetAdjacency_Transitive_Internal(dm, p, useCone, adjSize, *adj));
252   } else if (useCone) {
253     PetscCall(DMPlexGetAdjacency_Cone_Internal(dm, p, adjSize, *adj));
254   } else {
255     PetscCall(DMPlexGetAdjacency_Support_Internal(dm, p, adjSize, *adj));
256   }
257   if (useAnchors && aSec) {
258     PetscInt  origSize = *adjSize;
259     PetscInt  numAdj   = origSize;
260     PetscInt  i        = 0, j;
261     PetscInt *orig     = *adj;
262 
263     while (i < origSize) {
264       PetscInt p    = orig[i];
265       PetscInt aDof = 0;
266 
267       if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof));
268       if (aDof) {
269         PetscInt aOff;
270         PetscInt s, q;
271 
272         for (j = i + 1; j < numAdj; j++) orig[j - 1] = orig[j];
273         origSize--;
274         numAdj--;
275         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
276         for (s = 0; s < aDof; ++s) {
277           for (q = 0; q < numAdj || ((void)(orig[numAdj++] = anchors[aOff + s]), 0); ++q) {
278             if (anchors[aOff + s] == orig[q]) break;
279           }
280           PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize);
281         }
282       } else {
283         i++;
284       }
285     }
286     *adjSize = numAdj;
287     PetscCall(ISRestoreIndices(aIS, &anchors));
288   }
289   PetscFunctionReturn(PETSC_SUCCESS);
290 }
291 
292 /*@
293   DMPlexGetAdjacency - Return all points adjacent to the given point
294 
295   Input Parameters:
296 + dm - The `DM` object
297 - p  - The point
298 
299   Input/Output Parameters:
300 + adjSize - The maximum size of `adj` if it is non-`NULL`, or `PETSC_DETERMINE`;
301             on output the number of adjacent points
302 - adj     - Either `NULL` so that the array is allocated, or an existing array with size `adjSize`;
303             on output contains the adjacent points
304 
305   Level: advanced
306 
307   Notes:
308   The user must `PetscFree()` the `adj` array if it was not passed in.
309 
310 .seealso: `DMPLEX`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMCreateMatrix()`, `DMPlexPreallocateOperator()`
311 @*/
312 PetscErrorCode DMPlexGetAdjacency(DM dm, PetscInt p, PetscInt *adjSize, PetscInt *adj[])
313 {
314   PetscBool useCone, useClosure, useAnchors;
315 
316   PetscFunctionBeginHot;
317   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
318   PetscAssertPointer(adjSize, 3);
319   PetscAssertPointer(adj, 4);
320   PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
321   PetscCall(DMPlexGetAdjacencyUseAnchors(dm, &useAnchors));
322   PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, adjSize, adj));
323   PetscFunctionReturn(PETSC_SUCCESS);
324 }
325 
326 /*@
327   DMPlexCreateTwoSidedProcessSF - Create an `PetscSF` which just has process connectivity
328 
329   Collective
330 
331   Input Parameters:
332 + dm              - The `DM`
333 . sfPoint         - The `PetscSF` which encodes point connectivity
334 . rootRankSection - to be documented
335 . rootRanks       - to be documented
336 . leafRankSection - to be documented
337 - leafRanks       - to be documented
338 
339   Output Parameters:
340 + processRanks - A list of process neighbors, or `NULL`
341 - sfProcess    - An `PetscSF` encoding the two-sided process connectivity, or `NULL`
342 
343   Level: developer
344 
345 .seealso: `DMPLEX`, `PetscSFCreate()`, `DMPlexCreateProcessSF()`
346 @*/
347 PetscErrorCode DMPlexCreateTwoSidedProcessSF(DM dm, PetscSF sfPoint, PetscSection rootRankSection, IS rootRanks, PetscSection leafRankSection, IS leafRanks, PeOp IS *processRanks, PeOp PetscSF *sfProcess)
348 {
349   const PetscSFNode *remotePoints;
350   PetscInt          *localPointsNew;
351   PetscSFNode       *remotePointsNew;
352   const PetscInt    *nranks;
353   PetscInt          *ranksNew;
354   PetscBT            neighbors;
355   PetscInt           pStart, pEnd, p, numLeaves, l, numNeighbors, n;
356   PetscMPIInt        size, proc, rank;
357 
358   PetscFunctionBegin;
359   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
360   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
361   if (processRanks) PetscAssertPointer(processRanks, 7);
362   if (sfProcess) PetscAssertPointer(sfProcess, 8);
363   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
364   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
365   PetscCall(PetscSFGetGraph(sfPoint, NULL, &numLeaves, NULL, &remotePoints));
366   PetscCall(PetscBTCreate(size, &neighbors));
367   PetscCall(PetscBTMemzero(size, neighbors));
368   /* Compute root-to-leaf process connectivity */
369   PetscCall(PetscSectionGetChart(rootRankSection, &pStart, &pEnd));
370   PetscCall(ISGetIndices(rootRanks, &nranks));
371   for (p = pStart; p < pEnd; ++p) {
372     PetscInt ndof, noff, n;
373 
374     PetscCall(PetscSectionGetDof(rootRankSection, p, &ndof));
375     PetscCall(PetscSectionGetOffset(rootRankSection, p, &noff));
376     for (n = 0; n < ndof; ++n) PetscCall(PetscBTSet(neighbors, nranks[noff + n]));
377   }
378   PetscCall(ISRestoreIndices(rootRanks, &nranks));
379   /* Compute leaf-to-neighbor process connectivity */
380   PetscCall(PetscSectionGetChart(leafRankSection, &pStart, &pEnd));
381   PetscCall(ISGetIndices(leafRanks, &nranks));
382   for (p = pStart; p < pEnd; ++p) {
383     PetscInt ndof, noff, n;
384 
385     PetscCall(PetscSectionGetDof(leafRankSection, p, &ndof));
386     PetscCall(PetscSectionGetOffset(leafRankSection, p, &noff));
387     for (n = 0; n < ndof; ++n) PetscCall(PetscBTSet(neighbors, nranks[noff + n]));
388   }
389   PetscCall(ISRestoreIndices(leafRanks, &nranks));
390   /* Compute leaf-to-root process connectivity */
391   for (l = 0; l < numLeaves; ++l) PetscCall(PetscBTSet(neighbors, remotePoints[l].rank));
392   /* Calculate edges */
393   PetscCall(PetscBTClear(neighbors, rank));
394   for (proc = 0, numNeighbors = 0; proc < size; ++proc) {
395     if (PetscBTLookup(neighbors, proc)) ++numNeighbors;
396   }
397   PetscCall(PetscMalloc1(numNeighbors, &ranksNew));
398   PetscCall(PetscMalloc1(numNeighbors, &localPointsNew));
399   PetscCall(PetscMalloc1(numNeighbors, &remotePointsNew));
400   for (proc = 0, n = 0; proc < size; ++proc) {
401     if (PetscBTLookup(neighbors, proc)) {
402       ranksNew[n]              = proc;
403       localPointsNew[n]        = proc;
404       remotePointsNew[n].index = rank;
405       remotePointsNew[n].rank  = proc;
406       ++n;
407     }
408   }
409   PetscCall(PetscBTDestroy(&neighbors));
410   if (processRanks) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), numNeighbors, ranksNew, PETSC_OWN_POINTER, processRanks));
411   else PetscCall(PetscFree(ranksNew));
412   if (sfProcess) {
413     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess));
414     PetscCall(PetscObjectSetName((PetscObject)*sfProcess, "Two-Sided Process SF"));
415     PetscCall(PetscSFSetFromOptions(*sfProcess));
416     PetscCall(PetscSFSetGraph(*sfProcess, size, numNeighbors, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER));
417   }
418   PetscFunctionReturn(PETSC_SUCCESS);
419 }
420 
421 /*@
422   DMPlexDistributeOwnership - Compute owner information for shared points. This basically gets two-sided for an SF.
423 
424   Collective
425 
426   Input Parameter:
427 . dm - The `DM`
428 
429   Output Parameters:
430 + rootSection - The number of leaves for a given root point
431 . rootrank    - The rank of each edge into the root point
432 . leafSection - The number of processes sharing a given leaf point
433 - leafrank    - The rank of each process sharing a leaf point
434 
435   Level: developer
436 
437 .seealso: `DMPLEX`, `DMPlexCreateOverlapLabel()`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()`
438 @*/
439 PetscErrorCode DMPlexDistributeOwnership(DM dm, PetscSection rootSection, IS *rootrank, PetscSection leafSection, IS *leafrank)
440 {
441   MPI_Comm        comm;
442   PetscSF         sfPoint;
443   const PetscInt *rootdegree;
444   PetscInt       *myrank, *remoterank;
445   PetscInt        pStart, pEnd, p, nedges;
446   PetscMPIInt     rank;
447 
448   PetscFunctionBegin;
449   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
450   PetscCallMPI(MPI_Comm_rank(comm, &rank));
451   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
452   PetscCall(DMGetPointSF(dm, &sfPoint));
453   /* Compute number of leaves for each root */
454   PetscCall(PetscObjectSetName((PetscObject)rootSection, "Root Section"));
455   PetscCall(PetscSectionSetChart(rootSection, pStart, pEnd));
456   PetscCall(PetscSFComputeDegreeBegin(sfPoint, &rootdegree));
457   PetscCall(PetscSFComputeDegreeEnd(sfPoint, &rootdegree));
458   for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(rootSection, p, rootdegree[p - pStart]));
459   PetscCall(PetscSectionSetUp(rootSection));
460   /* Gather rank of each leaf to root */
461   PetscCall(PetscSectionGetStorageSize(rootSection, &nedges));
462   PetscCall(PetscMalloc1(pEnd - pStart, &myrank));
463   PetscCall(PetscMalloc1(nedges, &remoterank));
464   for (p = 0; p < pEnd - pStart; ++p) myrank[p] = rank;
465   PetscCall(PetscSFGatherBegin(sfPoint, MPIU_INT, myrank, remoterank));
466   PetscCall(PetscSFGatherEnd(sfPoint, MPIU_INT, myrank, remoterank));
467   PetscCall(PetscFree(myrank));
468   PetscCall(ISCreateGeneral(comm, nedges, remoterank, PETSC_OWN_POINTER, rootrank));
469   /* Distribute remote ranks to leaves */
470   PetscCall(PetscObjectSetName((PetscObject)leafSection, "Leaf Section"));
471   PetscCall(DMPlexDistributeFieldIS(dm, sfPoint, rootSection, *rootrank, leafSection, leafrank));
472   PetscFunctionReturn(PETSC_SUCCESS);
473 }
474 
475 /*@
476   DMPlexCreateOverlapLabel - Compute a label indicating what overlap points should be sent to new processes
477 
478   Collective
479 
480   Input Parameters:
481 + dm          - The `DM`
482 . levels      - Number of overlap levels
483 . rootSection - The number of leaves for a given root point
484 . rootrank    - The rank of each edge into the root point
485 . leafSection - The number of processes sharing a given leaf point
486 - leafrank    - The rank of each process sharing a leaf point
487 
488   Output Parameter:
489 . ovLabel - `DMLabel` containing remote overlap contributions as point/rank pairings
490 
491   Level: developer
492 
493 .seealso: `DMPLEX`, `DMPlexCreateOverlapLabelFromLabels()`, `DMPlexGetAdjacency()`, `DMPlexDistributeOwnership()`, `DMPlexDistribute()`
494 @*/
495 PetscErrorCode DMPlexCreateOverlapLabel(DM dm, PetscInt levels, PetscSection rootSection, IS rootrank, PetscSection leafSection, IS leafrank, DMLabel *ovLabel)
496 {
497   MPI_Comm           comm;
498   DMLabel            ovAdjByRank; /* A DMLabel containing all points adjacent to shared points, separated by rank (value in label) */
499   PetscSF            sfPoint;
500   const PetscSFNode *remote;
501   const PetscInt    *local;
502   const PetscInt    *nrank, *rrank;
503   PetscInt          *adj = NULL;
504   PetscInt           pStart, pEnd, p, sStart, sEnd, nleaves, l;
505   PetscMPIInt        rank, size;
506   PetscBool          flg;
507 
508   PetscFunctionBegin;
509   *ovLabel = NULL;
510   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
511   PetscCallMPI(MPI_Comm_size(comm, &size));
512   PetscCallMPI(MPI_Comm_rank(comm, &rank));
513   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
514   PetscCall(DMGetPointSF(dm, &sfPoint));
515   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
516   if (!levels) {
517     /* Add owned points */
518     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap label", ovLabel));
519     for (p = pStart; p < pEnd; ++p) PetscCall(DMLabelSetValue(*ovLabel, p, rank));
520     PetscFunctionReturn(PETSC_SUCCESS);
521   }
522   PetscCall(PetscSectionGetChart(leafSection, &sStart, &sEnd));
523   PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote));
524   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap adjacency", &ovAdjByRank));
525   /* Handle leaves: shared with the root point */
526   for (l = 0; l < nleaves; ++l) {
527     PetscInt adjSize = PETSC_DETERMINE, a;
528 
529     PetscCall(DMPlexGetAdjacency(dm, local ? local[l] : l, &adjSize, &adj));
530     for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remote[l].rank));
531   }
532   PetscCall(ISGetIndices(rootrank, &rrank));
533   PetscCall(ISGetIndices(leafrank, &nrank));
534   /* Handle roots */
535   for (p = pStart; p < pEnd; ++p) {
536     PetscInt adjSize = PETSC_DETERMINE, neighbors = 0, noff, n, a;
537 
538     if ((p >= sStart) && (p < sEnd)) {
539       /* Some leaves share a root with other leaves on different processes */
540       PetscCall(PetscSectionGetDof(leafSection, p, &neighbors));
541       if (neighbors) {
542         PetscCall(PetscSectionGetOffset(leafSection, p, &noff));
543         PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
544         for (n = 0; n < neighbors; ++n) {
545           const PetscInt remoteRank = nrank[noff + n];
546 
547           if (remoteRank == rank) continue;
548           for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank));
549         }
550       }
551     }
552     /* Roots are shared with leaves */
553     PetscCall(PetscSectionGetDof(rootSection, p, &neighbors));
554     if (!neighbors) continue;
555     PetscCall(PetscSectionGetOffset(rootSection, p, &noff));
556     PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
557     for (n = 0; n < neighbors; ++n) {
558       const PetscInt remoteRank = rrank[noff + n];
559 
560       if (remoteRank == rank) continue;
561       for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank));
562     }
563   }
564   PetscCall(PetscFree(adj));
565   PetscCall(ISRestoreIndices(rootrank, &rrank));
566   PetscCall(ISRestoreIndices(leafrank, &nrank));
567   /* Add additional overlap levels */
568   for (l = 1; l < levels; l++) {
569     /* Propagate point donations over SF to capture remote connections */
570     PetscCall(DMPlexPartitionLabelPropagate(dm, ovAdjByRank));
571     /* Add next level of point donations to the label */
572     PetscCall(DMPlexPartitionLabelAdjacency(dm, ovAdjByRank));
573   }
574   /* We require the closure in the overlap */
575   PetscCall(DMPlexPartitionLabelClosure(dm, ovAdjByRank));
576   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-overlap_view", &flg));
577   if (flg) {
578     PetscViewer viewer;
579     PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &viewer));
580     PetscCall(DMLabelView(ovAdjByRank, viewer));
581   }
582   /* Invert sender to receiver label */
583   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap label", ovLabel));
584   PetscCall(DMPlexPartitionLabelInvert(dm, ovAdjByRank, NULL, *ovLabel));
585   /* Add owned points, except for shared local points */
586   for (p = pStart; p < pEnd; ++p) PetscCall(DMLabelSetValue(*ovLabel, p, rank));
587   for (l = 0; l < nleaves; ++l) {
588     PetscCall(DMLabelClearValue(*ovLabel, local[l], rank));
589     PetscCall(DMLabelSetValue(*ovLabel, remote[l].index, remote[l].rank));
590   }
591   /* Clean up */
592   PetscCall(DMLabelDestroy(&ovAdjByRank));
593   PetscFunctionReturn(PETSC_SUCCESS);
594 }
595 
596 static PetscErrorCode HandlePoint_Private(DM dm, PetscInt p, PetscSection section, const PetscInt ranks[], PetscInt numExLabels, const DMLabel exLabel[], const PetscInt exValue[], DMLabel ovAdjByRank)
597 {
598   PetscInt neighbors, el;
599 
600   PetscFunctionBegin;
601   PetscCall(PetscSectionGetDof(section, p, &neighbors));
602   if (neighbors) {
603     PetscInt   *adj     = NULL;
604     PetscInt    adjSize = PETSC_DETERMINE, noff, n, a;
605     PetscMPIInt rank;
606 
607     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
608     PetscCall(PetscSectionGetOffset(section, p, &noff));
609     PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
610     for (n = 0; n < neighbors; ++n) {
611       const PetscInt remoteRank = ranks[noff + n];
612 
613       if (remoteRank == rank) continue;
614       for (a = 0; a < adjSize; ++a) {
615         PetscBool insert = PETSC_TRUE;
616 
617         for (el = 0; el < numExLabels; ++el) {
618           PetscInt exVal;
619           PetscCall(DMLabelGetValue(exLabel[el], adj[a], &exVal));
620           if (exVal == exValue[el]) {
621             insert = PETSC_FALSE;
622             break;
623           }
624         }
625         if (insert) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank));
626       }
627     }
628     PetscCall(PetscFree(adj));
629   }
630   PetscFunctionReturn(PETSC_SUCCESS);
631 }
632 
633 /*@C
634   DMPlexCreateOverlapLabelFromLabels - Compute a label indicating what overlap points should be sent to new processes
635 
636   Collective
637 
638   Input Parameters:
639 + dm          - The `DM`
640 . numLabels   - The number of labels to draw candidate points from
641 . label       - An array of labels containing candidate points
642 . value       - An array of label values marking the candidate points
643 . numExLabels - The number of labels to use for exclusion
644 . exLabel     - An array of labels indicating points to be excluded, or `NULL`
645 . exValue     - An array of label values to be excluded, or `NULL`
646 . rootSection - The number of leaves for a given root point
647 . rootrank    - The rank of each edge into the root point
648 . leafSection - The number of processes sharing a given leaf point
649 - leafrank    - The rank of each process sharing a leaf point
650 
651   Output Parameter:
652 . ovLabel - `DMLabel` containing remote overlap contributions as point/rank pairings
653 
654   Level: developer
655 
656   Note:
657   The candidate points are only added to the overlap if they are adjacent to a shared point
658 
659 .seealso: `DMPLEX`, `DMPlexCreateOverlapLabel()`, `DMPlexGetAdjacency()`, `DMPlexDistributeOwnership()`, `DMPlexDistribute()`
660 @*/
661 PetscErrorCode DMPlexCreateOverlapLabelFromLabels(DM dm, PetscInt numLabels, const DMLabel label[], const PetscInt value[], PetscInt numExLabels, const DMLabel exLabel[], const PetscInt exValue[], PetscSection rootSection, IS rootrank, PetscSection leafSection, IS leafrank, DMLabel *ovLabel)
662 {
663   MPI_Comm           comm;
664   DMLabel            ovAdjByRank; /* A DMLabel containing all points adjacent to shared points, separated by rank (value in label) */
665   PetscSF            sfPoint;
666   const PetscSFNode *remote;
667   const PetscInt    *local;
668   const PetscInt    *nrank, *rrank;
669   PetscInt          *adj = NULL;
670   PetscInt           pStart, pEnd, p, sStart, sEnd, nleaves, l, el;
671   PetscMPIInt        rank, size;
672   PetscBool          flg;
673 
674   PetscFunctionBegin;
675   *ovLabel = NULL;
676   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
677   PetscCallMPI(MPI_Comm_size(comm, &size));
678   PetscCallMPI(MPI_Comm_rank(comm, &rank));
679   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
680   PetscCall(DMGetPointSF(dm, &sfPoint));
681   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
682   PetscCall(PetscSectionGetChart(leafSection, &sStart, &sEnd));
683   PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote));
684   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap adjacency", &ovAdjByRank));
685   PetscCall(ISGetIndices(rootrank, &rrank));
686   PetscCall(ISGetIndices(leafrank, &nrank));
687   for (l = 0; l < numLabels; ++l) {
688     IS              valIS;
689     const PetscInt *points;
690     PetscInt        n;
691 
692     PetscCall(DMLabelGetStratumIS(label[l], value[l], &valIS));
693     if (!valIS) continue;
694     PetscCall(ISGetIndices(valIS, &points));
695     PetscCall(ISGetLocalSize(valIS, &n));
696     for (PetscInt i = 0; i < n; ++i) {
697       const PetscInt p = points[i];
698 
699       if ((p >= sStart) && (p < sEnd)) {
700         PetscInt loc, adjSize = PETSC_DETERMINE;
701 
702         /* Handle leaves: shared with the root point */
703         if (local) PetscCall(PetscFindInt(p, nleaves, local, &loc));
704         else loc = (p >= 0 && p < nleaves) ? p : -1;
705         if (loc >= 0) {
706           const PetscInt remoteRank = remote[loc].rank;
707 
708           PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
709           for (PetscInt a = 0; a < adjSize; ++a) {
710             PetscBool insert = PETSC_TRUE;
711 
712             for (el = 0; el < numExLabels; ++el) {
713               PetscInt exVal;
714               PetscCall(DMLabelGetValue(exLabel[el], adj[a], &exVal));
715               if (exVal == exValue[el]) {
716                 insert = PETSC_FALSE;
717                 break;
718               }
719             }
720             if (insert) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank));
721           }
722         }
723         /* Some leaves share a root with other leaves on different processes */
724         PetscCall(HandlePoint_Private(dm, p, leafSection, nrank, numExLabels, exLabel, exValue, ovAdjByRank));
725       }
726       /* Roots are shared with leaves */
727       PetscCall(HandlePoint_Private(dm, p, rootSection, rrank, numExLabels, exLabel, exValue, ovAdjByRank));
728     }
729     PetscCall(ISRestoreIndices(valIS, &points));
730     PetscCall(ISDestroy(&valIS));
731   }
732   PetscCall(PetscFree(adj));
733   PetscCall(ISRestoreIndices(rootrank, &rrank));
734   PetscCall(ISRestoreIndices(leafrank, &nrank));
735   /* We require the closure in the overlap */
736   PetscCall(DMPlexPartitionLabelClosure(dm, ovAdjByRank));
737   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-overlap_view", &flg));
738   if (flg) {
739     PetscViewer viewer;
740     PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &viewer));
741     PetscCall(DMLabelView(ovAdjByRank, viewer));
742   }
743   /* Invert sender to receiver label */
744   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap label", ovLabel));
745   PetscCall(DMPlexPartitionLabelInvert(dm, ovAdjByRank, NULL, *ovLabel));
746   /* Add owned points, except for shared local points */
747   for (p = pStart; p < pEnd; ++p) PetscCall(DMLabelSetValue(*ovLabel, p, rank));
748   for (l = 0; l < nleaves; ++l) {
749     PetscCall(DMLabelClearValue(*ovLabel, local[l], rank));
750     PetscCall(DMLabelSetValue(*ovLabel, remote[l].index, remote[l].rank));
751   }
752   /* Clean up */
753   PetscCall(DMLabelDestroy(&ovAdjByRank));
754   PetscFunctionReturn(PETSC_SUCCESS);
755 }
756 
757 /*@
758   DMPlexCreateOverlapMigrationSF - Create a `PetscSF` describing the new mesh distribution to make the overlap described by the input `PetscSF`
759 
760   Collective
761 
762   Input Parameters:
763 + dm        - The `DM`
764 - overlapSF - The `PetscSF` mapping ghost points in overlap to owner points on other processes
765 
766   Output Parameter:
767 . migrationSF - A `PetscSF` that maps original points in old locations to points in new locations
768 
769   Level: developer
770 
771 .seealso: `DMPLEX`, `DMPlexCreateOverlapLabel()`, `DMPlexDistributeOverlap()`, `DMPlexDistribute()`
772 @*/
773 PetscErrorCode DMPlexCreateOverlapMigrationSF(DM dm, PetscSF overlapSF, PetscSF *migrationSF)
774 {
775   MPI_Comm           comm;
776   PetscMPIInt        rank, size;
777   PetscInt           d, dim, p, pStart, pEnd, nroots, nleaves, newLeaves, point, numSharedPoints;
778   PetscInt          *pointDepths, *remoteDepths, *ilocal;
779   PetscInt          *depthRecv, *depthShift, *depthIdx;
780   PetscSFNode       *iremote;
781   PetscSF            pointSF;
782   const PetscInt    *sharedLocal;
783   const PetscSFNode *overlapRemote, *sharedRemote;
784 
785   PetscFunctionBegin;
786   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
787   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
788   PetscCallMPI(MPI_Comm_rank(comm, &rank));
789   PetscCallMPI(MPI_Comm_size(comm, &size));
790   PetscCall(DMGetDimension(dm, &dim));
791 
792   /* Before building the migration SF we need to know the new stratum offsets */
793   PetscCall(PetscSFGetGraph(overlapSF, &nroots, &nleaves, NULL, &overlapRemote));
794   PetscCall(PetscMalloc2(nroots, &pointDepths, nleaves, &remoteDepths));
795   for (d = 0; d < dim + 1; d++) {
796     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
797     for (p = pStart; p < pEnd; p++) pointDepths[p] = d;
798   }
799   for (p = 0; p < nleaves; p++) remoteDepths[p] = -1;
800   PetscCall(PetscSFBcastBegin(overlapSF, MPIU_INT, pointDepths, remoteDepths, MPI_REPLACE));
801   PetscCall(PetscSFBcastEnd(overlapSF, MPIU_INT, pointDepths, remoteDepths, MPI_REPLACE));
802 
803   /* Count received points in each stratum and compute the internal strata shift */
804   PetscCall(PetscMalloc3(dim + 1, &depthRecv, dim + 1, &depthShift, dim + 1, &depthIdx));
805   for (d = 0; d < dim + 1; d++) depthRecv[d] = 0;
806   for (p = 0; p < nleaves; p++) depthRecv[remoteDepths[p]]++;
807   depthShift[dim] = 0;
808   for (d = 0; d < dim; d++) depthShift[d] = depthRecv[dim];
809   for (d = 1; d < dim; d++) depthShift[d] += depthRecv[0];
810   for (d = dim - 2; d > 0; d--) depthShift[d] += depthRecv[d + 1];
811   for (d = 0; d < dim + 1; d++) {
812     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
813     depthIdx[d] = pStart + depthShift[d];
814   }
815 
816   /* Form the overlap SF build an SF that describes the full overlap migration SF */
817   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
818   newLeaves = pEnd - pStart + nleaves;
819   PetscCall(PetscMalloc1(newLeaves, &ilocal));
820   PetscCall(PetscMalloc1(newLeaves, &iremote));
821   /* First map local points to themselves */
822   for (d = 0; d < dim + 1; d++) {
823     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
824     for (p = pStart; p < pEnd; p++) {
825       point                = p + depthShift[d];
826       ilocal[point]        = point;
827       iremote[point].index = p;
828       iremote[point].rank  = rank;
829       depthIdx[d]++;
830     }
831   }
832 
833   /* Add in the remote roots for currently shared points */
834   PetscCall(DMGetPointSF(dm, &pointSF));
835   PetscCall(PetscSFGetGraph(pointSF, NULL, &numSharedPoints, &sharedLocal, &sharedRemote));
836   for (d = 0; d < dim + 1; d++) {
837     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
838     for (p = 0; p < numSharedPoints; p++) {
839       if (pStart <= sharedLocal[p] && sharedLocal[p] < pEnd) {
840         point                = sharedLocal[p] + depthShift[d];
841         iremote[point].index = sharedRemote[p].index;
842         iremote[point].rank  = sharedRemote[p].rank;
843       }
844     }
845   }
846 
847   /* Now add the incoming overlap points */
848   for (p = 0; p < nleaves; p++) {
849     point                = depthIdx[remoteDepths[p]];
850     ilocal[point]        = point;
851     iremote[point].index = overlapRemote[p].index;
852     iremote[point].rank  = overlapRemote[p].rank;
853     depthIdx[remoteDepths[p]]++;
854   }
855   PetscCall(PetscFree2(pointDepths, remoteDepths));
856 
857   PetscCall(PetscSFCreate(comm, migrationSF));
858   PetscCall(PetscObjectSetName((PetscObject)*migrationSF, "Overlap Migration SF"));
859   PetscCall(PetscSFSetFromOptions(*migrationSF));
860   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
861   PetscCall(PetscSFSetGraph(*migrationSF, pEnd - pStart, newLeaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
862 
863   PetscCall(PetscFree3(depthRecv, depthShift, depthIdx));
864   PetscFunctionReturn(PETSC_SUCCESS);
865 }
866 
867 /*@
868   DMPlexStratifyMigrationSF - Rearrange the leaves of a migration sf for stratification.
869 
870   Input Parameters:
871 + dm - The DM
872 - sf - A star forest with non-ordered leaves, usually defining a DM point migration
873 
874   Output Parameter:
875 . migrationSF - A star forest with added leaf indirection that ensures the resulting DM is stratified
876 
877   Level: developer
878 
879   Note:
880   This lexicographically sorts by (depth, cellType)
881 
882 .seealso: `DMPLEX`, `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()`
883 @*/
884 PetscErrorCode DMPlexStratifyMigrationSF(DM dm, PetscSF sf, PetscSF *migrationSF)
885 {
886   MPI_Comm           comm;
887   PetscMPIInt        rank, size;
888   PetscInt           d, ldepth, depth, dim, p, pStart, pEnd, nroots, nleaves;
889   PetscSFNode       *pointDepths, *remoteDepths;
890   PetscInt          *ilocal;
891   PetscInt          *depthRecv, *depthShift, *depthIdx;
892   PetscInt          *ctRecv, *ctShift, *ctIdx;
893   const PetscSFNode *iremote;
894 
895   PetscFunctionBegin;
896   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
897   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
898   PetscCallMPI(MPI_Comm_rank(comm, &rank));
899   PetscCallMPI(MPI_Comm_size(comm, &size));
900   PetscCall(DMPlexGetDepth(dm, &ldepth));
901   PetscCall(DMGetDimension(dm, &dim));
902   PetscCallMPI(MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
903   PetscCheck(!(ldepth >= 0) || !(depth != ldepth), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %" PetscInt_FMT " != %" PetscInt_FMT, ldepth, depth);
904   PetscCall(PetscLogEventBegin(DMPLEX_PartStratSF, dm, 0, 0, 0));
905 
906   /* Before building the migration SF we need to know the new stratum offsets */
907   PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, NULL, &iremote));
908   PetscCall(PetscMalloc2(nroots, &pointDepths, nleaves, &remoteDepths));
909   for (d = 0; d < depth + 1; ++d) {
910     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
911     for (p = pStart; p < pEnd; ++p) {
912       DMPolytopeType ct;
913 
914       PetscCall(DMPlexGetCellType(dm, p, &ct));
915       pointDepths[p].index = d;
916       pointDepths[p].rank  = ct;
917     }
918   }
919   for (p = 0; p < nleaves; ++p) {
920     remoteDepths[p].index = -1;
921     remoteDepths[p].rank  = -1;
922   }
923   PetscCall(PetscSFBcastBegin(sf, MPIU_SF_NODE, pointDepths, remoteDepths, MPI_REPLACE));
924   PetscCall(PetscSFBcastEnd(sf, MPIU_SF_NODE, pointDepths, remoteDepths, MPI_REPLACE));
925   /* Count received points in each stratum and compute the internal strata shift */
926   PetscCall(PetscCalloc6(depth + 1, &depthRecv, depth + 1, &depthShift, depth + 1, &depthIdx, DM_NUM_POLYTOPES, &ctRecv, DM_NUM_POLYTOPES, &ctShift, DM_NUM_POLYTOPES, &ctIdx));
927   for (p = 0; p < nleaves; ++p) {
928     if (remoteDepths[p].rank < 0) {
929       ++depthRecv[remoteDepths[p].index];
930     } else {
931       ++ctRecv[remoteDepths[p].rank];
932     }
933   }
934   {
935     PetscInt depths[4], dims[4], shift = 0, i, c;
936 
937     /* Cells (depth), Vertices (0), Faces (depth-1), Edges (1)
938          Consider DM_POLYTOPE_FV_GHOST, DM_POLYTOPE_INTERIOR_GHOST and DM_POLYTOPE_UNKNOWN_CELL as cells
939      */
940     depths[0] = depth;
941     depths[1] = 0;
942     depths[2] = depth - 1;
943     depths[3] = 1;
944     dims[0]   = dim;
945     dims[1]   = 0;
946     dims[2]   = dim - 1;
947     dims[3]   = 1;
948     for (i = 0; i <= depth; ++i) {
949       const PetscInt dep = depths[i];
950       const PetscInt dim = dims[i];
951 
952       for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
953         if (DMPolytopeTypeGetDim((DMPolytopeType)c) != dim && !(i == 0 && (c == DM_POLYTOPE_FV_GHOST || c == DM_POLYTOPE_INTERIOR_GHOST || c == DM_POLYTOPE_UNKNOWN_CELL))) continue;
954         ctShift[c] = shift;
955         shift += ctRecv[c];
956       }
957       depthShift[dep] = shift;
958       shift += depthRecv[dep];
959     }
960     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
961       const PetscInt ctDim = DMPolytopeTypeGetDim((DMPolytopeType)c);
962 
963       if ((ctDim < 0 || ctDim > dim) && c != DM_POLYTOPE_FV_GHOST && c != DM_POLYTOPE_INTERIOR_GHOST && c != DM_POLYTOPE_UNKNOWN_CELL) {
964         ctShift[c] = shift;
965         shift += ctRecv[c];
966       }
967     }
968   }
969   /* Derive a new local permutation based on stratified indices */
970   PetscCall(PetscMalloc1(nleaves, &ilocal));
971   for (p = 0; p < nleaves; ++p) {
972     const DMPolytopeType ct = (DMPolytopeType)remoteDepths[p].rank;
973 
974     ilocal[p] = ctShift[ct] + ctIdx[ct];
975     ++ctIdx[ct];
976   }
977   PetscCall(PetscSFCreate(comm, migrationSF));
978   PetscCall(PetscObjectSetName((PetscObject)*migrationSF, "Migration SF"));
979   PetscCall(PetscSFSetGraph(*migrationSF, nroots, nleaves, ilocal, PETSC_OWN_POINTER, (PetscSFNode *)iremote, PETSC_COPY_VALUES));
980   PetscCall(PetscFree2(pointDepths, remoteDepths));
981   PetscCall(PetscFree6(depthRecv, depthShift, depthIdx, ctRecv, ctShift, ctIdx));
982   PetscCall(PetscLogEventEnd(DMPLEX_PartStratSF, dm, 0, 0, 0));
983   PetscFunctionReturn(PETSC_SUCCESS);
984 }
985 
986 /*@
987   DMPlexDistributeField - Distribute field data to match a given `PetscSF`, usually the `PetscSF` from mesh distribution
988 
989   Collective
990 
991   Input Parameters:
992 + dm              - The `DMPLEX` object
993 . pointSF         - The `PetscSF` describing the communication pattern
994 . originalSection - The `PetscSection` for existing data layout
995 - originalVec     - The existing data in a local vector
996 
997   Output Parameters:
998 + newSection - The `PetscSF` describing the new data layout
999 - newVec     - The new data in a local vector
1000 
1001   Level: developer
1002 
1003 .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexDistributeFieldIS()`, `DMPlexDistributeData()`
1004 @*/
1005 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
1006 {
1007   PetscSF      fieldSF;
1008   PetscInt    *remoteOffsets, fieldSize;
1009   PetscScalar *originalValues, *newValues;
1010 
1011   PetscFunctionBegin;
1012   PetscCall(PetscLogEventBegin(DMPLEX_DistributeField, dm, 0, 0, 0));
1013   PetscCall(PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection));
1014 
1015   PetscCall(PetscSectionGetStorageSize(newSection, &fieldSize));
1016   PetscCall(VecSetSizes(newVec, fieldSize, PETSC_DETERMINE));
1017   PetscCall(VecSetType(newVec, dm->vectype));
1018 
1019   PetscCall(VecGetArray(originalVec, &originalValues));
1020   PetscCall(VecGetArray(newVec, &newValues));
1021   PetscCall(PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF));
1022   PetscCall(PetscFree(remoteOffsets));
1023   PetscCall(PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues, MPI_REPLACE));
1024   PetscCall(PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues, MPI_REPLACE));
1025   PetscCall(PetscSFDestroy(&fieldSF));
1026   PetscCall(VecRestoreArray(newVec, &newValues));
1027   PetscCall(VecRestoreArray(originalVec, &originalValues));
1028   PetscCall(PetscLogEventEnd(DMPLEX_DistributeField, dm, 0, 0, 0));
1029   PetscFunctionReturn(PETSC_SUCCESS);
1030 }
1031 
1032 /*@
1033   DMPlexDistributeFieldIS - Distribute field data to match a given `PetscSF`, usually the `PetscSF` from mesh distribution
1034 
1035   Collective
1036 
1037   Input Parameters:
1038 + dm              - The `DMPLEX` object
1039 . pointSF         - The `PetscSF` describing the communication pattern
1040 . originalSection - The `PetscSection` for existing data layout
1041 - originalIS      - The existing data
1042 
1043   Output Parameters:
1044 + newSection - The `PetscSF` describing the new data layout
1045 - newIS      - The new data
1046 
1047   Level: developer
1048 
1049 .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexDistributeData()`
1050 @*/
1051 PetscErrorCode DMPlexDistributeFieldIS(DM dm, PetscSF pointSF, PetscSection originalSection, IS originalIS, PetscSection newSection, IS *newIS)
1052 {
1053   PetscSF         fieldSF;
1054   PetscInt       *newValues, *remoteOffsets, fieldSize;
1055   const PetscInt *originalValues;
1056 
1057   PetscFunctionBegin;
1058   PetscCall(PetscLogEventBegin(DMPLEX_DistributeField, dm, 0, 0, 0));
1059   PetscCall(PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection));
1060 
1061   PetscCall(PetscSectionGetStorageSize(newSection, &fieldSize));
1062   PetscCall(PetscMalloc1(fieldSize, &newValues));
1063 
1064   PetscCall(ISGetIndices(originalIS, &originalValues));
1065   PetscCall(PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF));
1066   PetscCall(PetscFree(remoteOffsets));
1067   PetscCall(PetscSFBcastBegin(fieldSF, MPIU_INT, (PetscInt *)originalValues, newValues, MPI_REPLACE));
1068   PetscCall(PetscSFBcastEnd(fieldSF, MPIU_INT, (PetscInt *)originalValues, newValues, MPI_REPLACE));
1069   PetscCall(PetscSFDestroy(&fieldSF));
1070   PetscCall(ISRestoreIndices(originalIS, &originalValues));
1071   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pointSF), fieldSize, newValues, PETSC_OWN_POINTER, newIS));
1072   PetscCall(PetscLogEventEnd(DMPLEX_DistributeField, dm, 0, 0, 0));
1073   PetscFunctionReturn(PETSC_SUCCESS);
1074 }
1075 
1076 /*@
1077   DMPlexDistributeData - Distribute field data to match a given `PetscSF`, usually the `PetscSF` from mesh distribution
1078 
1079   Collective
1080 
1081   Input Parameters:
1082 + dm              - The `DMPLEX` object
1083 . pointSF         - The `PetscSF` describing the communication pattern
1084 . originalSection - The `PetscSection` for existing data layout
1085 . datatype        - The type of data
1086 - originalData    - The existing data
1087 
1088   Output Parameters:
1089 + newSection - The `PetscSection` describing the new data layout
1090 - newData    - The new data
1091 
1092   Level: developer
1093 
1094 .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexDistributeField()`
1095 @*/
1096 PetscErrorCode DMPlexDistributeData(DM dm, PetscSF pointSF, PetscSection originalSection, MPI_Datatype datatype, void *originalData, PetscSection newSection, void **newData)
1097 {
1098   PetscSF     fieldSF;
1099   PetscInt   *remoteOffsets, fieldSize;
1100   PetscMPIInt dataSize;
1101 
1102   PetscFunctionBegin;
1103   PetscCall(PetscLogEventBegin(DMPLEX_DistributeData, dm, 0, 0, 0));
1104   PetscCall(PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection));
1105 
1106   PetscCall(PetscSectionGetStorageSize(newSection, &fieldSize));
1107   PetscCallMPI(MPI_Type_size(datatype, &dataSize));
1108   PetscCall(PetscMalloc(fieldSize * dataSize, newData));
1109 
1110   PetscCall(PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF));
1111   PetscCall(PetscFree(remoteOffsets));
1112   PetscCall(PetscSFBcastBegin(fieldSF, datatype, originalData, *newData, MPI_REPLACE));
1113   PetscCall(PetscSFBcastEnd(fieldSF, datatype, originalData, *newData, MPI_REPLACE));
1114   PetscCall(PetscSFDestroy(&fieldSF));
1115   PetscCall(PetscLogEventEnd(DMPLEX_DistributeData, dm, 0, 0, 0));
1116   PetscFunctionReturn(PETSC_SUCCESS);
1117 }
1118 
1119 static PetscErrorCode DMPlexDistributeCones(DM dm, PetscSF migrationSF, ISLocalToGlobalMapping original, ISLocalToGlobalMapping renumbering, DM dmParallel)
1120 {
1121   DM_Plex     *pmesh = (DM_Plex *)dmParallel->data;
1122   MPI_Comm     comm;
1123   PetscSF      coneSF;
1124   PetscSection originalConeSection, newConeSection;
1125   PetscInt    *remoteOffsets, *cones, *globCones, *newCones, newConesSize;
1126   PetscBool    flg;
1127 
1128   PetscFunctionBegin;
1129   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1130   PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 5);
1131   PetscCall(PetscLogEventBegin(DMPLEX_DistributeCones, dm, 0, 0, 0));
1132   /* Distribute cone section */
1133   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1134   PetscCall(DMPlexGetConeSection(dm, &originalConeSection));
1135   PetscCall(DMPlexGetConeSection(dmParallel, &newConeSection));
1136   PetscCall(PetscSFDistributeSection(migrationSF, originalConeSection, &remoteOffsets, newConeSection));
1137   PetscCall(DMSetUp(dmParallel));
1138   /* Communicate and renumber cones */
1139   PetscCall(PetscSFCreateSectionSF(migrationSF, originalConeSection, remoteOffsets, newConeSection, &coneSF));
1140   PetscCall(PetscFree(remoteOffsets));
1141   PetscCall(DMPlexGetCones(dm, &cones));
1142   if (original) {
1143     PetscInt numCones;
1144 
1145     PetscCall(PetscSectionGetStorageSize(originalConeSection, &numCones));
1146     PetscCall(PetscMalloc1(numCones, &globCones));
1147     PetscCall(ISLocalToGlobalMappingApplyBlock(original, numCones, cones, globCones));
1148   } else {
1149     globCones = cones;
1150   }
1151   PetscCall(DMPlexGetCones(dmParallel, &newCones));
1152   PetscCall(PetscSFBcastBegin(coneSF, MPIU_INT, globCones, newCones, MPI_REPLACE));
1153   PetscCall(PetscSFBcastEnd(coneSF, MPIU_INT, globCones, newCones, MPI_REPLACE));
1154   if (original) PetscCall(PetscFree(globCones));
1155   PetscCall(PetscSectionGetStorageSize(newConeSection, &newConesSize));
1156   PetscCall(ISGlobalToLocalMappingApplyBlock(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones));
1157   if (PetscDefined(USE_DEBUG)) {
1158     PetscInt  p;
1159     PetscBool valid = PETSC_TRUE;
1160     for (p = 0; p < newConesSize; ++p) {
1161       if (newCones[p] < 0) {
1162         valid = PETSC_FALSE;
1163         PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Point %" PetscInt_FMT " not in overlap SF\n", PetscGlobalRank, p));
1164       }
1165     }
1166     PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid global to local map");
1167   }
1168   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-cones_view", &flg));
1169   if (flg) {
1170     PetscCall(PetscPrintf(comm, "Serial Cone Section:\n"));
1171     PetscCall(PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_(comm)));
1172     PetscCall(PetscPrintf(comm, "Parallel Cone Section:\n"));
1173     PetscCall(PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_(comm)));
1174     PetscCall(PetscSFView(coneSF, NULL));
1175   }
1176   PetscCall(DMPlexGetConeOrientations(dm, &cones));
1177   PetscCall(DMPlexGetConeOrientations(dmParallel, &newCones));
1178   PetscCall(PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones, MPI_REPLACE));
1179   PetscCall(PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones, MPI_REPLACE));
1180   PetscCall(PetscSFDestroy(&coneSF));
1181   PetscCall(PetscLogEventEnd(DMPLEX_DistributeCones, dm, 0, 0, 0));
1182   /* Create supports and stratify DMPlex */
1183   {
1184     PetscInt pStart, pEnd;
1185 
1186     PetscCall(PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd));
1187     PetscCall(PetscSectionSetChart(pmesh->supportSection, pStart, pEnd));
1188   }
1189   PetscCall(DMPlexSymmetrize(dmParallel));
1190   PetscCall(DMPlexStratify(dmParallel));
1191   {
1192     PetscBool useCone, useClosure, useAnchors;
1193 
1194     PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
1195     PetscCall(DMSetBasicAdjacency(dmParallel, useCone, useClosure));
1196     PetscCall(DMPlexGetAdjacencyUseAnchors(dm, &useAnchors));
1197     PetscCall(DMPlexSetAdjacencyUseAnchors(dmParallel, useAnchors));
1198   }
1199   PetscFunctionReturn(PETSC_SUCCESS);
1200 }
1201 
1202 static PetscErrorCode DMPlexDistributeCoordinates(DM dm, PetscSF migrationSF, DM dmParallel)
1203 {
1204   MPI_Comm         comm;
1205   DM               cdm, cdmParallel;
1206   PetscSection     originalCoordSection, newCoordSection;
1207   Vec              originalCoordinates, newCoordinates;
1208   PetscInt         bs;
1209   const char      *name;
1210   const PetscReal *maxCell, *Lstart, *L;
1211 
1212   PetscFunctionBegin;
1213   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1214   PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 3);
1215 
1216   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1217   PetscCall(DMGetCoordinateDM(dm, &cdm));
1218   PetscCall(DMGetCoordinateDM(dmParallel, &cdmParallel));
1219   PetscCall(DMCopyDisc(cdm, cdmParallel));
1220   PetscCall(DMGetCoordinateSection(dm, &originalCoordSection));
1221   PetscCall(DMGetCoordinateSection(dmParallel, &newCoordSection));
1222   PetscCall(DMGetCoordinatesLocal(dm, &originalCoordinates));
1223   if (originalCoordinates) {
1224     PetscCall(VecCreate(PETSC_COMM_SELF, &newCoordinates));
1225     PetscCall(PetscObjectGetName((PetscObject)originalCoordinates, &name));
1226     PetscCall(PetscObjectSetName((PetscObject)newCoordinates, name));
1227 
1228     PetscCall(DMPlexDistributeField(dm, migrationSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates));
1229     PetscCall(DMSetCoordinatesLocal(dmParallel, newCoordinates));
1230     PetscCall(VecGetBlockSize(originalCoordinates, &bs));
1231     PetscCall(VecSetBlockSize(newCoordinates, bs));
1232     PetscCall(VecDestroy(&newCoordinates));
1233   }
1234 
1235   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1236   PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
1237   PetscCall(DMSetPeriodicity(dmParallel, maxCell, Lstart, L));
1238   PetscCall(DMGetCellCoordinateDM(dm, &cdm));
1239   if (cdm) {
1240     PetscCall(DMClone(dmParallel, &cdmParallel));
1241     PetscCall(DMSetCellCoordinateDM(dmParallel, cdmParallel));
1242     PetscCall(DMCopyDisc(cdm, cdmParallel));
1243     PetscCall(DMDestroy(&cdmParallel));
1244     PetscCall(DMGetCellCoordinateSection(dm, &originalCoordSection));
1245     PetscCall(DMGetCellCoordinatesLocal(dm, &originalCoordinates));
1246     PetscCall(PetscSectionCreate(comm, &newCoordSection));
1247     if (originalCoordinates) {
1248       PetscCall(VecCreate(PETSC_COMM_SELF, &newCoordinates));
1249       PetscCall(PetscObjectGetName((PetscObject)originalCoordinates, &name));
1250       PetscCall(PetscObjectSetName((PetscObject)newCoordinates, name));
1251 
1252       PetscCall(DMPlexDistributeField(dm, migrationSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates));
1253       PetscCall(VecGetBlockSize(originalCoordinates, &bs));
1254       PetscCall(VecSetBlockSize(newCoordinates, bs));
1255       PetscCall(DMSetCellCoordinateSection(dmParallel, bs, newCoordSection));
1256       PetscCall(DMSetCellCoordinatesLocal(dmParallel, newCoordinates));
1257       PetscCall(VecDestroy(&newCoordinates));
1258     }
1259     PetscCall(PetscSectionDestroy(&newCoordSection));
1260   }
1261   PetscFunctionReturn(PETSC_SUCCESS);
1262 }
1263 
1264 static PetscErrorCode DMPlexDistributeLabels(DM dm, PetscSF migrationSF, DM dmParallel)
1265 {
1266   DM_Plex         *mesh = (DM_Plex *)dm->data;
1267   MPI_Comm         comm;
1268   DMLabel          depthLabel;
1269   PetscMPIInt      rank;
1270   PetscInt         depth, d, numLabels, numLocalLabels, l;
1271   PetscBool        hasLabels  = PETSC_FALSE, lsendDepth, sendDepth;
1272   PetscObjectState depthState = -1;
1273 
1274   PetscFunctionBegin;
1275   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1276   PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 3);
1277 
1278   PetscCall(PetscLogEventBegin(DMPLEX_DistributeLabels, dm, 0, 0, 0));
1279   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1280   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1281 
1282   /* If the user has changed the depth label, communicate it instead */
1283   PetscCall(DMPlexGetDepth(dm, &depth));
1284   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
1285   if (depthLabel) PetscCall(PetscObjectStateGet((PetscObject)depthLabel, &depthState));
1286   lsendDepth = mesh->depthState != depthState ? PETSC_TRUE : PETSC_FALSE;
1287   PetscCallMPI(MPIU_Allreduce(&lsendDepth, &sendDepth, 1, MPI_C_BOOL, MPI_LOR, comm));
1288   if (sendDepth) {
1289     PetscCall(DMPlexGetDepthLabel(dmParallel, &dmParallel->depthLabel));
1290     PetscCall(DMRemoveLabelBySelf(dmParallel, &dmParallel->depthLabel, PETSC_FALSE));
1291   }
1292   /* Everyone must have either the same number of labels, or none */
1293   PetscCall(DMGetNumLabels(dm, &numLocalLabels));
1294   numLabels = numLocalLabels;
1295   PetscCallMPI(MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm));
1296   if (numLabels == numLocalLabels) hasLabels = PETSC_TRUE;
1297   for (l = 0; l < numLabels; ++l) {
1298     DMLabel     label = NULL, labelNew = NULL;
1299     PetscBool   isDepth, lisOutput     = PETSC_TRUE, isOutput;
1300     const char *name = NULL;
1301 
1302     if (hasLabels) {
1303       PetscCall(DMGetLabelByNum(dm, l, &label));
1304       /* Skip "depth" because it is recreated */
1305       PetscCall(PetscObjectGetName((PetscObject)label, &name));
1306       PetscCall(PetscStrcmp(name, "depth", &isDepth));
1307     } else {
1308       isDepth = PETSC_FALSE;
1309     }
1310     PetscCallMPI(MPI_Bcast(&isDepth, 1, MPI_C_BOOL, 0, comm));
1311     if (isDepth && !sendDepth) continue;
1312     PetscCall(DMLabelDistribute(label, migrationSF, &labelNew));
1313     if (isDepth) {
1314       /* Put in any missing strata which can occur if users are managing the depth label themselves */
1315       PetscInt gdepth;
1316 
1317       PetscCallMPI(MPIU_Allreduce(&depth, &gdepth, 1, MPIU_INT, MPI_MAX, comm));
1318       PetscCheck(!(depth >= 0) || !(gdepth != depth), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %" PetscInt_FMT " != %" PetscInt_FMT, depth, gdepth);
1319       for (d = 0; d <= gdepth; ++d) {
1320         PetscBool has;
1321 
1322         PetscCall(DMLabelHasStratum(labelNew, d, &has));
1323         if (!has) PetscCall(DMLabelAddStratum(labelNew, d));
1324       }
1325     }
1326     PetscCall(DMAddLabel(dmParallel, labelNew));
1327     /* Put the output flag in the new label */
1328     if (hasLabels) PetscCall(DMGetLabelOutput(dm, name, &lisOutput));
1329     PetscCallMPI(MPIU_Allreduce(&lisOutput, &isOutput, 1, MPI_C_BOOL, MPI_LAND, comm));
1330     PetscCall(PetscObjectGetName((PetscObject)labelNew, &name));
1331     PetscCall(DMSetLabelOutput(dmParallel, name, isOutput));
1332     PetscCall(DMLabelDestroy(&labelNew));
1333   }
1334   {
1335     DMLabel ctLabel;
1336 
1337     // Reset label for fast lookup
1338     PetscCall(DMPlexGetCellTypeLabel(dmParallel, &ctLabel));
1339     PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
1340   }
1341   PetscCall(PetscLogEventEnd(DMPLEX_DistributeLabels, dm, 0, 0, 0));
1342   PetscFunctionReturn(PETSC_SUCCESS);
1343 }
1344 
1345 static PetscErrorCode DMPlexDistributeSetupTree(DM dm, PetscSF migrationSF, ISLocalToGlobalMapping original, ISLocalToGlobalMapping renumbering, DM dmParallel)
1346 {
1347   DM_Plex     *mesh  = (DM_Plex *)dm->data;
1348   DM_Plex     *pmesh = (DM_Plex *)dmParallel->data;
1349   MPI_Comm     comm;
1350   DM           refTree;
1351   PetscSection origParentSection, newParentSection;
1352   PetscInt    *origParents, *origChildIDs;
1353   PetscBool    flg;
1354 
1355   PetscFunctionBegin;
1356   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1357   PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 5);
1358   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1359 
1360   /* Set up tree */
1361   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
1362   PetscCall(DMPlexSetReferenceTree(dmParallel, refTree));
1363   PetscCall(DMPlexGetTree(dm, &origParentSection, &origParents, &origChildIDs, NULL, NULL));
1364   if (origParentSection) {
1365     PetscInt  pStart, pEnd;
1366     PetscInt *newParents, *newChildIDs, *globParents;
1367     PetscInt *remoteOffsetsParents, newParentSize;
1368     PetscSF   parentSF;
1369 
1370     PetscCall(DMPlexGetChart(dmParallel, &pStart, &pEnd));
1371     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmParallel), &newParentSection));
1372     PetscCall(PetscSectionSetChart(newParentSection, pStart, pEnd));
1373     PetscCall(PetscSFDistributeSection(migrationSF, origParentSection, &remoteOffsetsParents, newParentSection));
1374     PetscCall(PetscSFCreateSectionSF(migrationSF, origParentSection, remoteOffsetsParents, newParentSection, &parentSF));
1375     PetscCall(PetscFree(remoteOffsetsParents));
1376     PetscCall(PetscSectionGetStorageSize(newParentSection, &newParentSize));
1377     PetscCall(PetscMalloc2(newParentSize, &newParents, newParentSize, &newChildIDs));
1378     if (original) {
1379       PetscInt numParents;
1380 
1381       PetscCall(PetscSectionGetStorageSize(origParentSection, &numParents));
1382       PetscCall(PetscMalloc1(numParents, &globParents));
1383       PetscCall(ISLocalToGlobalMappingApplyBlock(original, numParents, origParents, globParents));
1384     } else {
1385       globParents = origParents;
1386     }
1387     PetscCall(PetscSFBcastBegin(parentSF, MPIU_INT, globParents, newParents, MPI_REPLACE));
1388     PetscCall(PetscSFBcastEnd(parentSF, MPIU_INT, globParents, newParents, MPI_REPLACE));
1389     if (original) PetscCall(PetscFree(globParents));
1390     PetscCall(PetscSFBcastBegin(parentSF, MPIU_INT, origChildIDs, newChildIDs, MPI_REPLACE));
1391     PetscCall(PetscSFBcastEnd(parentSF, MPIU_INT, origChildIDs, newChildIDs, MPI_REPLACE));
1392     PetscCall(ISGlobalToLocalMappingApplyBlock(renumbering, IS_GTOLM_MASK, newParentSize, newParents, NULL, newParents));
1393     if (PetscDefined(USE_DEBUG)) {
1394       PetscInt  p;
1395       PetscBool valid = PETSC_TRUE;
1396       for (p = 0; p < newParentSize; ++p) {
1397         if (newParents[p] < 0) {
1398           valid = PETSC_FALSE;
1399           PetscCall(PetscPrintf(PETSC_COMM_SELF, "Point %" PetscInt_FMT " not in overlap SF\n", p));
1400         }
1401       }
1402       PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid global to local map");
1403     }
1404     PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-parents_view", &flg));
1405     if (flg) {
1406       PetscCall(PetscPrintf(comm, "Serial Parent Section: \n"));
1407       PetscCall(PetscSectionView(origParentSection, PETSC_VIEWER_STDOUT_(comm)));
1408       PetscCall(PetscPrintf(comm, "Parallel Parent Section: \n"));
1409       PetscCall(PetscSectionView(newParentSection, PETSC_VIEWER_STDOUT_(comm)));
1410       PetscCall(PetscSFView(parentSF, NULL));
1411     }
1412     PetscCall(DMPlexSetTree(dmParallel, newParentSection, newParents, newChildIDs));
1413     PetscCall(PetscSectionDestroy(&newParentSection));
1414     PetscCall(PetscFree2(newParents, newChildIDs));
1415     PetscCall(PetscSFDestroy(&parentSF));
1416   }
1417   pmesh->useAnchors = mesh->useAnchors;
1418   PetscFunctionReturn(PETSC_SUCCESS);
1419 }
1420 
1421 /*@
1422   DMPlexSetPartitionBalance - Should distribution of the `DM` attempt to balance the shared point partition?
1423 
1424   Input Parameters:
1425 + dm  - The `DMPLEX` object
1426 - flg - Balance the partition?
1427 
1428   Level: intermediate
1429 
1430 .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexGetPartitionBalance()`
1431 @*/
1432 PetscErrorCode DMPlexSetPartitionBalance(DM dm, PetscBool flg)
1433 {
1434   DM_Plex *mesh = (DM_Plex *)dm->data;
1435 
1436   PetscFunctionBegin;
1437   mesh->partitionBalance = flg;
1438   PetscFunctionReturn(PETSC_SUCCESS);
1439 }
1440 
1441 /*@
1442   DMPlexGetPartitionBalance - Does distribution of the `DM` attempt to balance the shared point partition?
1443 
1444   Input Parameter:
1445 . dm - The `DMPLEX` object
1446 
1447   Output Parameter:
1448 . flg - Balance the partition?
1449 
1450   Level: intermediate
1451 
1452 .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexSetPartitionBalance()`
1453 @*/
1454 PetscErrorCode DMPlexGetPartitionBalance(DM dm, PetscBool *flg)
1455 {
1456   DM_Plex *mesh = (DM_Plex *)dm->data;
1457 
1458   PetscFunctionBegin;
1459   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1460   PetscAssertPointer(flg, 2);
1461   *flg = mesh->partitionBalance;
1462   PetscFunctionReturn(PETSC_SUCCESS);
1463 }
1464 
1465 typedef struct {
1466   PetscInt vote, rank, index;
1467 } Petsc3Int;
1468 
1469 /* MaxLoc, but carry a third piece of information around */
1470 static void MPIAPI MaxLocCarry(void *in_, void *inout_, PetscMPIInt *len_, MPI_Datatype *dtype)
1471 {
1472   Petsc3Int *a = (Petsc3Int *)inout_;
1473   Petsc3Int *b = (Petsc3Int *)in_;
1474   PetscInt   i, len = *len_;
1475   for (i = 0; i < len; i++) {
1476     if (a[i].vote < b[i].vote) {
1477       a[i].vote  = b[i].vote;
1478       a[i].rank  = b[i].rank;
1479       a[i].index = b[i].index;
1480     } else if (a[i].vote <= b[i].vote) {
1481       if (a[i].rank >= b[i].rank) {
1482         a[i].rank  = b[i].rank;
1483         a[i].index = b[i].index;
1484       }
1485     }
1486   }
1487 }
1488 
1489 /*@
1490   DMPlexCreatePointSF - Build a point `PetscSF` from an `PetscSF` describing a point migration
1491 
1492   Input Parameters:
1493 + dm          - The source `DMPLEX` object
1494 . migrationSF - The star forest that describes the parallel point remapping
1495 - ownership   - Flag causing a vote to determine point ownership
1496 
1497   Output Parameter:
1498 . pointSF - The star forest describing the point overlap in the remapped `DM`
1499 
1500   Level: developer
1501 
1502   Note:
1503   Output `pointSF` is guaranteed to have the array of local indices (leaves) sorted.
1504 
1505 .seealso: `DMPLEX`, `PetscSF`, `DM`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()`
1506 @*/
1507 PetscErrorCode DMPlexCreatePointSF(DM dm, PetscSF migrationSF, PetscBool ownership, PetscSF *pointSF)
1508 {
1509   PetscMPIInt        rank, size;
1510   PetscInt           p, nroots, nleaves, idx, npointLeaves;
1511   PetscInt          *pointLocal;
1512   const PetscInt    *leaves;
1513   const PetscSFNode *roots;
1514   PetscSFNode       *rootNodes, *leafNodes, *pointRemote;
1515   Vec                shifts;
1516   const PetscInt     numShifts  = 13759;
1517   const PetscScalar *shift      = NULL;
1518   const PetscBool    shiftDebug = PETSC_FALSE;
1519   PetscBool          balance;
1520 
1521   PetscFunctionBegin;
1522   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1523   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1524   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
1525   PetscCall(PetscLogEventBegin(DMPLEX_CreatePointSF, dm, 0, 0, 0));
1526   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), pointSF));
1527   PetscCall(PetscSFSetFromOptions(*pointSF));
1528   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
1529 
1530   PetscCall(DMPlexGetPartitionBalance(dm, &balance));
1531   PetscCall(PetscSFGetGraph(migrationSF, &nroots, &nleaves, &leaves, &roots));
1532   PetscCall(PetscMalloc2(nroots, &rootNodes, nleaves, &leafNodes));
1533   if (ownership) {
1534     MPI_Op       op;
1535     MPI_Datatype datatype;
1536     Petsc3Int   *rootVote = NULL, *leafVote = NULL;
1537 
1538     /* If balancing, we compute a random cyclic shift of the rank for each remote point. That way, the max will evenly distribute among ranks. */
1539     if (balance) {
1540       PetscRandom r;
1541 
1542       PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &r));
1543       PetscCall(PetscRandomSetInterval(r, 0, 2467 * size));
1544       PetscCall(VecCreate(PETSC_COMM_SELF, &shifts));
1545       PetscCall(VecSetSizes(shifts, numShifts, numShifts));
1546       PetscCall(VecSetType(shifts, VECSTANDARD));
1547       PetscCall(VecSetRandom(shifts, r));
1548       PetscCall(PetscRandomDestroy(&r));
1549       PetscCall(VecGetArrayRead(shifts, &shift));
1550     }
1551 
1552     PetscCall(PetscMalloc1(nroots, &rootVote));
1553     PetscCall(PetscMalloc1(nleaves, &leafVote));
1554     /* Point ownership vote: Process with highest rank owns shared points */
1555     for (p = 0; p < nleaves; ++p) {
1556       if (shiftDebug) {
1557         PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject)dm), "[%d] Point %" PetscInt_FMT " RemotePoint %" PetscInt_FMT " Shift %" PetscInt_FMT " MyRank %" PetscInt_FMT "\n", rank, leaves ? leaves[p] : p, roots[p].index,
1558                                           (PetscInt)PetscRealPart(shift[roots[p].index % numShifts]), (rank + (shift ? (PetscInt)PetscRealPart(shift[roots[p].index % numShifts]) : 0)) % size));
1559       }
1560       /* Either put in a bid or we know we own it */
1561       leafVote[p].vote  = (rank + (shift ? (PetscInt)PetscRealPart(shift[roots[p].index % numShifts]) : 0)) % size;
1562       leafVote[p].rank  = rank;
1563       leafVote[p].index = p;
1564     }
1565     for (p = 0; p < nroots; p++) {
1566       /* Root must not participate in the reduction, flag so that MAXLOC does not use */
1567       rootVote[p].vote  = -3;
1568       rootVote[p].rank  = -3;
1569       rootVote[p].index = -3;
1570     }
1571     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &datatype));
1572     PetscCallMPI(MPI_Type_commit(&datatype));
1573     PetscCallMPI(MPI_Op_create(&MaxLocCarry, 1, &op));
1574     PetscCall(PetscSFReduceBegin(migrationSF, datatype, leafVote, rootVote, op));
1575     PetscCall(PetscSFReduceEnd(migrationSF, datatype, leafVote, rootVote, op));
1576     PetscCallMPI(MPI_Op_free(&op));
1577     PetscCallMPI(MPI_Type_free(&datatype));
1578     for (p = 0; p < nroots; p++) {
1579       rootNodes[p].rank  = rootVote[p].rank;
1580       rootNodes[p].index = rootVote[p].index;
1581     }
1582     PetscCall(PetscFree(leafVote));
1583     PetscCall(PetscFree(rootVote));
1584   } else {
1585     for (p = 0; p < nroots; p++) {
1586       rootNodes[p].index = -1;
1587       rootNodes[p].rank  = rank;
1588     }
1589     for (p = 0; p < nleaves; p++) {
1590       /* Write new local id into old location */
1591       if (roots[p].rank == rank) rootNodes[roots[p].index].index = leaves ? leaves[p] : p;
1592     }
1593   }
1594   PetscCall(PetscSFBcastBegin(migrationSF, MPIU_SF_NODE, rootNodes, leafNodes, MPI_REPLACE));
1595   PetscCall(PetscSFBcastEnd(migrationSF, MPIU_SF_NODE, rootNodes, leafNodes, MPI_REPLACE));
1596 
1597   for (npointLeaves = 0, p = 0; p < nleaves; p++) {
1598     if (leafNodes[p].rank != rank) npointLeaves++;
1599   }
1600   PetscCall(PetscMalloc1(npointLeaves, &pointLocal));
1601   PetscCall(PetscMalloc1(npointLeaves, &pointRemote));
1602   for (idx = 0, p = 0; p < nleaves; p++) {
1603     if (leafNodes[p].rank != rank) {
1604       /* Note that pointLocal is automatically sorted as it is sublist of 0, ..., nleaves-1 */
1605       pointLocal[idx]  = p;
1606       pointRemote[idx] = leafNodes[p];
1607       idx++;
1608     }
1609   }
1610   if (shift) {
1611     PetscCall(VecRestoreArrayRead(shifts, &shift));
1612     PetscCall(VecDestroy(&shifts));
1613   }
1614   if (shiftDebug) PetscCall(PetscSynchronizedFlush(PetscObjectComm((PetscObject)dm), PETSC_STDOUT));
1615   PetscCall(PetscSFSetGraph(*pointSF, nleaves, npointLeaves, pointLocal, PETSC_OWN_POINTER, pointRemote, PETSC_OWN_POINTER));
1616   PetscCall(PetscFree2(rootNodes, leafNodes));
1617   PetscCall(PetscLogEventEnd(DMPLEX_CreatePointSF, dm, 0, 0, 0));
1618   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, *pointSF, PETSC_FALSE));
1619   PetscFunctionReturn(PETSC_SUCCESS);
1620 }
1621 
1622 /*@
1623   DMPlexMigrate  - Migrates internal `DM` data over the supplied star forest
1624 
1625   Collective
1626 
1627   Input Parameters:
1628 + dm - The source `DMPLEX` object
1629 - sf - The star forest communication context describing the migration pattern
1630 
1631   Output Parameter:
1632 . targetDM - The target `DMPLEX` object
1633 
1634   Level: intermediate
1635 
1636 .seealso: `DMPLEX`, `PetscSF`, `DM`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()`
1637 @*/
1638 PetscErrorCode DMPlexMigrate(DM dm, PetscSF sf, DM targetDM)
1639 {
1640   MPI_Comm               comm;
1641   PetscInt               dim, cdim, nroots;
1642   PetscSF                sfPoint;
1643   ISLocalToGlobalMapping ltogMigration;
1644   ISLocalToGlobalMapping ltogOriginal = NULL;
1645 
1646   PetscFunctionBegin;
1647   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1648   PetscCall(PetscLogEventBegin(DMPLEX_Migrate, dm, 0, 0, 0));
1649   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1650   PetscCall(DMGetDimension(dm, &dim));
1651   PetscCall(DMSetDimension(targetDM, dim));
1652   PetscCall(DMGetCoordinateDim(dm, &cdim));
1653   PetscCall(DMSetCoordinateDim(targetDM, cdim));
1654 
1655   /* Check for a one-to-all distribution pattern */
1656   PetscCall(DMGetPointSF(dm, &sfPoint));
1657   PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL));
1658   if (nroots >= 0) {
1659     IS        isOriginal;
1660     PetscInt  n, size, nleaves;
1661     PetscInt *numbering_orig, *numbering_new;
1662 
1663     /* Get the original point numbering */
1664     PetscCall(DMPlexCreatePointNumbering(dm, &isOriginal));
1665     PetscCall(ISLocalToGlobalMappingCreateIS(isOriginal, &ltogOriginal));
1666     PetscCall(ISLocalToGlobalMappingGetSize(ltogOriginal, &size));
1667     PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltogOriginal, (const PetscInt **)&numbering_orig));
1668     /* Convert to positive global numbers */
1669     for (n = 0; n < size; n++) {
1670       if (numbering_orig[n] < 0) numbering_orig[n] = -(numbering_orig[n] + 1);
1671     }
1672     /* Derive the new local-to-global mapping from the old one */
1673     PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, NULL, NULL));
1674     PetscCall(PetscMalloc1(nleaves, &numbering_new));
1675     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, numbering_orig, numbering_new, MPI_REPLACE));
1676     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, numbering_orig, numbering_new, MPI_REPLACE));
1677     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, nleaves, numbering_new, PETSC_OWN_POINTER, &ltogMigration));
1678     PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogOriginal, (const PetscInt **)&numbering_orig));
1679     PetscCall(ISDestroy(&isOriginal));
1680   } else {
1681     /* One-to-all distribution pattern: We can derive LToG from SF */
1682     PetscCall(ISLocalToGlobalMappingCreateSF(sf, 0, &ltogMigration));
1683   }
1684   PetscCall(PetscObjectSetName((PetscObject)ltogMigration, "Point renumbering for DM migration"));
1685   PetscCall(ISLocalToGlobalMappingViewFromOptions(ltogMigration, (PetscObject)dm, "-partition_view"));
1686   /* Migrate DM data to target DM */
1687   PetscCall(DMPlexDistributeCones(dm, sf, ltogOriginal, ltogMigration, targetDM));
1688   PetscCall(DMPlexDistributeLabels(dm, sf, targetDM));
1689   PetscCall(DMPlexDistributeCoordinates(dm, sf, targetDM));
1690   PetscCall(DMPlexDistributeSetupTree(dm, sf, ltogOriginal, ltogMigration, targetDM));
1691   PetscCall(ISLocalToGlobalMappingDestroy(&ltogOriginal));
1692   PetscCall(ISLocalToGlobalMappingDestroy(&ltogMigration));
1693   PetscCall(PetscLogEventEnd(DMPLEX_Migrate, dm, 0, 0, 0));
1694   PetscFunctionReturn(PETSC_SUCCESS);
1695 }
1696 
1697 /*@
1698   DMPlexRemapMigrationSF - Rewrite the distribution SF to account for overlap
1699 
1700   Collective
1701 
1702   Input Parameters:
1703 + sfOverlap   - The `PetscSF` object just for the overlap
1704 - sfMigration - The original distribution `PetscSF` object
1705 
1706   Output Parameters:
1707 . sfMigrationNew - A rewritten `PetscSF` object that incorporates the overlap
1708 
1709   Level: developer
1710 
1711 .seealso: `DMPLEX`, `DM`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()`, `DMPlexGetOverlap()`
1712 @*/
1713 PetscErrorCode DMPlexRemapMigrationSF(PetscSF sfOverlap, PetscSF sfMigration, PetscSF *sfMigrationNew)
1714 {
1715   PetscSFNode       *newRemote, *permRemote = NULL;
1716   const PetscInt    *oldLeaves;
1717   const PetscSFNode *oldRemote;
1718   PetscInt           nroots, nleaves, noldleaves;
1719 
1720   PetscFunctionBegin;
1721   PetscCall(PetscSFGetGraph(sfMigration, &nroots, &noldleaves, &oldLeaves, &oldRemote));
1722   PetscCall(PetscSFGetGraph(sfOverlap, NULL, &nleaves, NULL, NULL));
1723   PetscCall(PetscMalloc1(nleaves, &newRemote));
1724   /* oldRemote: original root point mapping to original leaf point
1725      newRemote: original leaf point mapping to overlapped leaf point */
1726   if (oldLeaves) {
1727     /* After stratification, the migration remotes may not be in root (canonical) order, so we reorder using the leaf numbering */
1728     PetscCall(PetscMalloc1(noldleaves, &permRemote));
1729     for (PetscInt l = 0; l < noldleaves; ++l) permRemote[oldLeaves[l]] = oldRemote[l];
1730     oldRemote = permRemote;
1731   }
1732   PetscCall(PetscSFBcastBegin(sfOverlap, MPIU_SF_NODE, oldRemote, newRemote, MPI_REPLACE));
1733   PetscCall(PetscSFBcastEnd(sfOverlap, MPIU_SF_NODE, oldRemote, newRemote, MPI_REPLACE));
1734   PetscCall(PetscFree(permRemote));
1735   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfOverlap), sfMigrationNew));
1736   PetscCall(PetscSFSetGraph(*sfMigrationNew, nroots, nleaves, NULL, PETSC_OWN_POINTER, newRemote, PETSC_OWN_POINTER));
1737   PetscFunctionReturn(PETSC_SUCCESS);
1738 }
1739 
1740 /* For DG-like methods, the code below is equivalent (but faster) than calling
1741    DMPlexCreateClosureIndex(dm,section) */
1742 static PetscErrorCode DMPlexCreateClosureIndex_CELL(DM dm, PetscSection section)
1743 {
1744   PetscSection clSection;
1745   IS           clPoints;
1746   PetscInt     pStart, pEnd, point;
1747   PetscInt    *closure, pos = 0;
1748 
1749   PetscFunctionBegin;
1750   if (!section) PetscCall(DMGetLocalSection(dm, &section));
1751   PetscCall(DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd));
1752   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &clSection));
1753   PetscCall(PetscSectionSetChart(clSection, pStart, pEnd));
1754   PetscCall(PetscMalloc1((2 * (pEnd - pStart)), &closure));
1755   for (point = pStart; point < pEnd; point++) {
1756     PetscCall(PetscSectionSetDof(clSection, point, 2));
1757     closure[pos++] = point; /* point */
1758     closure[pos++] = 0;     /* orientation */
1759   }
1760   PetscCall(PetscSectionSetUp(clSection));
1761   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * (pEnd - pStart), closure, PETSC_OWN_POINTER, &clPoints));
1762   PetscCall(PetscSectionSetClosureIndex(section, (PetscObject)dm, clSection, clPoints));
1763   PetscCall(PetscSectionDestroy(&clSection));
1764   PetscCall(ISDestroy(&clPoints));
1765   PetscFunctionReturn(PETSC_SUCCESS);
1766 }
1767 
1768 static PetscErrorCode DMPlexDistribute_Multistage(DM dm, PetscInt overlap, PetscSF *sf, DM *dmParallel)
1769 {
1770   MPI_Comm         comm = PetscObjectComm((PetscObject)dm);
1771   PetscPartitioner part;
1772   PetscBool        balance, printHeader;
1773   PetscInt         nl = 0;
1774 
1775   PetscFunctionBegin;
1776   if (sf) *sf = NULL;
1777   *dmParallel = NULL;
1778 
1779   PetscCall(DMPlexGetPartitioner(dm, &part));
1780   printHeader = part->printHeader;
1781   PetscCall(DMPlexGetPartitionBalance(dm, &balance));
1782   PetscCall(PetscPartitionerSetUp(part));
1783   PetscCall(PetscLogEventBegin(DMPLEX_DistributeMultistage, dm, 0, 0, 0));
1784   PetscCall(PetscPartitionerMultistageGetStages_Multistage(part, &nl, NULL));
1785   for (PetscInt l = 0; l < nl; l++) {
1786     PetscInt ovl = (l < nl - 1) ? 0 : overlap;
1787     PetscSF  sfDist;
1788     DM       dmDist;
1789 
1790     PetscCall(DMPlexSetPartitionBalance(dm, balance));
1791     PetscCall(DMViewFromOptions(dm, (PetscObject)part, "-petscpartitioner_multistage_dm_view"));
1792     PetscCall(PetscPartitionerMultistageSetStage_Multistage(part, l, (PetscObject)dm));
1793     PetscCall(DMPlexSetPartitioner(dm, part));
1794     PetscCall(DMPlexDistribute(dm, ovl, &sfDist, &dmDist));
1795     PetscCheck(dmDist, comm, PETSC_ERR_PLIB, "No distributed DM generated (stage %" PetscInt_FMT ")", l);
1796     PetscCheck(sfDist, comm, PETSC_ERR_PLIB, "No SF generated (stage %" PetscInt_FMT ")", l);
1797     part->printHeader = PETSC_FALSE;
1798 
1799     /* Propagate cell weights to the next level (if any, and if not the final dm) */
1800     if (part->usevwgt && dm->localSection && l != nl - 1) {
1801       PetscSection oldSection, newSection;
1802 
1803       PetscCall(DMGetLocalSection(dm, &oldSection));
1804       PetscCall(DMGetLocalSection(dmDist, &newSection));
1805       PetscCall(PetscSFDistributeSection(sfDist, oldSection, NULL, newSection));
1806       PetscCall(DMPlexCreateClosureIndex_CELL(dmDist, newSection));
1807     }
1808     if (!sf) PetscCall(PetscSFDestroy(&sfDist));
1809     if (l > 0) PetscCall(DMDestroy(&dm));
1810 
1811     if (sf && *sf) {
1812       PetscSF sfA = *sf, sfB = sfDist;
1813       PetscCall(PetscSFCompose(sfA, sfB, &sfDist));
1814       PetscCall(PetscSFDestroy(&sfA));
1815       PetscCall(PetscSFDestroy(&sfB));
1816     }
1817 
1818     if (sf) *sf = sfDist;
1819     dm = *dmParallel = dmDist;
1820   }
1821   PetscCall(PetscPartitionerMultistageSetStage_Multistage(part, 0, NULL)); /* reset */
1822   PetscCall(PetscLogEventEnd(DMPLEX_DistributeMultistage, dm, 0, 0, 0));
1823   part->printHeader = printHeader;
1824   PetscFunctionReturn(PETSC_SUCCESS);
1825 }
1826 
1827 /*@
1828   DMPlexDistribute - Distributes the mesh and any associated sections.
1829 
1830   Collective
1831 
1832   Input Parameters:
1833 + dm      - The original `DMPLEX` object
1834 - overlap - The overlap of partitions, 0 is the default
1835 
1836   Output Parameters:
1837 + sf         - The `PetscSF` used for point distribution, or `NULL` if not needed
1838 - dmParallel - The distributed `DMPLEX` object
1839 
1840   Level: intermediate
1841 
1842   Note:
1843   If the mesh was not distributed, the output `dmParallel` will be `NULL`.
1844 
1845   The user can control the definition of adjacency for the mesh using `DMSetAdjacency()`. They should choose the combination appropriate for the function
1846   representation on the mesh.
1847 
1848 .seealso: `DMPLEX`, `DM`, `DMPlexCreate()`, `DMSetAdjacency()`, `DMPlexGetOverlap()`
1849 @*/
1850 PetscErrorCode DMPlexDistribute(DM dm, PetscInt overlap, PeOp PetscSF *sf, DM *dmParallel)
1851 {
1852   MPI_Comm         comm;
1853   PetscPartitioner partitioner;
1854   IS               cellPart;
1855   PetscSection     cellPartSection;
1856   DM               dmCoord;
1857   DMLabel          lblPartition, lblMigration;
1858   PetscSF          sfMigration, sfStratified, sfPoint;
1859   PetscBool        flg, balance, isms;
1860   PetscMPIInt      rank, size;
1861 
1862   PetscFunctionBegin;
1863   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1864   PetscValidLogicalCollectiveInt(dm, overlap, 2);
1865   if (sf) PetscAssertPointer(sf, 3);
1866   PetscAssertPointer(dmParallel, 4);
1867 
1868   if (sf) *sf = NULL;
1869   *dmParallel = NULL;
1870   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1871   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1872   PetscCallMPI(MPI_Comm_size(comm, &size));
1873   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
1874 
1875   /* Handle multistage partitioner */
1876   PetscCall(DMPlexGetPartitioner(dm, &partitioner));
1877   PetscCall(PetscObjectTypeCompare((PetscObject)partitioner, PETSCPARTITIONERMULTISTAGE, &isms));
1878   if (isms) {
1879     PetscObject stagedm;
1880 
1881     PetscCall(PetscPartitionerMultistageGetStage_Multistage(partitioner, NULL, &stagedm));
1882     if (!stagedm) { /* No stage dm present, start the multistage algorithm */
1883       PetscCall(DMPlexDistribute_Multistage(dm, overlap, sf, dmParallel));
1884       PetscFunctionReturn(PETSC_SUCCESS);
1885     }
1886   }
1887   PetscCall(PetscLogEventBegin(DMPLEX_Distribute, dm, 0, 0, 0));
1888   /* Create cell partition */
1889   PetscCall(PetscLogEventBegin(DMPLEX_Partition, dm, 0, 0, 0));
1890   PetscCall(PetscSectionCreate(comm, &cellPartSection));
1891   PetscCall(PetscPartitionerDMPlexPartition(partitioner, dm, NULL, cellPartSection, &cellPart));
1892   PetscCall(PetscLogEventBegin(DMPLEX_PartSelf, dm, 0, 0, 0));
1893   {
1894     /* Convert partition to DMLabel */
1895     IS              is;
1896     PetscHSetI      ht;
1897     const PetscInt *points;
1898     PetscInt       *iranks;
1899     PetscInt        pStart, pEnd, proc, npoints, poff = 0, nranks;
1900 
1901     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Point Partition", &lblPartition));
1902     /* Preallocate strata */
1903     PetscCall(PetscHSetICreate(&ht));
1904     PetscCall(PetscSectionGetChart(cellPartSection, &pStart, &pEnd));
1905     for (proc = pStart; proc < pEnd; proc++) {
1906       PetscCall(PetscSectionGetDof(cellPartSection, proc, &npoints));
1907       if (npoints) PetscCall(PetscHSetIAdd(ht, proc));
1908     }
1909     PetscCall(PetscHSetIGetSize(ht, &nranks));
1910     PetscCall(PetscMalloc1(nranks, &iranks));
1911     PetscCall(PetscHSetIGetElems(ht, &poff, iranks));
1912     PetscCall(PetscHSetIDestroy(&ht));
1913     PetscCall(DMLabelAddStrata(lblPartition, nranks, iranks));
1914     PetscCall(PetscFree(iranks));
1915     /* Inline DMPlexPartitionLabelClosure() */
1916     PetscCall(ISGetIndices(cellPart, &points));
1917     PetscCall(PetscSectionGetChart(cellPartSection, &pStart, &pEnd));
1918     for (proc = pStart; proc < pEnd; proc++) {
1919       PetscCall(PetscSectionGetDof(cellPartSection, proc, &npoints));
1920       if (!npoints) continue;
1921       PetscCall(PetscSectionGetOffset(cellPartSection, proc, &poff));
1922       PetscCall(DMPlexClosurePoints_Private(dm, npoints, points + poff, &is));
1923       PetscCall(DMLabelSetStratumIS(lblPartition, proc, is));
1924       PetscCall(ISDestroy(&is));
1925     }
1926     PetscCall(ISRestoreIndices(cellPart, &points));
1927   }
1928   PetscCall(PetscLogEventEnd(DMPLEX_PartSelf, dm, 0, 0, 0));
1929 
1930   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Point migration", &lblMigration));
1931   PetscCall(DMPlexPartitionLabelInvert(dm, lblPartition, NULL, lblMigration));
1932   PetscCall(DMPlexPartitionLabelCreateSF(dm, lblMigration, PETSC_TRUE, &sfMigration));
1933   PetscCall(DMPlexStratifyMigrationSF(dm, sfMigration, &sfStratified));
1934   PetscCall(PetscSFDestroy(&sfMigration));
1935   sfMigration = sfStratified;
1936   PetscCall(PetscSFSetUp(sfMigration));
1937   PetscCall(PetscLogEventEnd(DMPLEX_Partition, dm, 0, 0, 0));
1938   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-partition_view", &flg));
1939   if (flg) {
1940     PetscCall(DMLabelView(lblPartition, PETSC_VIEWER_STDOUT_(comm)));
1941     PetscCall(PetscSFView(sfMigration, PETSC_VIEWER_STDOUT_(comm)));
1942   }
1943 
1944   /* Create non-overlapping parallel DM and migrate internal data */
1945   PetscCall(DMPlexCreate(comm, dmParallel));
1946   PetscCall(PetscObjectSetName((PetscObject)*dmParallel, "Parallel Mesh"));
1947   PetscCall(DMPlexMigrate(dm, sfMigration, *dmParallel));
1948 
1949   /* Build the point SF without overlap */
1950   PetscCall(DMPlexGetPartitionBalance(dm, &balance));
1951   PetscCall(DMPlexSetPartitionBalance(*dmParallel, balance));
1952   PetscCall(DMPlexCreatePointSF(*dmParallel, sfMigration, PETSC_TRUE, &sfPoint));
1953   PetscCall(DMSetPointSF(*dmParallel, sfPoint));
1954   PetscCall(DMPlexMigrateIsoperiodicFaceSF_Internal(dm, *dmParallel, sfMigration));
1955   PetscCall(DMGetCoordinateDM(*dmParallel, &dmCoord));
1956   if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint));
1957   if (flg) PetscCall(PetscSFView(sfPoint, NULL));
1958 
1959   if (overlap > 0) {
1960     DM      dmOverlap;
1961     PetscSF sfOverlap, sfOverlapPoint;
1962 
1963     /* Add the partition overlap to the distributed DM */
1964     PetscCall(DMPlexDistributeOverlap(*dmParallel, overlap, &sfOverlap, &dmOverlap));
1965     PetscCall(DMDestroy(dmParallel));
1966     *dmParallel = dmOverlap;
1967     if (flg) {
1968       PetscCall(PetscPrintf(comm, "Overlap Migration SF:\n"));
1969       PetscCall(PetscSFView(sfOverlap, NULL));
1970     }
1971 
1972     /* Re-map the migration SF to establish the full migration pattern */
1973     PetscCall(DMPlexRemapMigrationSF(sfOverlap, sfMigration, &sfOverlapPoint));
1974     PetscCall(PetscSFDestroy(&sfOverlap));
1975     PetscCall(PetscSFDestroy(&sfMigration));
1976     sfMigration = sfOverlapPoint;
1977   }
1978   /* Cleanup Partition */
1979   PetscCall(DMLabelDestroy(&lblPartition));
1980   PetscCall(DMLabelDestroy(&lblMigration));
1981   PetscCall(PetscSectionDestroy(&cellPartSection));
1982   PetscCall(ISDestroy(&cellPart));
1983   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, *dmParallel));
1984   // Create sfNatural, need discretization information
1985   PetscCall(DMCopyDisc(dm, *dmParallel));
1986   if (dm->localSection) {
1987     PetscSection psection;
1988     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &psection));
1989     PetscCall(PetscSFDistributeSection(sfMigration, dm->localSection, NULL, psection));
1990     PetscCall(DMSetLocalSection(*dmParallel, psection));
1991     PetscCall(PetscSectionDestroy(&psection));
1992   }
1993   if (dm->useNatural) {
1994     PetscSection section;
1995 
1996     PetscCall(DMSetUseNatural(*dmParallel, PETSC_TRUE));
1997     PetscCall(DMGetLocalSection(dm, &section));
1998 
1999     /* If DM has useNatural = PETSC_TRUE, but no sfNatural is set, the DM's Section is considered natural */
2000     /* sfMigration and sfNatural are respectively the point and dofs SFs mapping to this natural DM */
2001     /* Compose with a previous sfNatural if present */
2002     if (dm->sfNatural) {
2003       PetscCall(DMPlexMigrateGlobalToNaturalSF(dm, *dmParallel, dm->sfNatural, sfMigration, &(*dmParallel)->sfNatural));
2004     } else {
2005       PetscCall(DMPlexCreateGlobalToNaturalSF(*dmParallel, section, sfMigration, &(*dmParallel)->sfNatural));
2006     }
2007     /* Compose with a previous sfMigration if present */
2008     if (dm->sfMigration) {
2009       PetscSF naturalPointSF;
2010 
2011       PetscCall(PetscSFCompose(dm->sfMigration, sfMigration, &naturalPointSF));
2012       PetscCall(PetscSFDestroy(&sfMigration));
2013       sfMigration = naturalPointSF;
2014     }
2015   }
2016   /* Cleanup */
2017   if (sf) {
2018     *sf = sfMigration;
2019   } else PetscCall(PetscSFDestroy(&sfMigration));
2020   PetscCall(PetscSFDestroy(&sfPoint));
2021   PetscCall(PetscLogEventEnd(DMPLEX_Distribute, dm, 0, 0, 0));
2022   PetscFunctionReturn(PETSC_SUCCESS);
2023 }
2024 
2025 PetscErrorCode DMPlexDistributeOverlap_Internal(DM dm, PetscInt overlap, MPI_Comm newcomm, const char *ovlboundary, PetscSF *sf, DM *dmOverlap)
2026 {
2027   DM_Plex     *mesh = (DM_Plex *)dm->data;
2028   MPI_Comm     comm;
2029   PetscMPIInt  size, rank;
2030   PetscSection rootSection, leafSection;
2031   IS           rootrank, leafrank;
2032   DM           dmCoord;
2033   DMLabel      lblOverlap;
2034   PetscSF      sfOverlap, sfStratified, sfPoint;
2035   PetscBool    clear_ovlboundary;
2036 
2037   PetscFunctionBegin;
2038   if (sf) *sf = NULL;
2039   *dmOverlap = NULL;
2040   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2041   PetscCallMPI(MPI_Comm_size(comm, &size));
2042   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2043   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
2044   {
2045     // We need to get options for the _already_distributed mesh, so it must be done here
2046     PetscInt    overlap;
2047     const char *prefix;
2048     char        oldPrefix[PETSC_MAX_PATH_LEN];
2049 
2050     oldPrefix[0] = '\0';
2051     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
2052     PetscCall(PetscStrncpy(oldPrefix, prefix, sizeof(oldPrefix)));
2053     PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, "dist_"));
2054     PetscCall(DMPlexGetOverlap(dm, &overlap));
2055     PetscObjectOptionsBegin((PetscObject)dm);
2056     PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap));
2057     PetscOptionsEnd();
2058     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldPrefix[0] == '\0' ? NULL : oldPrefix));
2059   }
2060   if (ovlboundary) {
2061     PetscBool flg;
2062     PetscCall(DMHasLabel(dm, ovlboundary, &flg));
2063     if (!flg) {
2064       DMLabel label;
2065 
2066       PetscCall(DMCreateLabel(dm, ovlboundary));
2067       PetscCall(DMGetLabel(dm, ovlboundary, &label));
2068       PetscCall(DMPlexMarkBoundaryFaces(dm, 1, label));
2069       clear_ovlboundary = PETSC_TRUE;
2070     }
2071   }
2072   PetscCall(PetscLogEventBegin(DMPLEX_DistributeOverlap, dm, 0, 0, 0));
2073   /* Compute point overlap with neighbouring processes on the distributed DM */
2074   PetscCall(PetscLogEventBegin(DMPLEX_Partition, dm, 0, 0, 0));
2075   PetscCall(PetscSectionCreate(newcomm, &rootSection));
2076   PetscCall(PetscSectionCreate(newcomm, &leafSection));
2077   PetscCall(DMPlexDistributeOwnership(dm, rootSection, &rootrank, leafSection, &leafrank));
2078   if (mesh->numOvLabels) PetscCall(DMPlexCreateOverlapLabelFromLabels(dm, mesh->numOvLabels, mesh->ovLabels, mesh->ovValues, mesh->numOvExLabels, mesh->ovExLabels, mesh->ovExValues, rootSection, rootrank, leafSection, leafrank, &lblOverlap));
2079   else PetscCall(DMPlexCreateOverlapLabel(dm, overlap, rootSection, rootrank, leafSection, leafrank, &lblOverlap));
2080   /* Convert overlap label to stratified migration SF */
2081   PetscCall(DMPlexPartitionLabelCreateSF(dm, lblOverlap, PETSC_FALSE, &sfOverlap));
2082   PetscCall(DMPlexStratifyMigrationSF(dm, sfOverlap, &sfStratified));
2083   PetscCall(PetscSFDestroy(&sfOverlap));
2084   sfOverlap = sfStratified;
2085   PetscCall(PetscObjectSetName((PetscObject)sfOverlap, "Overlap SF"));
2086   PetscCall(PetscSFSetFromOptions(sfOverlap));
2087 
2088   PetscCall(PetscSectionDestroy(&rootSection));
2089   PetscCall(PetscSectionDestroy(&leafSection));
2090   PetscCall(ISDestroy(&rootrank));
2091   PetscCall(ISDestroy(&leafrank));
2092   PetscCall(PetscLogEventEnd(DMPLEX_Partition, dm, 0, 0, 0));
2093 
2094   /* Build the overlapping DM */
2095   PetscCall(DMPlexCreate(newcomm, dmOverlap));
2096   PetscCall(PetscObjectSetName((PetscObject)*dmOverlap, "Parallel Mesh"));
2097   PetscCall(DMPlexMigrate(dm, sfOverlap, *dmOverlap));
2098   /* Store the overlap in the new DM */
2099   PetscCall(DMPlexSetOverlap_Plex(*dmOverlap, dm, overlap));
2100   /* Build the new point SF */
2101   PetscCall(DMPlexCreatePointSF(*dmOverlap, sfOverlap, PETSC_FALSE, &sfPoint));
2102   PetscCall(DMSetPointSF(*dmOverlap, sfPoint));
2103   PetscCall(DMGetCoordinateDM(*dmOverlap, &dmCoord));
2104   if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint));
2105   PetscCall(DMGetCellCoordinateDM(*dmOverlap, &dmCoord));
2106   if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint));
2107   PetscCall(PetscSFDestroy(&sfPoint));
2108   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, *dmOverlap));
2109   /* TODO: labels stored inside the DS for regions should be handled here */
2110   PetscCall(DMCopyDisc(dm, *dmOverlap));
2111   /* Cleanup overlap partition */
2112   PetscCall(DMLabelDestroy(&lblOverlap));
2113   if (sf) *sf = sfOverlap;
2114   else PetscCall(PetscSFDestroy(&sfOverlap));
2115   if (ovlboundary) {
2116     DMLabel   label;
2117     PetscBool flg;
2118 
2119     if (clear_ovlboundary) PetscCall(DMRemoveLabel(dm, ovlboundary, NULL));
2120     PetscCall(DMHasLabel(*dmOverlap, ovlboundary, &flg));
2121     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing %s label", ovlboundary);
2122     PetscCall(DMGetLabel(*dmOverlap, ovlboundary, &label));
2123     PetscCall(DMPlexMarkBoundaryFaces_Internal(*dmOverlap, 1, 0, label, PETSC_TRUE));
2124   }
2125   PetscCall(PetscLogEventEnd(DMPLEX_DistributeOverlap, dm, 0, 0, 0));
2126   PetscFunctionReturn(PETSC_SUCCESS);
2127 }
2128 
2129 /*@
2130   DMPlexDistributeOverlap - Add partition overlap to a distributed non-overlapping `DM`.
2131 
2132   Collective
2133 
2134   Input Parameters:
2135 + dm      - The non-overlapping distributed `DMPLEX` object
2136 - overlap - The overlap of partitions (the same on all ranks)
2137 
2138   Output Parameters:
2139 + sf        - The `PetscSF` used for point distribution, or pass `NULL` if not needed
2140 - dmOverlap - The overlapping distributed `DMPLEX` object
2141 
2142   Options Database Keys:
2143 + -dm_plex_overlap_labels <name1,name2,...> - List of overlap label names
2144 . -dm_plex_overlap_values <int1,int2,...>   - List of overlap label values
2145 . -dm_plex_overlap_exclude_label <name>     - Label used to exclude points from overlap
2146 - -dm_plex_overlap_exclude_value <int>      - Label value used to exclude points from overlap
2147 
2148   Level: advanced
2149 
2150   Notes:
2151   If the mesh was not distributed, the return value is `NULL`.
2152 
2153   The user can control the definition of adjacency for the mesh using `DMSetAdjacency()`. They should choose the combination appropriate for the function
2154   representation on the mesh.
2155 
2156 .seealso: `DMPLEX`, `PetscSF`, `DM`, `DMPlexCreate()`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexCreateOverlapLabel()`, `DMPlexGetOverlap()`
2157 @*/
2158 PetscErrorCode DMPlexDistributeOverlap(DM dm, PetscInt overlap, PeOp PetscSF *sf, DM *dmOverlap)
2159 {
2160   PetscFunctionBegin;
2161   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2162   PetscValidLogicalCollectiveInt(dm, overlap, 2);
2163   if (sf) PetscAssertPointer(sf, 3);
2164   PetscAssertPointer(dmOverlap, 4);
2165   PetscCall(DMPlexDistributeOverlap_Internal(dm, overlap, PetscObjectComm((PetscObject)dm), NULL, sf, dmOverlap));
2166   PetscFunctionReturn(PETSC_SUCCESS);
2167 }
2168 
2169 PetscErrorCode DMPlexGetOverlap_Plex(DM dm, PetscInt *overlap)
2170 {
2171   DM_Plex *mesh = (DM_Plex *)dm->data;
2172 
2173   PetscFunctionBegin;
2174   *overlap = mesh->overlap;
2175   PetscFunctionReturn(PETSC_SUCCESS);
2176 }
2177 
2178 PetscErrorCode DMPlexSetOverlap_Plex(DM dm, DM dmSrc, PetscInt overlap)
2179 {
2180   DM_Plex *mesh    = NULL;
2181   DM_Plex *meshSrc = NULL;
2182 
2183   PetscFunctionBegin;
2184   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMPLEX);
2185   mesh = (DM_Plex *)dm->data;
2186   if (dmSrc) {
2187     PetscValidHeaderSpecificType(dmSrc, DM_CLASSID, 2, DMPLEX);
2188     meshSrc       = (DM_Plex *)dmSrc->data;
2189     mesh->overlap = meshSrc->overlap;
2190   } else {
2191     mesh->overlap = 0;
2192   }
2193   mesh->overlap += overlap;
2194   PetscFunctionReturn(PETSC_SUCCESS);
2195 }
2196 
2197 /*@
2198   DMPlexGetOverlap - Get the width of the cell overlap
2199 
2200   Not Collective
2201 
2202   Input Parameter:
2203 . dm - The `DM`
2204 
2205   Output Parameter:
2206 . overlap - the width of the cell overlap
2207 
2208   Level: intermediate
2209 
2210 .seealso: `DMPLEX`, `DMPlexSetOverlap()`, `DMPlexDistribute()`
2211 @*/
2212 PetscErrorCode DMPlexGetOverlap(DM dm, PetscInt *overlap)
2213 {
2214   PetscFunctionBegin;
2215   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2216   PetscAssertPointer(overlap, 2);
2217   PetscUseMethod(dm, "DMPlexGetOverlap_C", (DM, PetscInt *), (dm, overlap));
2218   PetscFunctionReturn(PETSC_SUCCESS);
2219 }
2220 
2221 /*@
2222   DMPlexSetOverlap - Set the width of the cell overlap
2223 
2224   Logically Collective
2225 
2226   Input Parameters:
2227 + dm      - The `DM`
2228 . dmSrc   - The `DM` that produced this one, or `NULL`
2229 - overlap - the width of the cell overlap
2230 
2231   Level: intermediate
2232 
2233   Note:
2234   The overlap from `dmSrc` is added to `dm`
2235 
2236 .seealso: `DMPLEX`, `DMPlexGetOverlap()`, `DMPlexDistribute()`
2237 @*/
2238 PetscErrorCode DMPlexSetOverlap(DM dm, DM dmSrc, PetscInt overlap)
2239 {
2240   PetscFunctionBegin;
2241   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2242   PetscValidLogicalCollectiveInt(dm, overlap, 3);
2243   PetscTryMethod(dm, "DMPlexSetOverlap_C", (DM, DM, PetscInt), (dm, dmSrc, overlap));
2244   PetscFunctionReturn(PETSC_SUCCESS);
2245 }
2246 
2247 PetscErrorCode DMPlexDistributeSetDefault_Plex(DM dm, PetscBool dist)
2248 {
2249   DM_Plex *mesh = (DM_Plex *)dm->data;
2250 
2251   PetscFunctionBegin;
2252   mesh->distDefault = dist;
2253   PetscFunctionReturn(PETSC_SUCCESS);
2254 }
2255 
2256 /*@
2257   DMPlexDistributeSetDefault - Set flag indicating whether the `DM` should be distributed by default
2258 
2259   Logically Collective
2260 
2261   Input Parameters:
2262 + dm   - The `DM`
2263 - dist - Flag for distribution
2264 
2265   Level: intermediate
2266 
2267 .seealso: `DMPLEX`, `DMPlexDistributeGetDefault()`, `DMPlexDistribute()`
2268 @*/
2269 PetscErrorCode DMPlexDistributeSetDefault(DM dm, PetscBool dist)
2270 {
2271   PetscFunctionBegin;
2272   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2273   PetscValidLogicalCollectiveBool(dm, dist, 2);
2274   PetscTryMethod(dm, "DMPlexDistributeSetDefault_C", (DM, PetscBool), (dm, dist));
2275   PetscFunctionReturn(PETSC_SUCCESS);
2276 }
2277 
2278 PetscErrorCode DMPlexDistributeGetDefault_Plex(DM dm, PetscBool *dist)
2279 {
2280   DM_Plex *mesh = (DM_Plex *)dm->data;
2281 
2282   PetscFunctionBegin;
2283   *dist = mesh->distDefault;
2284   PetscFunctionReturn(PETSC_SUCCESS);
2285 }
2286 
2287 /*@
2288   DMPlexDistributeGetDefault - Get flag indicating whether the `DM` should be distributed by default
2289 
2290   Not Collective
2291 
2292   Input Parameter:
2293 . dm - The `DM`
2294 
2295   Output Parameter:
2296 . dist - Flag for distribution
2297 
2298   Level: intermediate
2299 
2300 .seealso: `DMPLEX`, `DM`, `DMPlexDistributeSetDefault()`, `DMPlexDistribute()`
2301 @*/
2302 PetscErrorCode DMPlexDistributeGetDefault(DM dm, PetscBool *dist)
2303 {
2304   PetscFunctionBegin;
2305   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2306   PetscAssertPointer(dist, 2);
2307   PetscUseMethod(dm, "DMPlexDistributeGetDefault_C", (DM, PetscBool *), (dm, dist));
2308   PetscFunctionReturn(PETSC_SUCCESS);
2309 }
2310 
2311 /*@
2312   DMPlexGetGatherDM - Get a copy of the `DMPLEX` that gathers all points on the
2313   root process of the original's communicator.
2314 
2315   Collective
2316 
2317   Input Parameter:
2318 . dm - the original `DMPLEX` object
2319 
2320   Output Parameters:
2321 + sf         - the `PetscSF` used for point distribution (optional)
2322 - gatherMesh - the gathered `DM` object, or `NULL`
2323 
2324   Level: intermediate
2325 
2326 .seealso: `DMPLEX`, `DM`, `PetscSF`, `DMPlexDistribute()`, `DMPlexGetRedundantDM()`
2327 @*/
2328 PetscErrorCode DMPlexGetGatherDM(DM dm, PetscSF *sf, PeOp DM *gatherMesh)
2329 {
2330   MPI_Comm         comm;
2331   PetscMPIInt      size;
2332   PetscPartitioner oldPart, gatherPart;
2333 
2334   PetscFunctionBegin;
2335   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2336   PetscAssertPointer(gatherMesh, 3);
2337   *gatherMesh = NULL;
2338   if (sf) *sf = NULL;
2339   comm = PetscObjectComm((PetscObject)dm);
2340   PetscCallMPI(MPI_Comm_size(comm, &size));
2341   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
2342   PetscCall(DMPlexGetPartitioner(dm, &oldPart));
2343   PetscCall(PetscObjectReference((PetscObject)oldPart));
2344   PetscCall(PetscPartitionerCreate(comm, &gatherPart));
2345   PetscCall(PetscPartitionerSetType(gatherPart, PETSCPARTITIONERGATHER));
2346   PetscCall(DMPlexSetPartitioner(dm, gatherPart));
2347   PetscCall(DMPlexDistribute(dm, 0, sf, gatherMesh));
2348 
2349   PetscCall(DMPlexSetPartitioner(dm, oldPart));
2350   PetscCall(PetscPartitionerDestroy(&gatherPart));
2351   PetscCall(PetscPartitionerDestroy(&oldPart));
2352   PetscFunctionReturn(PETSC_SUCCESS);
2353 }
2354 
2355 /*@
2356   DMPlexGetRedundantDM - Get a copy of the `DMPLEX` that is completely copied on each process.
2357 
2358   Collective
2359 
2360   Input Parameter:
2361 . dm - the original `DMPLEX` object
2362 
2363   Output Parameters:
2364 + sf            - the `PetscSF` used for point distribution (optional)
2365 - redundantMesh - the redundant `DM` object, or `NULL`
2366 
2367   Level: intermediate
2368 
2369 .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexGetGatherDM()`
2370 @*/
2371 PetscErrorCode DMPlexGetRedundantDM(DM dm, PetscSF *sf, PeOp DM *redundantMesh)
2372 {
2373   MPI_Comm     comm;
2374   PetscMPIInt  size, rank;
2375   PetscInt     pStart, pEnd, p;
2376   PetscInt     numPoints = -1;
2377   PetscSF      migrationSF, sfPoint, gatherSF;
2378   DM           gatherDM, dmCoord;
2379   PetscSFNode *points;
2380 
2381   PetscFunctionBegin;
2382   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2383   PetscAssertPointer(redundantMesh, 3);
2384   *redundantMesh = NULL;
2385   comm           = PetscObjectComm((PetscObject)dm);
2386   PetscCallMPI(MPI_Comm_size(comm, &size));
2387   if (size == 1) {
2388     PetscCall(PetscObjectReference((PetscObject)dm));
2389     *redundantMesh = dm;
2390     if (sf) *sf = NULL;
2391     PetscFunctionReturn(PETSC_SUCCESS);
2392   }
2393   PetscCall(DMPlexGetGatherDM(dm, &gatherSF, &gatherDM));
2394   if (!gatherDM) PetscFunctionReturn(PETSC_SUCCESS);
2395   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2396   PetscCall(DMPlexGetChart(gatherDM, &pStart, &pEnd));
2397   numPoints = pEnd - pStart;
2398   PetscCallMPI(MPI_Bcast(&numPoints, 1, MPIU_INT, 0, comm));
2399   PetscCall(PetscMalloc1(numPoints, &points));
2400   PetscCall(PetscSFCreate(comm, &migrationSF));
2401   for (p = 0; p < numPoints; p++) {
2402     points[p].index = p;
2403     points[p].rank  = 0;
2404   }
2405   PetscCall(PetscSFSetGraph(migrationSF, pEnd - pStart, numPoints, NULL, PETSC_OWN_POINTER, points, PETSC_OWN_POINTER));
2406   PetscCall(DMPlexCreate(comm, redundantMesh));
2407   PetscCall(PetscObjectSetName((PetscObject)*redundantMesh, "Redundant Mesh"));
2408   PetscCall(DMPlexMigrate(gatherDM, migrationSF, *redundantMesh));
2409   /* This is to express that all point are in overlap */
2410   PetscCall(DMPlexSetOverlap_Plex(*redundantMesh, NULL, PETSC_INT_MAX));
2411   PetscCall(DMPlexCreatePointSF(*redundantMesh, migrationSF, PETSC_FALSE, &sfPoint));
2412   PetscCall(DMSetPointSF(*redundantMesh, sfPoint));
2413   PetscCall(DMGetCoordinateDM(*redundantMesh, &dmCoord));
2414   if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint));
2415   PetscCall(PetscSFDestroy(&sfPoint));
2416   if (sf) {
2417     PetscSF tsf;
2418 
2419     PetscCall(PetscSFCompose(gatherSF, migrationSF, &tsf));
2420     PetscCall(DMPlexStratifyMigrationSF(dm, tsf, sf));
2421     PetscCall(PetscSFDestroy(&tsf));
2422   }
2423   PetscCall(PetscSFDestroy(&migrationSF));
2424   PetscCall(PetscSFDestroy(&gatherSF));
2425   PetscCall(DMDestroy(&gatherDM));
2426   PetscCall(DMCopyDisc(dm, *redundantMesh));
2427   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, *redundantMesh));
2428   PetscFunctionReturn(PETSC_SUCCESS);
2429 }
2430 
2431 /*@
2432   DMPlexIsDistributed - Find out whether this `DM` is distributed, i.e. more than one rank owns some points.
2433 
2434   Collective
2435 
2436   Input Parameter:
2437 . dm - The `DM` object
2438 
2439   Output Parameter:
2440 . distributed - Flag whether the `DM` is distributed
2441 
2442   Level: intermediate
2443 
2444   Notes:
2445   This currently finds out whether at least two ranks have any DAG points.
2446   This involves `MPI_Allreduce()` with one integer.
2447   The result is currently not stashed so every call to this routine involves this global communication.
2448 
2449 .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexGetOverlap()`, `DMPlexIsInterpolated()`
2450 @*/
2451 PetscErrorCode DMPlexIsDistributed(DM dm, PetscBool *distributed)
2452 {
2453   PetscInt    pStart, pEnd, count;
2454   MPI_Comm    comm;
2455   PetscMPIInt size;
2456 
2457   PetscFunctionBegin;
2458   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2459   PetscAssertPointer(distributed, 2);
2460   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2461   PetscCallMPI(MPI_Comm_size(comm, &size));
2462   if (size == 1) {
2463     *distributed = PETSC_FALSE;
2464     PetscFunctionReturn(PETSC_SUCCESS);
2465   }
2466   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
2467   count = (pEnd - pStart) > 0 ? 1 : 0;
2468   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &count, 1, MPIU_INT, MPI_SUM, comm));
2469   *distributed = count > 1 ? PETSC_TRUE : PETSC_FALSE;
2470   PetscFunctionReturn(PETSC_SUCCESS);
2471 }
2472 
2473 /*@
2474   DMPlexDistributionSetName - Set the name of the specific parallel distribution
2475 
2476   Input Parameters:
2477 + dm   - The `DM`
2478 - name - The name of the specific parallel distribution
2479 
2480   Level: developer
2481 
2482   Note:
2483   If distribution name is set when saving, `DMPlexTopologyView()` saves the plex's
2484   parallel distribution (i.e., partition, ownership, and local ordering of points) under
2485   this name. Conversely, if distribution name is set when loading, `DMPlexTopologyLoad()`
2486   loads the parallel distribution stored in file under this name.
2487 
2488 .seealso: `DMPLEX`, `DMPlexDistributionGetName()`, `DMPlexTopologyView()`, `DMPlexTopologyLoad()`
2489 @*/
2490 PetscErrorCode DMPlexDistributionSetName(DM dm, const char name[])
2491 {
2492   DM_Plex *mesh = (DM_Plex *)dm->data;
2493 
2494   PetscFunctionBegin;
2495   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMPLEX);
2496   if (name) PetscAssertPointer(name, 2);
2497   PetscCall(PetscFree(mesh->distributionName));
2498   PetscCall(PetscStrallocpy(name, &mesh->distributionName));
2499   PetscFunctionReturn(PETSC_SUCCESS);
2500 }
2501 
2502 /*@
2503   DMPlexDistributionGetName - Retrieve the name of the specific parallel distribution
2504 
2505   Input Parameter:
2506 . dm - The `DM`
2507 
2508   Output Parameter:
2509 . name - The name of the specific parallel distribution
2510 
2511   Level: developer
2512 
2513   Note:
2514   If distribution name is set when saving, `DMPlexTopologyView()` saves the plex's
2515   parallel distribution (i.e., partition, ownership, and local ordering of points) under
2516   this name. Conversely, if distribution name is set when loading, `DMPlexTopologyLoad()`
2517   loads the parallel distribution stored in file under this name.
2518 
2519 .seealso: `DMPLEX`, `DMPlexDistributionSetName()`, `DMPlexTopologyView()`, `DMPlexTopologyLoad()`
2520 @*/
2521 PetscErrorCode DMPlexDistributionGetName(DM dm, const char *name[])
2522 {
2523   DM_Plex *mesh = (DM_Plex *)dm->data;
2524 
2525   PetscFunctionBegin;
2526   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMPLEX);
2527   PetscAssertPointer(name, 2);
2528   *name = mesh->distributionName;
2529   PetscFunctionReturn(PETSC_SUCCESS);
2530 }
2531