xref: /petsc/src/dm/impls/plex/plexdistribute.c (revision f13dfd9ea68e0ddeee984e65c377a1819eab8a8a)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>  /*I      "petscdmplex.h"   I*/
2c58f1c22SToby Isaac #include <petsc/private/dmlabelimpl.h> /*I      "petscdmlabel.h"  I*/
370034214SMatthew G. Knepley 
43c1f0c11SLawrence Mitchell /*@C
53c1f0c11SLawrence Mitchell   DMPlexSetAdjacencyUser - Define adjacency in the mesh using a user-provided callback
63c1f0c11SLawrence Mitchell 
73c1f0c11SLawrence Mitchell   Input Parameters:
83c1f0c11SLawrence Mitchell + dm   - The DM object
920f4b53cSBarry Smith . user - The user callback, may be `NULL` (to clear the callback)
1020f4b53cSBarry Smith - ctx  - context for callback evaluation, may be `NULL`
113c1f0c11SLawrence Mitchell 
123c1f0c11SLawrence Mitchell   Level: advanced
133c1f0c11SLawrence Mitchell 
143c1f0c11SLawrence Mitchell   Notes:
1520f4b53cSBarry Smith   The caller of `DMPlexGetAdjacency()` may need to arrange that a large enough array is available for the adjacency.
163c1f0c11SLawrence Mitchell 
1720f4b53cSBarry Smith   Any setting here overrides other configuration of `DMPLEX` adjacency determination.
183c1f0c11SLawrence Mitchell 
1920f4b53cSBarry Smith .seealso: `DMPLEX`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexGetAdjacency()`, `DMPlexGetAdjacencyUser()`
203c1f0c11SLawrence Mitchell @*/
21d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetAdjacencyUser(DM dm, PetscErrorCode (*user)(DM, PetscInt, PetscInt *, PetscInt[], void *), void *ctx)
22d71ae5a4SJacob Faibussowitsch {
233c1f0c11SLawrence Mitchell   DM_Plex *mesh = (DM_Plex *)dm->data;
243c1f0c11SLawrence Mitchell 
253c1f0c11SLawrence Mitchell   PetscFunctionBegin;
263c1f0c11SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
273c1f0c11SLawrence Mitchell   mesh->useradjacency    = user;
283c1f0c11SLawrence Mitchell   mesh->useradjacencyctx = ctx;
293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
303c1f0c11SLawrence Mitchell }
313c1f0c11SLawrence Mitchell 
323c1f0c11SLawrence Mitchell /*@C
333c1f0c11SLawrence Mitchell   DMPlexGetAdjacencyUser - get the user-defined adjacency callback
343c1f0c11SLawrence Mitchell 
353c1f0c11SLawrence Mitchell   Input Parameter:
3620f4b53cSBarry Smith . dm - The `DM` object
373c1f0c11SLawrence Mitchell 
383c1f0c11SLawrence Mitchell   Output Parameters:
39ef1023bdSBarry Smith + user - The callback
403c1f0c11SLawrence Mitchell - ctx  - context for callback evaluation
413c1f0c11SLawrence Mitchell 
423c1f0c11SLawrence Mitchell   Level: advanced
433c1f0c11SLawrence Mitchell 
4420f4b53cSBarry Smith .seealso: `DMPLEX`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexGetAdjacency()`, `DMPlexSetAdjacencyUser()`
453c1f0c11SLawrence Mitchell @*/
46d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAdjacencyUser(DM dm, PetscErrorCode (**user)(DM, PetscInt, PetscInt *, PetscInt[], void *), void **ctx)
47d71ae5a4SJacob Faibussowitsch {
483c1f0c11SLawrence Mitchell   DM_Plex *mesh = (DM_Plex *)dm->data;
493c1f0c11SLawrence Mitchell 
503c1f0c11SLawrence Mitchell   PetscFunctionBegin;
513c1f0c11SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
523c1f0c11SLawrence Mitchell   if (user) *user = mesh->useradjacency;
533c1f0c11SLawrence Mitchell   if (ctx) *ctx = mesh->useradjacencyctx;
543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
553c1f0c11SLawrence Mitchell }
563c1f0c11SLawrence Mitchell 
5770034214SMatthew G. Knepley /*@
58a17985deSToby Isaac   DMPlexSetAdjacencyUseAnchors - Define adjacency in the mesh using the point-to-point constraints.
598b0b4c70SToby Isaac 
608b0b4c70SToby Isaac   Input Parameters:
6120f4b53cSBarry Smith + dm         - The `DM` object
625b317d89SToby Isaac - useAnchors - Flag to use the constraints.  If PETSC_TRUE, then constrained points are omitted from DMPlexGetAdjacency(), and their anchor points appear in their place.
638b0b4c70SToby Isaac 
648b0b4c70SToby Isaac   Level: intermediate
658b0b4c70SToby Isaac 
6620f4b53cSBarry Smith .seealso: `DMPLEX`, `DMGetAdjacency()`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexSetAnchors()`
678b0b4c70SToby Isaac @*/
68d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetAdjacencyUseAnchors(DM dm, PetscBool useAnchors)
69d71ae5a4SJacob Faibussowitsch {
708b0b4c70SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
718b0b4c70SToby Isaac 
728b0b4c70SToby Isaac   PetscFunctionBegin;
738b0b4c70SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
745b317d89SToby Isaac   mesh->useAnchors = useAnchors;
753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
768b0b4c70SToby Isaac }
778b0b4c70SToby Isaac 
788b0b4c70SToby Isaac /*@
79a17985deSToby Isaac   DMPlexGetAdjacencyUseAnchors - Query whether adjacency in the mesh uses the point-to-point constraints.
808b0b4c70SToby Isaac 
818b0b4c70SToby Isaac   Input Parameter:
8220f4b53cSBarry Smith . dm - The `DM` object
838b0b4c70SToby Isaac 
848b0b4c70SToby Isaac   Output Parameter:
855b317d89SToby Isaac . useAnchors - Flag to use the closure.  If PETSC_TRUE, then constrained points are omitted from DMPlexGetAdjacency(), and their anchor points appear in their place.
868b0b4c70SToby Isaac 
878b0b4c70SToby Isaac   Level: intermediate
888b0b4c70SToby Isaac 
8920f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexSetAdjacencyUseAnchors()`, `DMSetAdjacency()`, `DMGetAdjacency()`, `DMPlexDistribute()`, `DMPlexPreallocateOperator()`, `DMPlexSetAnchors()`
908b0b4c70SToby Isaac @*/
91d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAdjacencyUseAnchors(DM dm, PetscBool *useAnchors)
92d71ae5a4SJacob Faibussowitsch {
938b0b4c70SToby Isaac   DM_Plex *mesh = (DM_Plex *)dm->data;
948b0b4c70SToby Isaac 
958b0b4c70SToby Isaac   PetscFunctionBegin;
968b0b4c70SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
974f572ea9SToby Isaac   PetscAssertPointer(useAnchors, 2);
985b317d89SToby Isaac   *useAnchors = mesh->useAnchors;
993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1008b0b4c70SToby Isaac }
1018b0b4c70SToby Isaac 
102d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetAdjacency_Cone_Internal(DM dm, PetscInt p, PetscInt *adjSize, PetscInt adj[])
103d71ae5a4SJacob Faibussowitsch {
10470034214SMatthew G. Knepley   const PetscInt *cone   = NULL;
10570034214SMatthew G. Knepley   PetscInt        numAdj = 0, maxAdjSize = *adjSize, coneSize, c;
10670034214SMatthew G. Knepley 
10770034214SMatthew G. Knepley   PetscFunctionBeginHot;
1089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
1099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, p, &cone));
1104b6b44bdSMatthew G. Knepley   for (c = 0; c <= coneSize; ++c) {
1114b6b44bdSMatthew G. Knepley     const PetscInt  point   = !c ? p : cone[c - 1];
11270034214SMatthew G. Knepley     const PetscInt *support = NULL;
11370034214SMatthew G. Knepley     PetscInt        supportSize, s, q;
11470034214SMatthew G. Knepley 
1159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, point, &supportSize));
1169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, point, &support));
11770034214SMatthew G. Knepley     for (s = 0; s < supportSize; ++s) {
118527e7439SSatish Balay       for (q = 0; q < numAdj || ((void)(adj[numAdj++] = support[s]), 0); ++q) {
11970034214SMatthew G. Knepley         if (support[s] == adj[q]) break;
12070034214SMatthew G. Knepley       }
12163a3b9bcSJacob Faibussowitsch       PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize);
12270034214SMatthew G. Knepley     }
12370034214SMatthew G. Knepley   }
12470034214SMatthew G. Knepley   *adjSize = numAdj;
1253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12670034214SMatthew G. Knepley }
12770034214SMatthew G. Knepley 
128d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetAdjacency_Support_Internal(DM dm, PetscInt p, PetscInt *adjSize, PetscInt adj[])
129d71ae5a4SJacob Faibussowitsch {
13070034214SMatthew G. Knepley   const PetscInt *support = NULL;
13170034214SMatthew G. Knepley   PetscInt        numAdj = 0, maxAdjSize = *adjSize, supportSize, s;
13270034214SMatthew G. Knepley 
13370034214SMatthew G. Knepley   PetscFunctionBeginHot;
1349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupportSize(dm, p, &supportSize));
1359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSupport(dm, p, &support));
1364b6b44bdSMatthew G. Knepley   for (s = 0; s <= supportSize; ++s) {
1374b6b44bdSMatthew G. Knepley     const PetscInt  point = !s ? p : support[s - 1];
13870034214SMatthew G. Knepley     const PetscInt *cone  = NULL;
13970034214SMatthew G. Knepley     PetscInt        coneSize, c, q;
14070034214SMatthew G. Knepley 
1419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
1429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
14370034214SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
144527e7439SSatish Balay       for (q = 0; q < numAdj || ((void)(adj[numAdj++] = cone[c]), 0); ++q) {
14570034214SMatthew G. Knepley         if (cone[c] == adj[q]) break;
14670034214SMatthew G. Knepley       }
14763a3b9bcSJacob Faibussowitsch       PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize);
14870034214SMatthew G. Knepley     }
14970034214SMatthew G. Knepley   }
15070034214SMatthew G. Knepley   *adjSize = numAdj;
1513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15270034214SMatthew G. Knepley }
15370034214SMatthew G. Knepley 
154d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetAdjacency_Transitive_Internal(DM dm, PetscInt p, PetscBool useClosure, PetscInt *adjSize, PetscInt adj[])
155d71ae5a4SJacob Faibussowitsch {
15670034214SMatthew G. Knepley   PetscInt *star   = NULL;
15770034214SMatthew G. Knepley   PetscInt  numAdj = 0, maxAdjSize = *adjSize, starSize, s;
15870034214SMatthew G. Knepley 
15970034214SMatthew G. Knepley   PetscFunctionBeginHot;
1609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, &star));
16170034214SMatthew G. Knepley   for (s = 0; s < starSize * 2; s += 2) {
16270034214SMatthew G. Knepley     const PetscInt *closure = NULL;
16370034214SMatthew G. Knepley     PetscInt        closureSize, c, q;
16470034214SMatthew G. Knepley 
1659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **)&closure));
16670034214SMatthew G. Knepley     for (c = 0; c < closureSize * 2; c += 2) {
167527e7439SSatish Balay       for (q = 0; q < numAdj || ((void)(adj[numAdj++] = closure[c]), 0); ++q) {
16870034214SMatthew G. Knepley         if (closure[c] == adj[q]) break;
16970034214SMatthew G. Knepley       }
17063a3b9bcSJacob Faibussowitsch       PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize);
17170034214SMatthew G. Knepley     }
1729566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **)&closure));
17370034214SMatthew G. Knepley   }
1749566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, p, useClosure, &starSize, &star));
17570034214SMatthew G. Knepley   *adjSize = numAdj;
1763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17770034214SMatthew G. Knepley }
17870034214SMatthew G. Knepley 
179d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAdjacency_Internal(DM dm, PetscInt p, PetscBool useCone, PetscBool useTransitiveClosure, PetscBool useAnchors, PetscInt *adjSize, PetscInt *adj[])
180d71ae5a4SJacob Faibussowitsch {
18179bad331SMatthew G. Knepley   static PetscInt asiz       = 0;
1828b0b4c70SToby Isaac   PetscInt        maxAnchors = 1;
1838b0b4c70SToby Isaac   PetscInt        aStart = -1, aEnd = -1;
1848b0b4c70SToby Isaac   PetscInt        maxAdjSize;
1858b0b4c70SToby Isaac   PetscSection    aSec = NULL;
1868b0b4c70SToby Isaac   IS              aIS  = NULL;
1878b0b4c70SToby Isaac   const PetscInt *anchors;
1883c1f0c11SLawrence Mitchell   DM_Plex        *mesh = (DM_Plex *)dm->data;
18970034214SMatthew G. Knepley 
19070034214SMatthew G. Knepley   PetscFunctionBeginHot;
1915b317d89SToby Isaac   if (useAnchors) {
1929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS));
1938b0b4c70SToby Isaac     if (aSec) {
1949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchors));
19524c766afSToby Isaac       maxAnchors = PetscMax(1, maxAnchors);
1969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd));
1979566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(aIS, &anchors));
1988b0b4c70SToby Isaac     }
1998b0b4c70SToby Isaac   }
20079bad331SMatthew G. Knepley   if (!*adj) {
201cf910586SMatthew G. Knepley     PetscInt depth, maxC, maxS, maxP, pStart, pEnd;
20279bad331SMatthew G. Knepley 
2039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
2049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
205412e9a14SMatthew G. Knepley     depth = PetscMax(depth, -depth);
2069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetMaxSizes(dm, &maxC, &maxS));
207cf910586SMatthew G. Knepley     maxP = maxS * maxC;
208cf910586SMatthew G. Knepley     /* Adjacency can be as large as supp(cl(cell)) or cl(supp(vertex)),
209cf910586SMatthew G. Knepley            supp(cell) + supp(maxC faces) + supp(maxC^2 edges) + supp(maxC^3 vertices)
210cf910586SMatthew G. Knepley          = 0 + maxS*maxC + maxS^2*maxC^2 + maxS^3*maxC^3
211cf910586SMatthew G. Knepley          = \sum^d_{i=0} (maxS*maxC)^i - 1
212cf910586SMatthew G. Knepley          = (maxS*maxC)^{d+1} - 1 / (maxS*maxC - 1) - 1
213cf910586SMatthew G. Knepley       We could improve this by getting the max by strata:
214cf910586SMatthew G. Knepley            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)
215cf910586SMatthew G. Knepley          = 0 + maxS[d-1]*maxC[d] + maxS[1]*maxC[d]*maxC[d-1] + maxS[0]*maxC[d]*maxC[d-1]*maxC[d-2]
216cf910586SMatthew G. Knepley       and the same with S and C reversed
217cf910586SMatthew G. Knepley     */
218cf910586SMatthew G. Knepley     if ((depth == 3 && maxP > 200) || (depth == 2 && maxP > 580)) asiz = pEnd - pStart;
219cf910586SMatthew G. Knepley     else asiz = (maxP > 1) ? ((PetscPowInt(maxP, depth + 1) - 1) / (maxP - 1)) : depth + 1;
2208b0b4c70SToby Isaac     asiz *= maxAnchors;
22124c766afSToby Isaac     asiz = PetscMin(asiz, pEnd - pStart);
2229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(asiz, adj));
22379bad331SMatthew G. Knepley   }
22479bad331SMatthew G. Knepley   if (*adjSize < 0) *adjSize = asiz;
2258b0b4c70SToby Isaac   maxAdjSize = *adjSize;
2263c1f0c11SLawrence Mitchell   if (mesh->useradjacency) {
2279566063dSJacob Faibussowitsch     PetscCall((*mesh->useradjacency)(dm, p, adjSize, *adj, mesh->useradjacencyctx));
2283c1f0c11SLawrence Mitchell   } else if (useTransitiveClosure) {
2299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Transitive_Internal(dm, p, useCone, adjSize, *adj));
23070034214SMatthew G. Knepley   } else if (useCone) {
2319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Cone_Internal(dm, p, adjSize, *adj));
23270034214SMatthew G. Knepley   } else {
2339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Support_Internal(dm, p, adjSize, *adj));
23470034214SMatthew G. Knepley   }
2355b317d89SToby Isaac   if (useAnchors && aSec) {
2368b0b4c70SToby Isaac     PetscInt  origSize = *adjSize;
2378b0b4c70SToby Isaac     PetscInt  numAdj   = origSize;
2388b0b4c70SToby Isaac     PetscInt  i        = 0, j;
2398b0b4c70SToby Isaac     PetscInt *orig     = *adj;
2408b0b4c70SToby Isaac 
2418b0b4c70SToby Isaac     while (i < origSize) {
2428b0b4c70SToby Isaac       PetscInt p    = orig[i];
2438b0b4c70SToby Isaac       PetscInt aDof = 0;
2448b0b4c70SToby Isaac 
24548a46eb9SPierre Jolivet       if (p >= aStart && p < aEnd) PetscCall(PetscSectionGetDof(aSec, p, &aDof));
2468b0b4c70SToby Isaac       if (aDof) {
2478b0b4c70SToby Isaac         PetscInt aOff;
2488b0b4c70SToby Isaac         PetscInt s, q;
2498b0b4c70SToby Isaac 
250ad540459SPierre Jolivet         for (j = i + 1; j < numAdj; j++) orig[j - 1] = orig[j];
2518b0b4c70SToby Isaac         origSize--;
2528b0b4c70SToby Isaac         numAdj--;
2539566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(aSec, p, &aOff));
2548b0b4c70SToby Isaac         for (s = 0; s < aDof; ++s) {
255527e7439SSatish Balay           for (q = 0; q < numAdj || ((void)(orig[numAdj++] = anchors[aOff + s]), 0); ++q) {
2568b0b4c70SToby Isaac             if (anchors[aOff + s] == orig[q]) break;
2578b0b4c70SToby Isaac           }
25863a3b9bcSJacob Faibussowitsch           PetscCheck(numAdj <= maxAdjSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%" PetscInt_FMT ")", maxAdjSize);
2598b0b4c70SToby Isaac         }
2609371c9d4SSatish Balay       } else {
2618b0b4c70SToby Isaac         i++;
2628b0b4c70SToby Isaac       }
2638b0b4c70SToby Isaac     }
2648b0b4c70SToby Isaac     *adjSize = numAdj;
2659566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(aIS, &anchors));
2668b0b4c70SToby Isaac   }
2673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26870034214SMatthew G. Knepley }
26970034214SMatthew G. Knepley 
27070034214SMatthew G. Knepley /*@
27170034214SMatthew G. Knepley   DMPlexGetAdjacency - Return all points adjacent to the given point
27270034214SMatthew G. Knepley 
27370034214SMatthew G. Knepley   Input Parameters:
27420f4b53cSBarry Smith + dm - The `DM` object
2756b867d5aSJose E. Roman - p  - The point
27670034214SMatthew G. Knepley 
2776b867d5aSJose E. Roman   Input/Output Parameters:
27820f4b53cSBarry Smith + adjSize - The maximum size of `adj` if it is non-`NULL`, or `PETSC_DETERMINE`;
2796b867d5aSJose E. Roman             on output the number of adjacent points
28020f4b53cSBarry Smith - adj     - Either `NULL` so that the array is allocated, or an existing array with size `adjSize`;
2816b867d5aSJose E. Roman         on output contains the adjacent points
28270034214SMatthew G. Knepley 
28370034214SMatthew G. Knepley   Level: advanced
28470034214SMatthew G. Knepley 
28595452b02SPatrick Sanan   Notes:
28620f4b53cSBarry Smith   The user must `PetscFree()` the `adj` array if it was not passed in.
28770034214SMatthew G. Knepley 
28820f4b53cSBarry Smith .seealso: `DMPLEX`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMCreateMatrix()`, `DMPlexPreallocateOperator()`
28970034214SMatthew G. Knepley @*/
290d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAdjacency(DM dm, PetscInt p, PetscInt *adjSize, PetscInt *adj[])
291d71ae5a4SJacob Faibussowitsch {
2921cf84007SMatthew G. Knepley   PetscBool useCone, useClosure, useAnchors;
29370034214SMatthew G. Knepley 
29470034214SMatthew G. Knepley   PetscFunctionBeginHot;
29570034214SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2964f572ea9SToby Isaac   PetscAssertPointer(adjSize, 3);
2974f572ea9SToby Isaac   PetscAssertPointer(adj, 4);
2989566063dSJacob Faibussowitsch   PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
2999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAdjacencyUseAnchors(dm, &useAnchors));
3009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, adjSize, adj));
3013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30270034214SMatthew G. Knepley }
30308633170SToby Isaac 
304b0a623aaSMatthew G. Knepley /*@
30520f4b53cSBarry Smith   DMPlexCreateTwoSidedProcessSF - Create an `PetscSF` which just has process connectivity
306b0a623aaSMatthew G. Knepley 
30720f4b53cSBarry Smith   Collective
308b0a623aaSMatthew G. Knepley 
309b0a623aaSMatthew G. Knepley   Input Parameters:
31020f4b53cSBarry Smith + dm              - The `DM`
31120f4b53cSBarry Smith . sfPoint         - The `PetscSF` which encodes point connectivity
31220f4b53cSBarry Smith . rootRankSection - to be documented
31320f4b53cSBarry Smith . rootRanks       - to be documented
31460225df5SJacob Faibussowitsch . leafRankSection - to be documented
31520f4b53cSBarry Smith - leafRanks       - to be documented
316b0a623aaSMatthew G. Knepley 
317b0a623aaSMatthew G. Knepley   Output Parameters:
31820f4b53cSBarry Smith + processRanks - A list of process neighbors, or `NULL`
31920f4b53cSBarry Smith - sfProcess    - An `PetscSF` encoding the two-sided process connectivity, or `NULL`
320b0a623aaSMatthew G. Knepley 
321b0a623aaSMatthew G. Knepley   Level: developer
322b0a623aaSMatthew G. Knepley 
32320f4b53cSBarry Smith .seealso: `DMPLEX`, `PetscSFCreate()`, `DMPlexCreateProcessSF()`
324b0a623aaSMatthew G. Knepley @*/
325d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateTwoSidedProcessSF(DM dm, PetscSF sfPoint, PetscSection rootRankSection, IS rootRanks, PetscSection leafRankSection, IS leafRanks, IS *processRanks, PetscSF *sfProcess)
326d71ae5a4SJacob Faibussowitsch {
327b0a623aaSMatthew G. Knepley   const PetscSFNode *remotePoints;
328b0a623aaSMatthew G. Knepley   PetscInt          *localPointsNew;
329b0a623aaSMatthew G. Knepley   PetscSFNode       *remotePointsNew;
330b0a623aaSMatthew G. Knepley   const PetscInt    *nranks;
331b0a623aaSMatthew G. Knepley   PetscInt          *ranksNew;
332b0a623aaSMatthew G. Knepley   PetscBT            neighbors;
333b0a623aaSMatthew G. Knepley   PetscInt           pStart, pEnd, p, numLeaves, l, numNeighbors, n;
3349852e123SBarry Smith   PetscMPIInt        size, proc, rank;
335b0a623aaSMatthew G. Knepley 
336b0a623aaSMatthew G. Knepley   PetscFunctionBegin;
337b0a623aaSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
338b0a623aaSMatthew G. Knepley   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
3394f572ea9SToby Isaac   if (processRanks) PetscAssertPointer(processRanks, 7);
3404f572ea9SToby Isaac   if (sfProcess) PetscAssertPointer(sfProcess, 8);
3419566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
3429566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3439566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfPoint, NULL, &numLeaves, NULL, &remotePoints));
3449566063dSJacob Faibussowitsch   PetscCall(PetscBTCreate(size, &neighbors));
3459566063dSJacob Faibussowitsch   PetscCall(PetscBTMemzero(size, neighbors));
346b0a623aaSMatthew G. Knepley   /* Compute root-to-leaf process connectivity */
3479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(rootRankSection, &pStart, &pEnd));
3489566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rootRanks, &nranks));
349b0a623aaSMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
350b0a623aaSMatthew G. Knepley     PetscInt ndof, noff, n;
351b0a623aaSMatthew G. Knepley 
3529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(rootRankSection, p, &ndof));
3539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(rootRankSection, p, &noff));
3549566063dSJacob Faibussowitsch     for (n = 0; n < ndof; ++n) PetscCall(PetscBTSet(neighbors, nranks[noff + n]));
355b0a623aaSMatthew G. Knepley   }
3569566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rootRanks, &nranks));
357b0a623aaSMatthew G. Knepley   /* Compute leaf-to-neighbor process connectivity */
3589566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(leafRankSection, &pStart, &pEnd));
3599566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(leafRanks, &nranks));
360b0a623aaSMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
361b0a623aaSMatthew G. Knepley     PetscInt ndof, noff, n;
362b0a623aaSMatthew G. Knepley 
3639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(leafRankSection, p, &ndof));
3649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(leafRankSection, p, &noff));
3659566063dSJacob Faibussowitsch     for (n = 0; n < ndof; ++n) PetscCall(PetscBTSet(neighbors, nranks[noff + n]));
366b0a623aaSMatthew G. Knepley   }
3679566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(leafRanks, &nranks));
368b0a623aaSMatthew G. Knepley   /* Compute leaf-to-root process connectivity */
3693ba16761SJacob Faibussowitsch   for (l = 0; l < numLeaves; ++l) PetscCall(PetscBTSet(neighbors, remotePoints[l].rank));
370b0a623aaSMatthew G. Knepley   /* Calculate edges */
3713ba16761SJacob Faibussowitsch   PetscCall(PetscBTClear(neighbors, rank));
3729371c9d4SSatish Balay   for (proc = 0, numNeighbors = 0; proc < size; ++proc) {
3739371c9d4SSatish Balay     if (PetscBTLookup(neighbors, proc)) ++numNeighbors;
3749371c9d4SSatish Balay   }
3759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numNeighbors, &ranksNew));
3769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numNeighbors, &localPointsNew));
3779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numNeighbors, &remotePointsNew));
3789852e123SBarry Smith   for (proc = 0, n = 0; proc < size; ++proc) {
379b0a623aaSMatthew G. Knepley     if (PetscBTLookup(neighbors, proc)) {
380b0a623aaSMatthew G. Knepley       ranksNew[n]              = proc;
381b0a623aaSMatthew G. Knepley       localPointsNew[n]        = proc;
382b0a623aaSMatthew G. Knepley       remotePointsNew[n].index = rank;
383b0a623aaSMatthew G. Knepley       remotePointsNew[n].rank  = proc;
384b0a623aaSMatthew G. Knepley       ++n;
385b0a623aaSMatthew G. Knepley     }
386b0a623aaSMatthew G. Knepley   }
3879566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&neighbors));
3889566063dSJacob Faibussowitsch   if (processRanks) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), numNeighbors, ranksNew, PETSC_OWN_POINTER, processRanks));
3899566063dSJacob Faibussowitsch   else PetscCall(PetscFree(ranksNew));
390b0a623aaSMatthew G. Knepley   if (sfProcess) {
3919566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess));
3929566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)*sfProcess, "Two-Sided Process SF"));
3939566063dSJacob Faibussowitsch     PetscCall(PetscSFSetFromOptions(*sfProcess));
3949566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(*sfProcess, size, numNeighbors, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER));
395b0a623aaSMatthew G. Knepley   }
3963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
397b0a623aaSMatthew G. Knepley }
398b0a623aaSMatthew G. Knepley 
399b0a623aaSMatthew G. Knepley /*@
400b0a623aaSMatthew G. Knepley   DMPlexDistributeOwnership - Compute owner information for shared points. This basically gets two-sided for an SF.
401b0a623aaSMatthew G. Knepley 
40220f4b53cSBarry Smith   Collective
403b0a623aaSMatthew G. Knepley 
404b0a623aaSMatthew G. Knepley   Input Parameter:
40520f4b53cSBarry Smith . dm - The `DM`
406b0a623aaSMatthew G. Knepley 
407b0a623aaSMatthew G. Knepley   Output Parameters:
408b0a623aaSMatthew G. Knepley + rootSection - The number of leaves for a given root point
409b0a623aaSMatthew G. Knepley . rootrank    - The rank of each edge into the root point
410b0a623aaSMatthew G. Knepley . leafSection - The number of processes sharing a given leaf point
411b0a623aaSMatthew G. Knepley - leafrank    - The rank of each process sharing a leaf point
412b0a623aaSMatthew G. Knepley 
413b0a623aaSMatthew G. Knepley   Level: developer
414b0a623aaSMatthew G. Knepley 
41520f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexCreateOverlapLabel()`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()`
416b0a623aaSMatthew G. Knepley @*/
417d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributeOwnership(DM dm, PetscSection rootSection, IS *rootrank, PetscSection leafSection, IS *leafrank)
418d71ae5a4SJacob Faibussowitsch {
419b0a623aaSMatthew G. Knepley   MPI_Comm        comm;
420b0a623aaSMatthew G. Knepley   PetscSF         sfPoint;
421b0a623aaSMatthew G. Knepley   const PetscInt *rootdegree;
422b0a623aaSMatthew G. Knepley   PetscInt       *myrank, *remoterank;
423b0a623aaSMatthew G. Knepley   PetscInt        pStart, pEnd, p, nedges;
424b0a623aaSMatthew G. Knepley   PetscMPIInt     rank;
425b0a623aaSMatthew G. Knepley 
426b0a623aaSMatthew G. Knepley   PetscFunctionBegin;
4279566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4309566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
431b0a623aaSMatthew G. Knepley   /* Compute number of leaves for each root */
4329566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)rootSection, "Root Section"));
4339566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootSection, pStart, pEnd));
4349566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(sfPoint, &rootdegree));
4359566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(sfPoint, &rootdegree));
4369566063dSJacob Faibussowitsch   for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(rootSection, p, rootdegree[p - pStart]));
4379566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootSection));
438b0a623aaSMatthew G. Knepley   /* Gather rank of each leaf to root */
4399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(rootSection, &nedges));
4409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &myrank));
4419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nedges, &remoterank));
442b0a623aaSMatthew G. Knepley   for (p = 0; p < pEnd - pStart; ++p) myrank[p] = rank;
4439566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherBegin(sfPoint, MPIU_INT, myrank, remoterank));
4449566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherEnd(sfPoint, MPIU_INT, myrank, remoterank));
4459566063dSJacob Faibussowitsch   PetscCall(PetscFree(myrank));
4469566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, nedges, remoterank, PETSC_OWN_POINTER, rootrank));
447b0a623aaSMatthew G. Knepley   /* Distribute remote ranks to leaves */
4489566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)leafSection, "Leaf Section"));
4499566063dSJacob Faibussowitsch   PetscCall(DMPlexDistributeFieldIS(dm, sfPoint, rootSection, *rootrank, leafSection, leafrank));
4503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
451b0a623aaSMatthew G. Knepley }
452b0a623aaSMatthew G. Knepley 
453278397a0SMatthew G. Knepley /*@C
454c506a872SMatthew G. Knepley   DMPlexCreateOverlapLabel - Compute a label indicating what overlap points should be sent to new processes
455b0a623aaSMatthew G. Knepley 
45620f4b53cSBarry Smith   Collective
457b0a623aaSMatthew G. Knepley 
458b0a623aaSMatthew G. Knepley   Input Parameters:
45920f4b53cSBarry Smith + dm          - The `DM`
46024d039d7SMichael Lange . levels      - Number of overlap levels
461b0a623aaSMatthew G. Knepley . rootSection - The number of leaves for a given root point
462b0a623aaSMatthew G. Knepley . rootrank    - The rank of each edge into the root point
463b0a623aaSMatthew G. Knepley . leafSection - The number of processes sharing a given leaf point
464b0a623aaSMatthew G. Knepley - leafrank    - The rank of each process sharing a leaf point
465b0a623aaSMatthew G. Knepley 
466064ec1f3Sprj-   Output Parameter:
46720f4b53cSBarry Smith . ovLabel - `DMLabel` containing remote overlap contributions as point/rank pairings
468b0a623aaSMatthew G. Knepley 
469b0a623aaSMatthew G. Knepley   Level: developer
470b0a623aaSMatthew G. Knepley 
47120f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexCreateOverlapLabelFromLabels()`, `DMPlexGetAdjacency()`, `DMPlexDistributeOwnership()`, `DMPlexDistribute()`
472b0a623aaSMatthew G. Knepley @*/
473d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateOverlapLabel(DM dm, PetscInt levels, PetscSection rootSection, IS rootrank, PetscSection leafSection, IS leafrank, DMLabel *ovLabel)
474d71ae5a4SJacob Faibussowitsch {
475e540f424SMichael Lange   MPI_Comm           comm;
476b0a623aaSMatthew G. Knepley   DMLabel            ovAdjByRank; /* A DMLabel containing all points adjacent to shared points, separated by rank (value in label) */
477874ddda9SLisandro Dalcin   PetscSF            sfPoint;
478b0a623aaSMatthew G. Knepley   const PetscSFNode *remote;
479b0a623aaSMatthew G. Knepley   const PetscInt    *local;
4801fd9873aSMichael Lange   const PetscInt    *nrank, *rrank;
481b0a623aaSMatthew G. Knepley   PetscInt          *adj = NULL;
4821fd9873aSMichael Lange   PetscInt           pStart, pEnd, p, sStart, sEnd, nleaves, l;
4839852e123SBarry Smith   PetscMPIInt        rank, size;
48431bc6364SLisandro Dalcin   PetscBool          flg;
485b0a623aaSMatthew G. Knepley 
486b0a623aaSMatthew G. Knepley   PetscFunctionBegin;
4876ba1a4c7SVaclav Hapla   *ovLabel = NULL;
4889566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4899566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
4909566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4913ba16761SJacob Faibussowitsch   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
4929566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
4939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
494d1674c6dSMatthew Knepley   if (!levels) {
495d1674c6dSMatthew Knepley     /* Add owned points */
4969566063dSJacob Faibussowitsch     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap label", ovLabel));
4979566063dSJacob Faibussowitsch     for (p = pStart; p < pEnd; ++p) PetscCall(DMLabelSetValue(*ovLabel, p, rank));
4983ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
499d1674c6dSMatthew Knepley   }
5009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(leafSection, &sStart, &sEnd));
5019566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote));
5029566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap adjacency", &ovAdjByRank));
503b0a623aaSMatthew G. Knepley   /* Handle leaves: shared with the root point */
504b0a623aaSMatthew G. Knepley   for (l = 0; l < nleaves; ++l) {
505b0a623aaSMatthew G. Knepley     PetscInt adjSize = PETSC_DETERMINE, a;
506b0a623aaSMatthew G. Knepley 
5079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dm, local ? local[l] : l, &adjSize, &adj));
5089566063dSJacob Faibussowitsch     for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remote[l].rank));
509b0a623aaSMatthew G. Knepley   }
5109566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rootrank, &rrank));
5119566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(leafrank, &nrank));
512b0a623aaSMatthew G. Knepley   /* Handle roots */
513b0a623aaSMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
514b0a623aaSMatthew G. Knepley     PetscInt adjSize = PETSC_DETERMINE, neighbors = 0, noff, n, a;
515b0a623aaSMatthew G. Knepley 
516b0a623aaSMatthew G. Knepley     if ((p >= sStart) && (p < sEnd)) {
517b0a623aaSMatthew G. Knepley       /* Some leaves share a root with other leaves on different processes */
5189566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafSection, p, &neighbors));
519b0a623aaSMatthew G. Knepley       if (neighbors) {
5209566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafSection, p, &noff));
5219566063dSJacob Faibussowitsch         PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
522b0a623aaSMatthew G. Knepley         for (n = 0; n < neighbors; ++n) {
523b0a623aaSMatthew G. Knepley           const PetscInt remoteRank = nrank[noff + n];
524b0a623aaSMatthew G. Knepley 
525b0a623aaSMatthew G. Knepley           if (remoteRank == rank) continue;
5269566063dSJacob Faibussowitsch           for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank));
527b0a623aaSMatthew G. Knepley         }
528b0a623aaSMatthew G. Knepley       }
529b0a623aaSMatthew G. Knepley     }
530b0a623aaSMatthew G. Knepley     /* Roots are shared with leaves */
5319566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(rootSection, p, &neighbors));
532b0a623aaSMatthew G. Knepley     if (!neighbors) continue;
5339566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(rootSection, p, &noff));
5349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
535b0a623aaSMatthew G. Knepley     for (n = 0; n < neighbors; ++n) {
536b0a623aaSMatthew G. Knepley       const PetscInt remoteRank = rrank[noff + n];
537b0a623aaSMatthew G. Knepley 
538b0a623aaSMatthew G. Knepley       if (remoteRank == rank) continue;
5399566063dSJacob Faibussowitsch       for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank));
540b0a623aaSMatthew G. Knepley     }
541b0a623aaSMatthew G. Knepley   }
5429566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
5439566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rootrank, &rrank));
5449566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(leafrank, &nrank));
54524d039d7SMichael Lange   /* Add additional overlap levels */
546be200f8dSMichael Lange   for (l = 1; l < levels; l++) {
547be200f8dSMichael Lange     /* Propagate point donations over SF to capture remote connections */
5489566063dSJacob Faibussowitsch     PetscCall(DMPlexPartitionLabelPropagate(dm, ovAdjByRank));
549be200f8dSMichael Lange     /* Add next level of point donations to the label */
5509566063dSJacob Faibussowitsch     PetscCall(DMPlexPartitionLabelAdjacency(dm, ovAdjByRank));
551be200f8dSMichael Lange   }
55226a7d390SMatthew G. Knepley   /* We require the closure in the overlap */
5539566063dSJacob Faibussowitsch   PetscCall(DMPlexPartitionLabelClosure(dm, ovAdjByRank));
5549566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-overlap_view", &flg));
555e540f424SMichael Lange   if (flg) {
556825f8a23SLisandro Dalcin     PetscViewer viewer;
5579566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &viewer));
5589566063dSJacob Faibussowitsch     PetscCall(DMLabelView(ovAdjByRank, viewer));
559b0a623aaSMatthew G. Knepley   }
560874ddda9SLisandro Dalcin   /* Invert sender to receiver label */
5619566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap label", ovLabel));
5629566063dSJacob Faibussowitsch   PetscCall(DMPlexPartitionLabelInvert(dm, ovAdjByRank, NULL, *ovLabel));
563a9f1d5b2SMichael Lange   /* Add owned points, except for shared local points */
5649566063dSJacob Faibussowitsch   for (p = pStart; p < pEnd; ++p) PetscCall(DMLabelSetValue(*ovLabel, p, rank));
565e540f424SMichael Lange   for (l = 0; l < nleaves; ++l) {
5669566063dSJacob Faibussowitsch     PetscCall(DMLabelClearValue(*ovLabel, local[l], rank));
5679566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(*ovLabel, remote[l].index, remote[l].rank));
568e540f424SMichael Lange   }
569e540f424SMichael Lange   /* Clean up */
5709566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&ovAdjByRank));
5713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
572b0a623aaSMatthew G. Knepley }
57370034214SMatthew G. Knepley 
574d71ae5a4SJacob Faibussowitsch static PetscErrorCode HandlePoint_Private(DM dm, PetscInt p, PetscSection section, const PetscInt ranks[], PetscInt numExLabels, const DMLabel exLabel[], const PetscInt exValue[], DMLabel ovAdjByRank)
575d71ae5a4SJacob Faibussowitsch {
576c506a872SMatthew G. Knepley   PetscInt neighbors, el;
577c506a872SMatthew G. Knepley 
578c506a872SMatthew G. Knepley   PetscFunctionBegin;
579c506a872SMatthew G. Knepley   PetscCall(PetscSectionGetDof(section, p, &neighbors));
580c506a872SMatthew G. Knepley   if (neighbors) {
581c506a872SMatthew G. Knepley     PetscInt   *adj     = NULL;
582c506a872SMatthew G. Knepley     PetscInt    adjSize = PETSC_DETERMINE, noff, n, a;
583c506a872SMatthew G. Knepley     PetscMPIInt rank;
584c506a872SMatthew G. Knepley 
585c506a872SMatthew G. Knepley     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
586c506a872SMatthew G. Knepley     PetscCall(PetscSectionGetOffset(section, p, &noff));
587c506a872SMatthew G. Knepley     PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
588c506a872SMatthew G. Knepley     for (n = 0; n < neighbors; ++n) {
589c506a872SMatthew G. Knepley       const PetscInt remoteRank = ranks[noff + n];
590c506a872SMatthew G. Knepley 
591c506a872SMatthew G. Knepley       if (remoteRank == rank) continue;
592c506a872SMatthew G. Knepley       for (a = 0; a < adjSize; ++a) {
593c506a872SMatthew G. Knepley         PetscBool insert = PETSC_TRUE;
594c506a872SMatthew G. Knepley 
595c506a872SMatthew G. Knepley         for (el = 0; el < numExLabels; ++el) {
596c506a872SMatthew G. Knepley           PetscInt exVal;
597c506a872SMatthew G. Knepley           PetscCall(DMLabelGetValue(exLabel[el], adj[a], &exVal));
5989371c9d4SSatish Balay           if (exVal == exValue[el]) {
5999371c9d4SSatish Balay             insert = PETSC_FALSE;
6009371c9d4SSatish Balay             break;
6019371c9d4SSatish Balay           }
602c506a872SMatthew G. Knepley         }
603c506a872SMatthew G. Knepley         if (insert) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank));
604c506a872SMatthew G. Knepley       }
605c506a872SMatthew G. Knepley     }
606f88a03deSMatthew G. Knepley     PetscCall(PetscFree(adj));
607c506a872SMatthew G. Knepley   }
6083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
609c506a872SMatthew G. Knepley }
610c506a872SMatthew G. Knepley 
611c506a872SMatthew G. Knepley /*@C
612c506a872SMatthew G. Knepley   DMPlexCreateOverlapLabelFromLabels - Compute a label indicating what overlap points should be sent to new processes
613c506a872SMatthew G. Knepley 
61420f4b53cSBarry Smith   Collective
615c506a872SMatthew G. Knepley 
616c506a872SMatthew G. Knepley   Input Parameters:
61720f4b53cSBarry Smith + dm          - The `DM`
618c506a872SMatthew G. Knepley . numLabels   - The number of labels to draw candidate points from
619c506a872SMatthew G. Knepley . label       - An array of labels containing candidate points
620c506a872SMatthew G. Knepley . value       - An array of label values marking the candidate points
621c506a872SMatthew G. Knepley . numExLabels - The number of labels to use for exclusion
62220f4b53cSBarry Smith . exLabel     - An array of labels indicating points to be excluded, or `NULL`
62320f4b53cSBarry Smith . exValue     - An array of label values to be excluded, or `NULL`
624c506a872SMatthew G. Knepley . rootSection - The number of leaves for a given root point
625c506a872SMatthew G. Knepley . rootrank    - The rank of each edge into the root point
626c506a872SMatthew G. Knepley . leafSection - The number of processes sharing a given leaf point
627c506a872SMatthew G. Knepley - leafrank    - The rank of each process sharing a leaf point
628c506a872SMatthew G. Knepley 
629c506a872SMatthew G. Knepley   Output Parameter:
63020f4b53cSBarry Smith . ovLabel - `DMLabel` containing remote overlap contributions as point/rank pairings
63120f4b53cSBarry Smith 
63220f4b53cSBarry Smith   Level: developer
633c506a872SMatthew G. Knepley 
634c506a872SMatthew G. Knepley   Note:
635c506a872SMatthew G. Knepley   The candidate points are only added to the overlap if they are adjacent to a shared point
636c506a872SMatthew G. Knepley 
63720f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexCreateOverlapLabel()`, `DMPlexGetAdjacency()`, `DMPlexDistributeOwnership()`, `DMPlexDistribute()`
638c506a872SMatthew G. Knepley @*/
639d71ae5a4SJacob Faibussowitsch 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)
640d71ae5a4SJacob Faibussowitsch {
641c506a872SMatthew G. Knepley   MPI_Comm           comm;
642c506a872SMatthew G. Knepley   DMLabel            ovAdjByRank; /* A DMLabel containing all points adjacent to shared points, separated by rank (value in label) */
643c506a872SMatthew G. Knepley   PetscSF            sfPoint;
644c506a872SMatthew G. Knepley   const PetscSFNode *remote;
645c506a872SMatthew G. Knepley   const PetscInt    *local;
646c506a872SMatthew G. Knepley   const PetscInt    *nrank, *rrank;
647c506a872SMatthew G. Knepley   PetscInt          *adj = NULL;
648c506a872SMatthew G. Knepley   PetscInt           pStart, pEnd, p, sStart, sEnd, nleaves, l, el;
649c506a872SMatthew G. Knepley   PetscMPIInt        rank, size;
650c506a872SMatthew G. Knepley   PetscBool          flg;
651c506a872SMatthew G. Knepley 
652c506a872SMatthew G. Knepley   PetscFunctionBegin;
653c506a872SMatthew G. Knepley   *ovLabel = NULL;
654c506a872SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
655c506a872SMatthew G. Knepley   PetscCallMPI(MPI_Comm_size(comm, &size));
656c506a872SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
6573ba16761SJacob Faibussowitsch   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
658c506a872SMatthew G. Knepley   PetscCall(DMGetPointSF(dm, &sfPoint));
659c506a872SMatthew G. Knepley   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
660c506a872SMatthew G. Knepley   PetscCall(PetscSectionGetChart(leafSection, &sStart, &sEnd));
661c506a872SMatthew G. Knepley   PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote));
662c506a872SMatthew G. Knepley   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap adjacency", &ovAdjByRank));
663c506a872SMatthew G. Knepley   PetscCall(ISGetIndices(rootrank, &rrank));
664c506a872SMatthew G. Knepley   PetscCall(ISGetIndices(leafrank, &nrank));
665c506a872SMatthew G. Knepley   for (l = 0; l < numLabels; ++l) {
666c506a872SMatthew G. Knepley     IS              valIS;
667c506a872SMatthew G. Knepley     const PetscInt *points;
668c506a872SMatthew G. Knepley     PetscInt        n;
669c506a872SMatthew G. Knepley 
670c506a872SMatthew G. Knepley     PetscCall(DMLabelGetStratumIS(label[l], value[l], &valIS));
671c506a872SMatthew G. Knepley     if (!valIS) continue;
672c506a872SMatthew G. Knepley     PetscCall(ISGetIndices(valIS, &points));
673c506a872SMatthew G. Knepley     PetscCall(ISGetLocalSize(valIS, &n));
674c506a872SMatthew G. Knepley     for (PetscInt i = 0; i < n; ++i) {
675c506a872SMatthew G. Knepley       const PetscInt p = points[i];
676c506a872SMatthew G. Knepley 
677c506a872SMatthew G. Knepley       if ((p >= sStart) && (p < sEnd)) {
678c506a872SMatthew G. Knepley         PetscInt loc, adjSize = PETSC_DETERMINE;
679c506a872SMatthew G. Knepley 
680c506a872SMatthew G. Knepley         /* Handle leaves: shared with the root point */
681c506a872SMatthew G. Knepley         if (local) PetscCall(PetscFindInt(p, nleaves, local, &loc));
682c506a872SMatthew G. Knepley         else loc = (p >= 0 && p < nleaves) ? p : -1;
683c506a872SMatthew G. Knepley         if (loc >= 0) {
684c506a872SMatthew G. Knepley           const PetscInt remoteRank = remote[loc].rank;
685c506a872SMatthew G. Knepley 
686c506a872SMatthew G. Knepley           PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
687c506a872SMatthew G. Knepley           for (PetscInt a = 0; a < adjSize; ++a) {
688c506a872SMatthew G. Knepley             PetscBool insert = PETSC_TRUE;
689c506a872SMatthew G. Knepley 
690c506a872SMatthew G. Knepley             for (el = 0; el < numExLabels; ++el) {
691c506a872SMatthew G. Knepley               PetscInt exVal;
692c506a872SMatthew G. Knepley               PetscCall(DMLabelGetValue(exLabel[el], adj[a], &exVal));
6939371c9d4SSatish Balay               if (exVal == exValue[el]) {
6949371c9d4SSatish Balay                 insert = PETSC_FALSE;
6959371c9d4SSatish Balay                 break;
6969371c9d4SSatish Balay               }
697c506a872SMatthew G. Knepley             }
698c506a872SMatthew G. Knepley             if (insert) PetscCall(DMLabelSetValue(ovAdjByRank, adj[a], remoteRank));
699c506a872SMatthew G. Knepley           }
700c506a872SMatthew G. Knepley         }
701c506a872SMatthew G. Knepley         /* Some leaves share a root with other leaves on different processes */
7023ba16761SJacob Faibussowitsch         PetscCall(HandlePoint_Private(dm, p, leafSection, nrank, numExLabels, exLabel, exValue, ovAdjByRank));
703c506a872SMatthew G. Knepley       }
704c506a872SMatthew G. Knepley       /* Roots are shared with leaves */
7053ba16761SJacob Faibussowitsch       PetscCall(HandlePoint_Private(dm, p, rootSection, rrank, numExLabels, exLabel, exValue, ovAdjByRank));
706c506a872SMatthew G. Knepley     }
707c506a872SMatthew G. Knepley     PetscCall(ISRestoreIndices(valIS, &points));
708c506a872SMatthew G. Knepley     PetscCall(ISDestroy(&valIS));
709c506a872SMatthew G. Knepley   }
710c506a872SMatthew G. Knepley   PetscCall(PetscFree(adj));
711c506a872SMatthew G. Knepley   PetscCall(ISRestoreIndices(rootrank, &rrank));
712c506a872SMatthew G. Knepley   PetscCall(ISRestoreIndices(leafrank, &nrank));
713c506a872SMatthew G. Knepley   /* We require the closure in the overlap */
714c506a872SMatthew G. Knepley   PetscCall(DMPlexPartitionLabelClosure(dm, ovAdjByRank));
715c506a872SMatthew G. Knepley   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-overlap_view", &flg));
716c506a872SMatthew G. Knepley   if (flg) {
717c506a872SMatthew G. Knepley     PetscViewer viewer;
718c506a872SMatthew G. Knepley     PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &viewer));
719c506a872SMatthew G. Knepley     PetscCall(DMLabelView(ovAdjByRank, viewer));
720c506a872SMatthew G. Knepley   }
721c506a872SMatthew G. Knepley   /* Invert sender to receiver label */
722c506a872SMatthew G. Knepley   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Overlap label", ovLabel));
723c506a872SMatthew G. Knepley   PetscCall(DMPlexPartitionLabelInvert(dm, ovAdjByRank, NULL, *ovLabel));
724c506a872SMatthew G. Knepley   /* Add owned points, except for shared local points */
725c506a872SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) PetscCall(DMLabelSetValue(*ovLabel, p, rank));
726c506a872SMatthew G. Knepley   for (l = 0; l < nleaves; ++l) {
727c506a872SMatthew G. Knepley     PetscCall(DMLabelClearValue(*ovLabel, local[l], rank));
728c506a872SMatthew G. Knepley     PetscCall(DMLabelSetValue(*ovLabel, remote[l].index, remote[l].rank));
729c506a872SMatthew G. Knepley   }
730c506a872SMatthew G. Knepley   /* Clean up */
731c506a872SMatthew G. Knepley   PetscCall(DMLabelDestroy(&ovAdjByRank));
7323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
733c506a872SMatthew G. Knepley }
734c506a872SMatthew G. Knepley 
73524cc2ca5SMatthew G. Knepley /*@C
73620f4b53cSBarry Smith   DMPlexCreateOverlapMigrationSF - Create a `PetscSF` describing the new mesh distribution to make the overlap described by the input `PetscSF`
73724cc2ca5SMatthew G. Knepley 
73820f4b53cSBarry Smith   Collective
73924cc2ca5SMatthew G. Knepley 
74024cc2ca5SMatthew G. Knepley   Input Parameters:
74120f4b53cSBarry Smith + dm        - The `DM`
74220f4b53cSBarry Smith - overlapSF - The `PetscSF` mapping ghost points in overlap to owner points on other processes
74324cc2ca5SMatthew G. Knepley 
744064ec1f3Sprj-   Output Parameter:
74520f4b53cSBarry Smith . migrationSF - A `PetscSF` that maps original points in old locations to points in new locations
74624cc2ca5SMatthew G. Knepley 
74724cc2ca5SMatthew G. Knepley   Level: developer
74824cc2ca5SMatthew G. Knepley 
74920f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexCreateOverlapLabel()`, `DMPlexDistributeOverlap()`, `DMPlexDistribute()`
75024cc2ca5SMatthew G. Knepley @*/
751d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateOverlapMigrationSF(DM dm, PetscSF overlapSF, PetscSF *migrationSF)
752d71ae5a4SJacob Faibussowitsch {
75346f9b1c3SMichael Lange   MPI_Comm           comm;
7549852e123SBarry Smith   PetscMPIInt        rank, size;
75546f9b1c3SMichael Lange   PetscInt           d, dim, p, pStart, pEnd, nroots, nleaves, newLeaves, point, numSharedPoints;
75646f9b1c3SMichael Lange   PetscInt          *pointDepths, *remoteDepths, *ilocal;
75746f9b1c3SMichael Lange   PetscInt          *depthRecv, *depthShift, *depthIdx;
75846f9b1c3SMichael Lange   PetscSFNode       *iremote;
75946f9b1c3SMichael Lange   PetscSF            pointSF;
76046f9b1c3SMichael Lange   const PetscInt    *sharedLocal;
76146f9b1c3SMichael Lange   const PetscSFNode *overlapRemote, *sharedRemote;
76246f9b1c3SMichael Lange 
76346f9b1c3SMichael Lange   PetscFunctionBegin;
76446f9b1c3SMichael Lange   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7659566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
7669566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
7689566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
76946f9b1c3SMichael Lange 
77046f9b1c3SMichael Lange   /* Before building the migration SF we need to know the new stratum offsets */
7719566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(overlapSF, &nroots, &nleaves, NULL, &overlapRemote));
7729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nroots, &pointDepths, nleaves, &remoteDepths));
77346f9b1c3SMichael Lange   for (d = 0; d < dim + 1; d++) {
7749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
77546f9b1c3SMichael Lange     for (p = pStart; p < pEnd; p++) pointDepths[p] = d;
77646f9b1c3SMichael Lange   }
77746f9b1c3SMichael Lange   for (p = 0; p < nleaves; p++) remoteDepths[p] = -1;
7789566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(overlapSF, MPIU_INT, pointDepths, remoteDepths, MPI_REPLACE));
7799566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(overlapSF, MPIU_INT, pointDepths, remoteDepths, MPI_REPLACE));
78046f9b1c3SMichael Lange 
7812d4ee042Sprj-   /* Count received points in each stratum and compute the internal strata shift */
7829566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim + 1, &depthRecv, dim + 1, &depthShift, dim + 1, &depthIdx));
78346f9b1c3SMichael Lange   for (d = 0; d < dim + 1; d++) depthRecv[d] = 0;
78446f9b1c3SMichael Lange   for (p = 0; p < nleaves; p++) depthRecv[remoteDepths[p]]++;
78546f9b1c3SMichael Lange   depthShift[dim] = 0;
78646f9b1c3SMichael Lange   for (d = 0; d < dim; d++) depthShift[d] = depthRecv[dim];
78746f9b1c3SMichael Lange   for (d = 1; d < dim; d++) depthShift[d] += depthRecv[0];
78846f9b1c3SMichael Lange   for (d = dim - 2; d > 0; d--) depthShift[d] += depthRecv[d + 1];
78946f9b1c3SMichael Lange   for (d = 0; d < dim + 1; d++) {
7909566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
79146f9b1c3SMichael Lange     depthIdx[d] = pStart + depthShift[d];
79246f9b1c3SMichael Lange   }
79346f9b1c3SMichael Lange 
79446f9b1c3SMichael Lange   /* Form the overlap SF build an SF that describes the full overlap migration SF */
7959566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
79646f9b1c3SMichael Lange   newLeaves = pEnd - pStart + nleaves;
7979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(newLeaves, &ilocal));
7989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(newLeaves, &iremote));
79946f9b1c3SMichael Lange   /* First map local points to themselves */
80046f9b1c3SMichael Lange   for (d = 0; d < dim + 1; d++) {
8019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
80246f9b1c3SMichael Lange     for (p = pStart; p < pEnd; p++) {
80346f9b1c3SMichael Lange       point                = p + depthShift[d];
80446f9b1c3SMichael Lange       ilocal[point]        = point;
80546f9b1c3SMichael Lange       iremote[point].index = p;
80646f9b1c3SMichael Lange       iremote[point].rank  = rank;
80746f9b1c3SMichael Lange       depthIdx[d]++;
80846f9b1c3SMichael Lange     }
80946f9b1c3SMichael Lange   }
81046f9b1c3SMichael Lange 
81146f9b1c3SMichael Lange   /* Add in the remote roots for currently shared points */
8129566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &pointSF));
8139566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(pointSF, NULL, &numSharedPoints, &sharedLocal, &sharedRemote));
81446f9b1c3SMichael Lange   for (d = 0; d < dim + 1; d++) {
8159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
81646f9b1c3SMichael Lange     for (p = 0; p < numSharedPoints; p++) {
81746f9b1c3SMichael Lange       if (pStart <= sharedLocal[p] && sharedLocal[p] < pEnd) {
81846f9b1c3SMichael Lange         point                = sharedLocal[p] + depthShift[d];
81946f9b1c3SMichael Lange         iremote[point].index = sharedRemote[p].index;
82046f9b1c3SMichael Lange         iremote[point].rank  = sharedRemote[p].rank;
82146f9b1c3SMichael Lange       }
82246f9b1c3SMichael Lange     }
82346f9b1c3SMichael Lange   }
82446f9b1c3SMichael Lange 
82546f9b1c3SMichael Lange   /* Now add the incoming overlap points */
82646f9b1c3SMichael Lange   for (p = 0; p < nleaves; p++) {
82746f9b1c3SMichael Lange     point                = depthIdx[remoteDepths[p]];
82846f9b1c3SMichael Lange     ilocal[point]        = point;
82946f9b1c3SMichael Lange     iremote[point].index = overlapRemote[p].index;
83046f9b1c3SMichael Lange     iremote[point].rank  = overlapRemote[p].rank;
83146f9b1c3SMichael Lange     depthIdx[remoteDepths[p]]++;
83246f9b1c3SMichael Lange   }
8339566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointDepths, remoteDepths));
83446f9b1c3SMichael Lange 
8359566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, migrationSF));
8369566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*migrationSF, "Overlap Migration SF"));
8379566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(*migrationSF));
8389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8399566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*migrationSF, pEnd - pStart, newLeaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
84046f9b1c3SMichael Lange 
8419566063dSJacob Faibussowitsch   PetscCall(PetscFree3(depthRecv, depthShift, depthIdx));
8423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
84370034214SMatthew G. Knepley }
84470034214SMatthew G. Knepley 
845a9f1d5b2SMichael Lange /*@
846f0e73a3dSToby Isaac   DMPlexStratifyMigrationSF - Rearrange the leaves of a migration sf for stratification.
847a9f1d5b2SMichael Lange 
848064ec1f3Sprj-   Input Parameters:
849a9f1d5b2SMichael Lange + dm - The DM
850a9f1d5b2SMichael Lange - sf - A star forest with non-ordered leaves, usually defining a DM point migration
851a9f1d5b2SMichael Lange 
852a9f1d5b2SMichael Lange   Output Parameter:
853a9f1d5b2SMichael Lange . migrationSF - A star forest with added leaf indirection that ensures the resulting DM is stratified
854a9f1d5b2SMichael Lange 
85520f4b53cSBarry Smith   Level: developer
85620f4b53cSBarry Smith 
857412e9a14SMatthew G. Knepley   Note:
858412e9a14SMatthew G. Knepley   This lexicographically sorts by (depth, cellType)
859412e9a14SMatthew G. Knepley 
86020f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()`
861a9f1d5b2SMichael Lange @*/
862d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexStratifyMigrationSF(DM dm, PetscSF sf, PetscSF *migrationSF)
863d71ae5a4SJacob Faibussowitsch {
864a9f1d5b2SMichael Lange   MPI_Comm           comm;
8659852e123SBarry Smith   PetscMPIInt        rank, size;
866412e9a14SMatthew G. Knepley   PetscInt           d, ldepth, depth, dim, p, pStart, pEnd, nroots, nleaves;
867412e9a14SMatthew G. Knepley   PetscSFNode       *pointDepths, *remoteDepths;
868412e9a14SMatthew G. Knepley   PetscInt          *ilocal;
869a9f1d5b2SMichael Lange   PetscInt          *depthRecv, *depthShift, *depthIdx;
870412e9a14SMatthew G. Knepley   PetscInt          *ctRecv, *ctShift, *ctIdx;
871a9f1d5b2SMichael Lange   const PetscSFNode *iremote;
872a9f1d5b2SMichael Lange 
873a9f1d5b2SMichael Lange   PetscFunctionBegin;
874a9f1d5b2SMichael Lange   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8759566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
8769566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
8779566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
8789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &ldepth));
8799566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
8801c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, comm));
88163a3b9bcSJacob Faibussowitsch   PetscCheck(!(ldepth >= 0) || !(depth != ldepth), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %" PetscInt_FMT " != %" PetscInt_FMT, ldepth, depth);
8829566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_PartStratSF, dm, 0, 0, 0));
883a9f1d5b2SMichael Lange 
884a9f1d5b2SMichael Lange   /* Before building the migration SF we need to know the new stratum offsets */
8859566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, NULL, &iremote));
8869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nroots, &pointDepths, nleaves, &remoteDepths));
8877fab53ddSMatthew G. Knepley   for (d = 0; d < depth + 1; ++d) {
8889566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
889f0e73a3dSToby Isaac     for (p = pStart; p < pEnd; ++p) {
890412e9a14SMatthew G. Knepley       DMPolytopeType ct;
891f0e73a3dSToby Isaac 
8929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, p, &ct));
893412e9a14SMatthew G. Knepley       pointDepths[p].index = d;
894412e9a14SMatthew G. Knepley       pointDepths[p].rank  = ct;
895f0e73a3dSToby Isaac     }
896412e9a14SMatthew G. Knepley   }
8979371c9d4SSatish Balay   for (p = 0; p < nleaves; ++p) {
8989371c9d4SSatish Balay     remoteDepths[p].index = -1;
8999371c9d4SSatish Balay     remoteDepths[p].rank  = -1;
9009371c9d4SSatish Balay   }
9019566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, pointDepths, remoteDepths, MPI_REPLACE));
9029566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, pointDepths, remoteDepths, MPI_REPLACE));
903412e9a14SMatthew G. Knepley   /* Count received points in each stratum and compute the internal strata shift */
9049566063dSJacob Faibussowitsch   PetscCall(PetscCalloc6(depth + 1, &depthRecv, depth + 1, &depthShift, depth + 1, &depthIdx, DM_NUM_POLYTOPES, &ctRecv, DM_NUM_POLYTOPES, &ctShift, DM_NUM_POLYTOPES, &ctIdx));
905412e9a14SMatthew G. Knepley   for (p = 0; p < nleaves; ++p) {
906412e9a14SMatthew G. Knepley     if (remoteDepths[p].rank < 0) {
907412e9a14SMatthew G. Knepley       ++depthRecv[remoteDepths[p].index];
908412e9a14SMatthew G. Knepley     } else {
909412e9a14SMatthew G. Knepley       ++ctRecv[remoteDepths[p].rank];
910412e9a14SMatthew G. Knepley     }
911412e9a14SMatthew G. Knepley   }
912412e9a14SMatthew G. Knepley   {
913412e9a14SMatthew G. Knepley     PetscInt depths[4], dims[4], shift = 0, i, c;
914412e9a14SMatthew G. Knepley 
9158238f61eSMatthew G. Knepley     /* Cells (depth), Vertices (0), Faces (depth-1), Edges (1)
916476787b7SMatthew G. Knepley          Consider DM_POLYTOPE_FV_GHOST, DM_POLYTOPE_INTERIOR_GHOST and DM_POLYTOPE_UNKNOWN_CELL as cells
9178238f61eSMatthew G. Knepley      */
9189371c9d4SSatish Balay     depths[0] = depth;
9199371c9d4SSatish Balay     depths[1] = 0;
9209371c9d4SSatish Balay     depths[2] = depth - 1;
9219371c9d4SSatish Balay     depths[3] = 1;
9229371c9d4SSatish Balay     dims[0]   = dim;
9239371c9d4SSatish Balay     dims[1]   = 0;
9249371c9d4SSatish Balay     dims[2]   = dim - 1;
9259371c9d4SSatish Balay     dims[3]   = 1;
926412e9a14SMatthew G. Knepley     for (i = 0; i <= depth; ++i) {
927412e9a14SMatthew G. Knepley       const PetscInt dep = depths[i];
928412e9a14SMatthew G. Knepley       const PetscInt dim = dims[i];
929412e9a14SMatthew G. Knepley 
930412e9a14SMatthew G. Knepley       for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
931476787b7SMatthew G. Knepley         if (DMPolytopeTypeGetDim((DMPolytopeType)c) != dim && !(i == 0 && (c == DM_POLYTOPE_FV_GHOST || c == DM_POLYTOPE_INTERIOR_GHOST || c == DM_POLYTOPE_UNKNOWN_CELL))) continue;
932412e9a14SMatthew G. Knepley         ctShift[c] = shift;
933412e9a14SMatthew G. Knepley         shift += ctRecv[c];
934412e9a14SMatthew G. Knepley       }
935412e9a14SMatthew G. Knepley       depthShift[dep] = shift;
936412e9a14SMatthew G. Knepley       shift += depthRecv[dep];
937412e9a14SMatthew G. Knepley     }
938412e9a14SMatthew G. Knepley     for (c = 0; c < DM_NUM_POLYTOPES; ++c) {
939412e9a14SMatthew G. Knepley       const PetscInt ctDim = DMPolytopeTypeGetDim((DMPolytopeType)c);
940412e9a14SMatthew G. Knepley 
941476787b7SMatthew G. Knepley       if ((ctDim < 0 || ctDim > dim) && (c != DM_POLYTOPE_FV_GHOST && c != DM_POLYTOPE_INTERIOR_GHOST && c != DM_POLYTOPE_UNKNOWN_CELL)) {
942412e9a14SMatthew G. Knepley         ctShift[c] = shift;
943412e9a14SMatthew G. Knepley         shift += ctRecv[c];
944412e9a14SMatthew G. Knepley       }
945412e9a14SMatthew G. Knepley     }
946412e9a14SMatthew G. Knepley   }
947a9f1d5b2SMichael Lange   /* Derive a new local permutation based on stratified indices */
9489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nleaves, &ilocal));
9497fab53ddSMatthew G. Knepley   for (p = 0; p < nleaves; ++p) {
950412e9a14SMatthew G. Knepley     const PetscInt       dep = remoteDepths[p].index;
951412e9a14SMatthew G. Knepley     const DMPolytopeType ct  = (DMPolytopeType)remoteDepths[p].rank;
9527fab53ddSMatthew G. Knepley 
953412e9a14SMatthew G. Knepley     if ((PetscInt)ct < 0) {
9547fab53ddSMatthew G. Knepley       ilocal[p] = depthShift[dep] + depthIdx[dep];
955412e9a14SMatthew G. Knepley       ++depthIdx[dep];
956412e9a14SMatthew G. Knepley     } else {
957412e9a14SMatthew G. Knepley       ilocal[p] = ctShift[ct] + ctIdx[ct];
958412e9a14SMatthew G. Knepley       ++ctIdx[ct];
959412e9a14SMatthew G. Knepley     }
960a9f1d5b2SMichael Lange   }
9619566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, migrationSF));
9629566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*migrationSF, "Migration SF"));
9639566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*migrationSF, nroots, nleaves, ilocal, PETSC_OWN_POINTER, (PetscSFNode *)iremote, PETSC_COPY_VALUES));
9649566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pointDepths, remoteDepths));
9659566063dSJacob Faibussowitsch   PetscCall(PetscFree6(depthRecv, depthShift, depthIdx, ctRecv, ctShift, ctIdx));
9669566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_PartStratSF, dm, 0, 0, 0));
9673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
968a9f1d5b2SMichael Lange }
969a9f1d5b2SMichael Lange 
97070034214SMatthew G. Knepley /*@
97120f4b53cSBarry Smith   DMPlexDistributeField - Distribute field data to match a given `PetscSF`, usually the `PetscSF` from mesh distribution
97270034214SMatthew G. Knepley 
97320f4b53cSBarry Smith   Collective
97470034214SMatthew G. Knepley 
97570034214SMatthew G. Knepley   Input Parameters:
97620f4b53cSBarry Smith + dm              - The `DMPLEX` object
97720f4b53cSBarry Smith . pointSF         - The `PetscSF` describing the communication pattern
97820f4b53cSBarry Smith . originalSection - The `PetscSection` for existing data layout
979cb15cd0eSMatthew G. Knepley - originalVec     - The existing data in a local vector
98070034214SMatthew G. Knepley 
98170034214SMatthew G. Knepley   Output Parameters:
98220f4b53cSBarry Smith + newSection - The `PetscSF` describing the new data layout
983cb15cd0eSMatthew G. Knepley - newVec     - The new data in a local vector
98470034214SMatthew G. Knepley 
98570034214SMatthew G. Knepley   Level: developer
98670034214SMatthew G. Knepley 
98720f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexDistributeFieldIS()`, `DMPlexDistributeData()`
98870034214SMatthew G. Knepley @*/
989d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
990d71ae5a4SJacob Faibussowitsch {
99170034214SMatthew G. Knepley   PetscSF      fieldSF;
99270034214SMatthew G. Knepley   PetscInt    *remoteOffsets, fieldSize;
99370034214SMatthew G. Knepley   PetscScalar *originalValues, *newValues;
99470034214SMatthew G. Knepley 
99570034214SMatthew G. Knepley   PetscFunctionBegin;
9969566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_DistributeField, dm, 0, 0, 0));
9979566063dSJacob Faibussowitsch   PetscCall(PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection));
99870034214SMatthew G. Knepley 
9999566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSection, &fieldSize));
10009566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(newVec, fieldSize, PETSC_DETERMINE));
10019566063dSJacob Faibussowitsch   PetscCall(VecSetType(newVec, dm->vectype));
100270034214SMatthew G. Knepley 
10039566063dSJacob Faibussowitsch   PetscCall(VecGetArray(originalVec, &originalValues));
10049566063dSJacob Faibussowitsch   PetscCall(VecGetArray(newVec, &newValues));
10059566063dSJacob Faibussowitsch   PetscCall(PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF));
10069566063dSJacob Faibussowitsch   PetscCall(PetscFree(remoteOffsets));
10079566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues, MPI_REPLACE));
10089566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues, MPI_REPLACE));
10099566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&fieldSF));
10109566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(newVec, &newValues));
10119566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(originalVec, &originalValues));
10129566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_DistributeField, dm, 0, 0, 0));
10133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
101470034214SMatthew G. Knepley }
101570034214SMatthew G. Knepley 
101670034214SMatthew G. Knepley /*@
101720f4b53cSBarry Smith   DMPlexDistributeFieldIS - Distribute field data to match a given `PetscSF`, usually the `PetscSF` from mesh distribution
101870034214SMatthew G. Knepley 
101920f4b53cSBarry Smith   Collective
102070034214SMatthew G. Knepley 
102170034214SMatthew G. Knepley   Input Parameters:
102220f4b53cSBarry Smith + dm              - The `DMPLEX` object
102320f4b53cSBarry Smith . pointSF         - The `PetscSF` describing the communication pattern
102420f4b53cSBarry Smith . originalSection - The `PetscSection` for existing data layout
102570034214SMatthew G. Knepley - originalIS      - The existing data
102670034214SMatthew G. Knepley 
102770034214SMatthew G. Knepley   Output Parameters:
102820f4b53cSBarry Smith + newSection - The `PetscSF` describing the new data layout
102970034214SMatthew G. Knepley - newIS      - The new data
103070034214SMatthew G. Knepley 
103170034214SMatthew G. Knepley   Level: developer
103270034214SMatthew G. Knepley 
103320f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexDistributeData()`
103470034214SMatthew G. Knepley @*/
1035d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributeFieldIS(DM dm, PetscSF pointSF, PetscSection originalSection, IS originalIS, PetscSection newSection, IS *newIS)
1036d71ae5a4SJacob Faibussowitsch {
103770034214SMatthew G. Knepley   PetscSF         fieldSF;
103870034214SMatthew G. Knepley   PetscInt       *newValues, *remoteOffsets, fieldSize;
103970034214SMatthew G. Knepley   const PetscInt *originalValues;
104070034214SMatthew G. Knepley 
104170034214SMatthew G. Knepley   PetscFunctionBegin;
10429566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_DistributeField, dm, 0, 0, 0));
10439566063dSJacob Faibussowitsch   PetscCall(PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection));
104470034214SMatthew G. Knepley 
10459566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSection, &fieldSize));
10469566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(fieldSize, &newValues));
104770034214SMatthew G. Knepley 
10489566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(originalIS, &originalValues));
10499566063dSJacob Faibussowitsch   PetscCall(PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF));
10509566063dSJacob Faibussowitsch   PetscCall(PetscFree(remoteOffsets));
10519566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(fieldSF, MPIU_INT, (PetscInt *)originalValues, newValues, MPI_REPLACE));
10529566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(fieldSF, MPIU_INT, (PetscInt *)originalValues, newValues, MPI_REPLACE));
10539566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&fieldSF));
10549566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(originalIS, &originalValues));
10559566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pointSF), fieldSize, newValues, PETSC_OWN_POINTER, newIS));
10569566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_DistributeField, dm, 0, 0, 0));
10573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
105870034214SMatthew G. Knepley }
105970034214SMatthew G. Knepley 
106070034214SMatthew G. Knepley /*@
106120f4b53cSBarry Smith   DMPlexDistributeData - Distribute field data to match a given `PetscSF`, usually the `PetscSF` from mesh distribution
106270034214SMatthew G. Knepley 
106320f4b53cSBarry Smith   Collective
106470034214SMatthew G. Knepley 
106570034214SMatthew G. Knepley   Input Parameters:
106620f4b53cSBarry Smith + dm              - The `DMPLEX` object
106720f4b53cSBarry Smith . pointSF         - The `PetscSF` describing the communication pattern
106820f4b53cSBarry Smith . originalSection - The `PetscSection` for existing data layout
106970034214SMatthew G. Knepley . datatype        - The type of data
107070034214SMatthew G. Knepley - originalData    - The existing data
107170034214SMatthew G. Knepley 
107270034214SMatthew G. Knepley   Output Parameters:
107320f4b53cSBarry Smith + newSection - The `PetscSection` describing the new data layout
107470034214SMatthew G. Knepley - newData    - The new data
107570034214SMatthew G. Knepley 
107670034214SMatthew G. Knepley   Level: developer
107770034214SMatthew G. Knepley 
107820f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexDistributeField()`
107970034214SMatthew G. Knepley @*/
1080d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributeData(DM dm, PetscSF pointSF, PetscSection originalSection, MPI_Datatype datatype, void *originalData, PetscSection newSection, void **newData)
1081d71ae5a4SJacob Faibussowitsch {
108270034214SMatthew G. Knepley   PetscSF     fieldSF;
108370034214SMatthew G. Knepley   PetscInt   *remoteOffsets, fieldSize;
108470034214SMatthew G. Knepley   PetscMPIInt dataSize;
108570034214SMatthew G. Knepley 
108670034214SMatthew G. Knepley   PetscFunctionBegin;
10879566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_DistributeData, dm, 0, 0, 0));
10889566063dSJacob Faibussowitsch   PetscCall(PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection));
108970034214SMatthew G. Knepley 
10909566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSection, &fieldSize));
10919566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_size(datatype, &dataSize));
10929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc(fieldSize * dataSize, newData));
109370034214SMatthew G. Knepley 
10949566063dSJacob Faibussowitsch   PetscCall(PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF));
10959566063dSJacob Faibussowitsch   PetscCall(PetscFree(remoteOffsets));
10969566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(fieldSF, datatype, originalData, *newData, MPI_REPLACE));
10979566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(fieldSF, datatype, originalData, *newData, MPI_REPLACE));
10989566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&fieldSF));
10999566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_DistributeData, dm, 0, 0, 0));
11003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
110170034214SMatthew G. Knepley }
110270034214SMatthew G. Knepley 
1103d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDistributeCones(DM dm, PetscSF migrationSF, ISLocalToGlobalMapping original, ISLocalToGlobalMapping renumbering, DM dmParallel)
1104d71ae5a4SJacob Faibussowitsch {
1105cc71bff1SMichael Lange   DM_Plex     *pmesh = (DM_Plex *)(dmParallel)->data;
1106cc71bff1SMichael Lange   MPI_Comm     comm;
1107cc71bff1SMichael Lange   PetscSF      coneSF;
1108cc71bff1SMichael Lange   PetscSection originalConeSection, newConeSection;
1109ac04eaf7SToby Isaac   PetscInt    *remoteOffsets, *cones, *globCones, *newCones, newConesSize;
1110cc71bff1SMichael Lange   PetscBool    flg;
1111cc71bff1SMichael Lange 
1112cc71bff1SMichael Lange   PetscFunctionBegin;
1113cc71bff1SMichael Lange   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
11140c86c063SLisandro Dalcin   PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 5);
11159566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_DistributeCones, dm, 0, 0, 0));
1116cc71bff1SMichael Lange   /* Distribute cone section */
11179566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
11189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dm, &originalConeSection));
11199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSection(dmParallel, &newConeSection));
11209566063dSJacob Faibussowitsch   PetscCall(PetscSFDistributeSection(migrationSF, originalConeSection, &remoteOffsets, newConeSection));
11219566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dmParallel));
1122cc71bff1SMichael Lange   /* Communicate and renumber cones */
11239566063dSJacob Faibussowitsch   PetscCall(PetscSFCreateSectionSF(migrationSF, originalConeSection, remoteOffsets, newConeSection, &coneSF));
11249566063dSJacob Faibussowitsch   PetscCall(PetscFree(remoteOffsets));
11259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
1126ac04eaf7SToby Isaac   if (original) {
1127ac04eaf7SToby Isaac     PetscInt numCones;
1128ac04eaf7SToby Isaac 
11299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(originalConeSection, &numCones));
11309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numCones, &globCones));
11319566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApplyBlock(original, numCones, cones, globCones));
1132367003a6SStefano Zampini   } else {
1133ac04eaf7SToby Isaac     globCones = cones;
1134ac04eaf7SToby Isaac   }
11359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dmParallel, &newCones));
11369566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(coneSF, MPIU_INT, globCones, newCones, MPI_REPLACE));
11379566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(coneSF, MPIU_INT, globCones, newCones, MPI_REPLACE));
11381baa6e33SBarry Smith   if (original) PetscCall(PetscFree(globCones));
11399566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newConeSection, &newConesSize));
11409566063dSJacob Faibussowitsch   PetscCall(ISGlobalToLocalMappingApplyBlock(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones));
114176bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
11423533c52bSMatthew G. Knepley     PetscInt  p;
11433533c52bSMatthew G. Knepley     PetscBool valid = PETSC_TRUE;
11443533c52bSMatthew G. Knepley     for (p = 0; p < newConesSize; ++p) {
11459371c9d4SSatish Balay       if (newCones[p] < 0) {
11469371c9d4SSatish Balay         valid = PETSC_FALSE;
11479371c9d4SSatish Balay         PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Point %" PetscInt_FMT " not in overlap SF\n", PetscGlobalRank, p));
11489371c9d4SSatish Balay       }
11493533c52bSMatthew G. Knepley     }
115028b400f6SJacob Faibussowitsch     PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid global to local map");
11513533c52bSMatthew G. Knepley   }
11529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-cones_view", &flg));
1153cc71bff1SMichael Lange   if (flg) {
11549566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Serial Cone Section:\n"));
11559566063dSJacob Faibussowitsch     PetscCall(PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_(comm)));
11569566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Parallel Cone Section:\n"));
11579566063dSJacob Faibussowitsch     PetscCall(PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_(comm)));
11589566063dSJacob Faibussowitsch     PetscCall(PetscSFView(coneSF, NULL));
1159cc71bff1SMichael Lange   }
11609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientations(dm, &cones));
11619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeOrientations(dmParallel, &newCones));
11629566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones, MPI_REPLACE));
11639566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones, MPI_REPLACE));
11649566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&coneSF));
11659566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_DistributeCones, dm, 0, 0, 0));
1166eaf898f9SPatrick Sanan   /* Create supports and stratify DMPlex */
1167cc71bff1SMichael Lange   {
1168cc71bff1SMichael Lange     PetscInt pStart, pEnd;
1169cc71bff1SMichael Lange 
11709566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd));
11719566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(pmesh->supportSection, pStart, pEnd));
1172cc71bff1SMichael Lange   }
11739566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(dmParallel));
11749566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(dmParallel));
11751cf84007SMatthew G. Knepley   {
11761cf84007SMatthew G. Knepley     PetscBool useCone, useClosure, useAnchors;
11771cf84007SMatthew G. Knepley 
11789566063dSJacob Faibussowitsch     PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
11799566063dSJacob Faibussowitsch     PetscCall(DMSetBasicAdjacency(dmParallel, useCone, useClosure));
11809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacencyUseAnchors(dm, &useAnchors));
11819566063dSJacob Faibussowitsch     PetscCall(DMPlexSetAdjacencyUseAnchors(dmParallel, useAnchors));
11821cf84007SMatthew G. Knepley   }
11833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1184cc71bff1SMichael Lange }
1185cc71bff1SMichael Lange 
1186d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDistributeCoordinates(DM dm, PetscSF migrationSF, DM dmParallel)
1187d71ae5a4SJacob Faibussowitsch {
11880df0e737SMichael Lange   MPI_Comm         comm;
11899318fe57SMatthew G. Knepley   DM               cdm, cdmParallel;
11900df0e737SMichael Lange   PetscSection     originalCoordSection, newCoordSection;
11910df0e737SMichael Lange   Vec              originalCoordinates, newCoordinates;
11920df0e737SMichael Lange   PetscInt         bs;
11930df0e737SMichael Lange   const char      *name;
11944fb89dddSMatthew G. Knepley   const PetscReal *maxCell, *Lstart, *L;
11950df0e737SMichael Lange 
11960df0e737SMichael Lange   PetscFunctionBegin;
11970df0e737SMichael Lange   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
11980c86c063SLisandro Dalcin   PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 3);
11990df0e737SMichael Lange 
12009566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
12016858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
12026858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dmParallel, &cdmParallel));
12036858538eSMatthew G. Knepley   PetscCall(DMCopyDisc(cdm, cdmParallel));
12049566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &originalCoordSection));
12059566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dmParallel, &newCoordSection));
12069566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dm, &originalCoordinates));
12070df0e737SMichael Lange   if (originalCoordinates) {
12089566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF, &newCoordinates));
12099566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)originalCoordinates, &name));
12109566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)newCoordinates, name));
12110df0e737SMichael Lange 
12129566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeField(dm, migrationSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates));
12139566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinatesLocal(dmParallel, newCoordinates));
12149566063dSJacob Faibussowitsch     PetscCall(VecGetBlockSize(originalCoordinates, &bs));
12159566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(newCoordinates, bs));
12169566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&newCoordinates));
12170df0e737SMichael Lange   }
12186858538eSMatthew G. Knepley 
12196858538eSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
12204fb89dddSMatthew G. Knepley   PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
12214fb89dddSMatthew G. Knepley   PetscCall(DMSetPeriodicity(dmParallel, maxCell, Lstart, L));
12226858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dm, &cdm));
12236858538eSMatthew G. Knepley   if (cdm) {
12246858538eSMatthew G. Knepley     PetscCall(DMClone(dmParallel, &cdmParallel));
12256858538eSMatthew G. Knepley     PetscCall(DMSetCellCoordinateDM(dmParallel, cdmParallel));
12269566063dSJacob Faibussowitsch     PetscCall(DMCopyDisc(cdm, cdmParallel));
12276858538eSMatthew G. Knepley     PetscCall(DMDestroy(&cdmParallel));
12286858538eSMatthew G. Knepley     PetscCall(DMGetCellCoordinateSection(dm, &originalCoordSection));
12296858538eSMatthew G. Knepley     PetscCall(DMGetCellCoordinatesLocal(dm, &originalCoordinates));
12306858538eSMatthew G. Knepley     PetscCall(PetscSectionCreate(comm, &newCoordSection));
12316858538eSMatthew G. Knepley     if (originalCoordinates) {
12326858538eSMatthew G. Knepley       PetscCall(VecCreate(PETSC_COMM_SELF, &newCoordinates));
12336858538eSMatthew G. Knepley       PetscCall(PetscObjectGetName((PetscObject)originalCoordinates, &name));
12346858538eSMatthew G. Knepley       PetscCall(PetscObjectSetName((PetscObject)newCoordinates, name));
12356858538eSMatthew G. Knepley 
12366858538eSMatthew G. Knepley       PetscCall(DMPlexDistributeField(dm, migrationSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates));
12376858538eSMatthew G. Knepley       PetscCall(VecGetBlockSize(originalCoordinates, &bs));
12386858538eSMatthew G. Knepley       PetscCall(VecSetBlockSize(newCoordinates, bs));
12396858538eSMatthew G. Knepley       PetscCall(DMSetCellCoordinateSection(dmParallel, bs, newCoordSection));
12406858538eSMatthew G. Knepley       PetscCall(DMSetCellCoordinatesLocal(dmParallel, newCoordinates));
12416858538eSMatthew G. Knepley       PetscCall(VecDestroy(&newCoordinates));
12426858538eSMatthew G. Knepley     }
12436858538eSMatthew G. Knepley     PetscCall(PetscSectionDestroy(&newCoordSection));
12446858538eSMatthew G. Knepley   }
12453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12460df0e737SMichael Lange }
12470df0e737SMichael Lange 
1248d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDistributeLabels(DM dm, PetscSF migrationSF, DM dmParallel)
1249d71ae5a4SJacob Faibussowitsch {
1250df0420ecSMatthew G. Knepley   DM_Plex         *mesh = (DM_Plex *)dm->data;
12510df0e737SMichael Lange   MPI_Comm         comm;
12527980c9d4SMatthew G. Knepley   DMLabel          depthLabel;
12530df0e737SMichael Lange   PetscMPIInt      rank;
12547980c9d4SMatthew G. Knepley   PetscInt         depth, d, numLabels, numLocalLabels, l;
1255df0420ecSMatthew G. Knepley   PetscBool        hasLabels  = PETSC_FALSE, lsendDepth, sendDepth;
1256df0420ecSMatthew G. Knepley   PetscObjectState depthState = -1;
12570df0e737SMichael Lange 
12580df0e737SMichael Lange   PetscFunctionBegin;
12590df0e737SMichael Lange   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
12600c86c063SLisandro Dalcin   PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 3);
12610c86c063SLisandro Dalcin 
12629566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_DistributeLabels, dm, 0, 0, 0));
12639566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
12649566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
12650df0e737SMichael Lange 
1266df0420ecSMatthew G. Knepley   /* If the user has changed the depth label, communicate it instead */
12679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
12689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
12699566063dSJacob Faibussowitsch   if (depthLabel) PetscCall(PetscObjectStateGet((PetscObject)depthLabel, &depthState));
1270df0420ecSMatthew G. Knepley   lsendDepth = mesh->depthState != depthState ? PETSC_TRUE : PETSC_FALSE;
12711c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&lsendDepth, &sendDepth, 1, MPIU_BOOL, MPI_LOR, comm));
1272df0420ecSMatthew G. Knepley   if (sendDepth) {
12739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthLabel(dmParallel, &dmParallel->depthLabel));
12749566063dSJacob Faibussowitsch     PetscCall(DMRemoveLabelBySelf(dmParallel, &dmParallel->depthLabel, PETSC_FALSE));
1275df0420ecSMatthew G. Knepley   }
1276d995df53SMatthew G. Knepley   /* Everyone must have either the same number of labels, or none */
12779566063dSJacob Faibussowitsch   PetscCall(DMGetNumLabels(dm, &numLocalLabels));
1278d995df53SMatthew G. Knepley   numLabels = numLocalLabels;
12799566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm));
1280627847f0SMatthew G. Knepley   if (numLabels == numLocalLabels) hasLabels = PETSC_TRUE;
12815d80c0bfSVaclav Hapla   for (l = 0; l < numLabels; ++l) {
1282bdd2d751SMichael Lange     DMLabel     label = NULL, labelNew = NULL;
128383e10cb3SLisandro Dalcin     PetscBool   isDepth, lisOutput     = PETSC_TRUE, isOutput;
1284d67d17b1SMatthew G. Knepley     const char *name = NULL;
12850df0e737SMichael Lange 
1286d67d17b1SMatthew G. Knepley     if (hasLabels) {
12879566063dSJacob Faibussowitsch       PetscCall(DMGetLabelByNum(dm, l, &label));
12880df0e737SMichael Lange       /* Skip "depth" because it is recreated */
12899566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)label, &name));
12909566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isDepth));
1291bbcf679cSJacob Faibussowitsch     } else {
1292bbcf679cSJacob Faibussowitsch       isDepth = PETSC_FALSE;
1293d67d17b1SMatthew G. Knepley     }
12949566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(&isDepth, 1, MPIU_BOOL, 0, comm));
129583e10cb3SLisandro Dalcin     if (isDepth && !sendDepth) continue;
12969566063dSJacob Faibussowitsch     PetscCall(DMLabelDistribute(label, migrationSF, &labelNew));
129783e10cb3SLisandro Dalcin     if (isDepth) {
12987980c9d4SMatthew G. Knepley       /* Put in any missing strata which can occur if users are managing the depth label themselves */
12997980c9d4SMatthew G. Knepley       PetscInt gdepth;
13007980c9d4SMatthew G. Knepley 
13011c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&depth, &gdepth, 1, MPIU_INT, MPI_MAX, comm));
130263a3b9bcSJacob Faibussowitsch       PetscCheck(!(depth >= 0) || !(gdepth != depth), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %" PetscInt_FMT " != %" PetscInt_FMT, depth, gdepth);
13037980c9d4SMatthew G. Knepley       for (d = 0; d <= gdepth; ++d) {
13047980c9d4SMatthew G. Knepley         PetscBool has;
13057980c9d4SMatthew G. Knepley 
13069566063dSJacob Faibussowitsch         PetscCall(DMLabelHasStratum(labelNew, d, &has));
13079566063dSJacob Faibussowitsch         if (!has) PetscCall(DMLabelAddStratum(labelNew, d));
13087980c9d4SMatthew G. Knepley       }
13097980c9d4SMatthew G. Knepley     }
13109566063dSJacob Faibussowitsch     PetscCall(DMAddLabel(dmParallel, labelNew));
131183e10cb3SLisandro Dalcin     /* Put the output flag in the new label */
13129566063dSJacob Faibussowitsch     if (hasLabels) PetscCall(DMGetLabelOutput(dm, name, &lisOutput));
13131c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&lisOutput, &isOutput, 1, MPIU_BOOL, MPI_LAND, comm));
13149566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)labelNew, &name));
13159566063dSJacob Faibussowitsch     PetscCall(DMSetLabelOutput(dmParallel, name, isOutput));
13169566063dSJacob Faibussowitsch     PetscCall(DMLabelDestroy(&labelNew));
13170df0e737SMichael Lange   }
1318695799ffSMatthew G. Knepley   {
1319695799ffSMatthew G. Knepley     DMLabel ctLabel;
1320695799ffSMatthew G. Knepley 
1321695799ffSMatthew G. Knepley     // Reset label for fast lookup
1322695799ffSMatthew G. Knepley     PetscCall(DMPlexGetCellTypeLabel(dmParallel, &ctLabel));
1323695799ffSMatthew G. Knepley     PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel));
1324695799ffSMatthew G. Knepley   }
13259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_DistributeLabels, dm, 0, 0, 0));
13263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13270df0e737SMichael Lange }
13280df0e737SMichael Lange 
1329d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexDistributeSetupTree(DM dm, PetscSF migrationSF, ISLocalToGlobalMapping original, ISLocalToGlobalMapping renumbering, DM dmParallel)
1330d71ae5a4SJacob Faibussowitsch {
133115078cd4SMichael Lange   DM_Plex     *mesh  = (DM_Plex *)dm->data;
133215078cd4SMichael Lange   DM_Plex     *pmesh = (DM_Plex *)(dmParallel)->data;
1333a6f36705SMichael Lange   MPI_Comm     comm;
1334a6f36705SMichael Lange   DM           refTree;
1335a6f36705SMichael Lange   PetscSection origParentSection, newParentSection;
1336a6f36705SMichael Lange   PetscInt    *origParents, *origChildIDs;
1337a6f36705SMichael Lange   PetscBool    flg;
1338a6f36705SMichael Lange 
1339a6f36705SMichael Lange   PetscFunctionBegin;
1340a6f36705SMichael Lange   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13410c86c063SLisandro Dalcin   PetscValidHeaderSpecific(dmParallel, DM_CLASSID, 5);
13429566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1343a6f36705SMichael Lange 
1344a6f36705SMichael Lange   /* Set up tree */
13459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
13469566063dSJacob Faibussowitsch   PetscCall(DMPlexSetReferenceTree(dmParallel, refTree));
13479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTree(dm, &origParentSection, &origParents, &origChildIDs, NULL, NULL));
1348a6f36705SMichael Lange   if (origParentSection) {
1349a6f36705SMichael Lange     PetscInt  pStart, pEnd;
135008633170SToby Isaac     PetscInt *newParents, *newChildIDs, *globParents;
1351a6f36705SMichael Lange     PetscInt *remoteOffsetsParents, newParentSize;
1352a6f36705SMichael Lange     PetscSF   parentSF;
1353a6f36705SMichael Lange 
13549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(dmParallel, &pStart, &pEnd));
13559566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmParallel), &newParentSection));
13569566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(newParentSection, pStart, pEnd));
13579566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(migrationSF, origParentSection, &remoteOffsetsParents, newParentSection));
13589566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(migrationSF, origParentSection, remoteOffsetsParents, newParentSection, &parentSF));
13599566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsetsParents));
13609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(newParentSection, &newParentSize));
13619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(newParentSize, &newParents, newParentSize, &newChildIDs));
136208633170SToby Isaac     if (original) {
136308633170SToby Isaac       PetscInt numParents;
136408633170SToby Isaac 
13659566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(origParentSection, &numParents));
13669566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numParents, &globParents));
13679566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApplyBlock(original, numParents, origParents, globParents));
13689371c9d4SSatish Balay     } else {
136908633170SToby Isaac       globParents = origParents;
137008633170SToby Isaac     }
13719566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(parentSF, MPIU_INT, globParents, newParents, MPI_REPLACE));
13729566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(parentSF, MPIU_INT, globParents, newParents, MPI_REPLACE));
13731baa6e33SBarry Smith     if (original) PetscCall(PetscFree(globParents));
13749566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(parentSF, MPIU_INT, origChildIDs, newChildIDs, MPI_REPLACE));
13759566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(parentSF, MPIU_INT, origChildIDs, newChildIDs, MPI_REPLACE));
13769566063dSJacob Faibussowitsch     PetscCall(ISGlobalToLocalMappingApplyBlock(renumbering, IS_GTOLM_MASK, newParentSize, newParents, NULL, newParents));
137776bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {
13784a54e071SToby Isaac       PetscInt  p;
13794a54e071SToby Isaac       PetscBool valid = PETSC_TRUE;
13804a54e071SToby Isaac       for (p = 0; p < newParentSize; ++p) {
13819371c9d4SSatish Balay         if (newParents[p] < 0) {
13829371c9d4SSatish Balay           valid = PETSC_FALSE;
13839371c9d4SSatish Balay           PetscCall(PetscPrintf(PETSC_COMM_SELF, "Point %" PetscInt_FMT " not in overlap SF\n", p));
13849371c9d4SSatish Balay         }
13854a54e071SToby Isaac       }
138628b400f6SJacob Faibussowitsch       PetscCheck(valid, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid global to local map");
13874a54e071SToby Isaac     }
13889566063dSJacob Faibussowitsch     PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-parents_view", &flg));
1389a6f36705SMichael Lange     if (flg) {
13909566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "Serial Parent Section: \n"));
13919566063dSJacob Faibussowitsch       PetscCall(PetscSectionView(origParentSection, PETSC_VIEWER_STDOUT_(comm)));
13929566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "Parallel Parent Section: \n"));
13939566063dSJacob Faibussowitsch       PetscCall(PetscSectionView(newParentSection, PETSC_VIEWER_STDOUT_(comm)));
13949566063dSJacob Faibussowitsch       PetscCall(PetscSFView(parentSF, NULL));
1395a6f36705SMichael Lange     }
13969566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(dmParallel, newParentSection, newParents, newChildIDs));
13979566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&newParentSection));
13989566063dSJacob Faibussowitsch     PetscCall(PetscFree2(newParents, newChildIDs));
13999566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&parentSF));
1400a6f36705SMichael Lange   }
140115078cd4SMichael Lange   pmesh->useAnchors = mesh->useAnchors;
14023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1403a6f36705SMichael Lange }
14040df0e737SMichael Lange 
140598ba2d7fSLawrence Mitchell /*@
140620f4b53cSBarry Smith   DMPlexSetPartitionBalance - Should distribution of the `DM` attempt to balance the shared point partition?
140798ba2d7fSLawrence Mitchell 
140898ba2d7fSLawrence Mitchell   Input Parameters:
140920f4b53cSBarry Smith + dm  - The `DMPLEX` object
141098ba2d7fSLawrence Mitchell - flg - Balance the partition?
141198ba2d7fSLawrence Mitchell 
141298ba2d7fSLawrence Mitchell   Level: intermediate
141398ba2d7fSLawrence Mitchell 
141420f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexGetPartitionBalance()`
141598ba2d7fSLawrence Mitchell @*/
1416d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetPartitionBalance(DM dm, PetscBool flg)
1417d71ae5a4SJacob Faibussowitsch {
141898ba2d7fSLawrence Mitchell   DM_Plex *mesh = (DM_Plex *)dm->data;
141998ba2d7fSLawrence Mitchell 
142098ba2d7fSLawrence Mitchell   PetscFunctionBegin;
142198ba2d7fSLawrence Mitchell   mesh->partitionBalance = flg;
14223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
142398ba2d7fSLawrence Mitchell }
142498ba2d7fSLawrence Mitchell 
142598ba2d7fSLawrence Mitchell /*@
142620f4b53cSBarry Smith   DMPlexGetPartitionBalance - Does distribution of the `DM` attempt to balance the shared point partition?
142798ba2d7fSLawrence Mitchell 
142898ba2d7fSLawrence Mitchell   Input Parameter:
142920f4b53cSBarry Smith . dm - The `DMPLEX` object
143098ba2d7fSLawrence Mitchell 
143198ba2d7fSLawrence Mitchell   Output Parameter:
1432a2b725a8SWilliam Gropp . flg - Balance the partition?
143398ba2d7fSLawrence Mitchell 
143498ba2d7fSLawrence Mitchell   Level: intermediate
143598ba2d7fSLawrence Mitchell 
143620f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexSetPartitionBalance()`
143798ba2d7fSLawrence Mitchell @*/
1438d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPartitionBalance(DM dm, PetscBool *flg)
1439d71ae5a4SJacob Faibussowitsch {
144098ba2d7fSLawrence Mitchell   DM_Plex *mesh = (DM_Plex *)dm->data;
144198ba2d7fSLawrence Mitchell 
144298ba2d7fSLawrence Mitchell   PetscFunctionBegin;
144398ba2d7fSLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
14444f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
144598ba2d7fSLawrence Mitchell   *flg = mesh->partitionBalance;
14463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
144798ba2d7fSLawrence Mitchell }
144898ba2d7fSLawrence Mitchell 
1449fc02256fSLawrence Mitchell typedef struct {
1450fc02256fSLawrence Mitchell   PetscInt vote, rank, index;
1451fc02256fSLawrence Mitchell } Petsc3Int;
1452fc02256fSLawrence Mitchell 
1453fc02256fSLawrence Mitchell /* MaxLoc, but carry a third piece of information around */
1454d71ae5a4SJacob Faibussowitsch static void MPIAPI MaxLocCarry(void *in_, void *inout_, PetscMPIInt *len_, MPI_Datatype *dtype)
1455d71ae5a4SJacob Faibussowitsch {
1456fc02256fSLawrence Mitchell   Petsc3Int *a = (Petsc3Int *)inout_;
1457fc02256fSLawrence Mitchell   Petsc3Int *b = (Petsc3Int *)in_;
1458fc02256fSLawrence Mitchell   PetscInt   i, len = *len_;
1459fc02256fSLawrence Mitchell   for (i = 0; i < len; i++) {
1460fc02256fSLawrence Mitchell     if (a[i].vote < b[i].vote) {
1461fc02256fSLawrence Mitchell       a[i].vote  = b[i].vote;
1462fc02256fSLawrence Mitchell       a[i].rank  = b[i].rank;
1463fc02256fSLawrence Mitchell       a[i].index = b[i].index;
1464fc02256fSLawrence Mitchell     } else if (a[i].vote <= b[i].vote) {
1465fc02256fSLawrence Mitchell       if (a[i].rank >= b[i].rank) {
1466fc02256fSLawrence Mitchell         a[i].rank  = b[i].rank;
1467fc02256fSLawrence Mitchell         a[i].index = b[i].index;
1468fc02256fSLawrence Mitchell       }
1469fc02256fSLawrence Mitchell     }
1470fc02256fSLawrence Mitchell   }
1471fc02256fSLawrence Mitchell }
1472fc02256fSLawrence Mitchell 
1473f5bf2dbfSMichael Lange /*@C
147420f4b53cSBarry Smith   DMPlexCreatePointSF - Build a point `PetscSF` from an `PetscSF` describing a point migration
1475f5bf2dbfSMichael Lange 
1476064ec1f3Sprj-   Input Parameters:
147720f4b53cSBarry Smith + dm          - The source `DMPLEX` object
1478f5bf2dbfSMichael Lange . migrationSF - The star forest that describes the parallel point remapping
1479d8d19677SJose E. Roman - ownership   - Flag causing a vote to determine point ownership
1480f5bf2dbfSMichael Lange 
1481f5bf2dbfSMichael Lange   Output Parameter:
148220f4b53cSBarry Smith . pointSF - The star forest describing the point overlap in the remapped `DM`
14833618482eSVaclav Hapla 
1484f5bf2dbfSMichael Lange   Level: developer
1485f5bf2dbfSMichael Lange 
148620f4b53cSBarry Smith   Note:
148720f4b53cSBarry Smith   Output `pointSF` is guaranteed to have the array of local indices (leaves) sorted.
148820f4b53cSBarry Smith 
148920f4b53cSBarry Smith .seealso: `DMPLEX`, `PetscSF`, `DM`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()`
1490f5bf2dbfSMichael Lange @*/
1491d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreatePointSF(DM dm, PetscSF migrationSF, PetscBool ownership, PetscSF *pointSF)
1492d71ae5a4SJacob Faibussowitsch {
149323193802SMatthew G. Knepley   PetscMPIInt        rank, size;
14941627f6ccSMichael Lange   PetscInt           p, nroots, nleaves, idx, npointLeaves;
1495f5bf2dbfSMichael Lange   PetscInt          *pointLocal;
1496f5bf2dbfSMichael Lange   const PetscInt    *leaves;
1497f5bf2dbfSMichael Lange   const PetscSFNode *roots;
1498f5bf2dbfSMichael Lange   PetscSFNode       *rootNodes, *leafNodes, *pointRemote;
149923193802SMatthew G. Knepley   Vec                shifts;
1500cae3e4f3SLawrence Mitchell   const PetscInt     numShifts  = 13759;
150123193802SMatthew G. Knepley   const PetscScalar *shift      = NULL;
150223193802SMatthew G. Knepley   const PetscBool    shiftDebug = PETSC_FALSE;
150398ba2d7fSLawrence Mitchell   PetscBool          balance;
1504f5bf2dbfSMichael Lange 
1505f5bf2dbfSMichael Lange   PetscFunctionBegin;
1506f5bf2dbfSMichael Lange   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
15079566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
15089566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
15099566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CreatePointSF, dm, 0, 0, 0));
1510907a3e9cSStefano Zampini   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), pointSF));
1511907a3e9cSStefano Zampini   PetscCall(PetscSFSetFromOptions(*pointSF));
1512907a3e9cSStefano Zampini   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
1513f5bf2dbfSMichael Lange 
15149566063dSJacob Faibussowitsch   PetscCall(DMPlexGetPartitionBalance(dm, &balance));
15159566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(migrationSF, &nroots, &nleaves, &leaves, &roots));
15169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nroots, &rootNodes, nleaves, &leafNodes));
1517f5bf2dbfSMichael Lange   if (ownership) {
1518fc02256fSLawrence Mitchell     MPI_Op       op;
1519fc02256fSLawrence Mitchell     MPI_Datatype datatype;
1520fc02256fSLawrence Mitchell     Petsc3Int   *rootVote = NULL, *leafVote = NULL;
152123193802SMatthew G. Knepley     /* If balancing, we compute a random cyclic shift of the rank for each remote point. That way, the max will evenly distribute among ranks. */
152298ba2d7fSLawrence Mitchell     if (balance) {
152323193802SMatthew G. Knepley       PetscRandom r;
152423193802SMatthew G. Knepley 
15259566063dSJacob Faibussowitsch       PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &r));
15269566063dSJacob Faibussowitsch       PetscCall(PetscRandomSetInterval(r, 0, 2467 * size));
15279566063dSJacob Faibussowitsch       PetscCall(VecCreate(PETSC_COMM_SELF, &shifts));
15289566063dSJacob Faibussowitsch       PetscCall(VecSetSizes(shifts, numShifts, numShifts));
15299566063dSJacob Faibussowitsch       PetscCall(VecSetType(shifts, VECSTANDARD));
15309566063dSJacob Faibussowitsch       PetscCall(VecSetRandom(shifts, r));
15319566063dSJacob Faibussowitsch       PetscCall(PetscRandomDestroy(&r));
15329566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(shifts, &shift));
153323193802SMatthew G. Knepley     }
153423193802SMatthew G. Knepley 
15359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nroots, &rootVote));
15369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &leafVote));
153723193802SMatthew G. Knepley     /* Point ownership vote: Process with highest rank owns shared points */
1538f5bf2dbfSMichael Lange     for (p = 0; p < nleaves; ++p) {
153923193802SMatthew G. Knepley       if (shiftDebug) {
15409371c9d4SSatish Balay         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,
15419371c9d4SSatish Balay                                           (PetscInt)PetscRealPart(shift[roots[p].index % numShifts]), (rank + (shift ? (PetscInt)PetscRealPart(shift[roots[p].index % numShifts]) : 0)) % size));
154223193802SMatthew G. Knepley       }
1543f5bf2dbfSMichael Lange       /* Either put in a bid or we know we own it */
1544fc02256fSLawrence Mitchell       leafVote[p].vote  = (rank + (shift ? (PetscInt)PetscRealPart(shift[roots[p].index % numShifts]) : 0)) % size;
1545fc02256fSLawrence Mitchell       leafVote[p].rank  = rank;
1546fc02256fSLawrence Mitchell       leafVote[p].index = p;
1547f5bf2dbfSMichael Lange     }
1548f5bf2dbfSMichael Lange     for (p = 0; p < nroots; p++) {
15491627f6ccSMichael Lange       /* Root must not participate in the reduction, flag so that MAXLOC does not use */
1550fc02256fSLawrence Mitchell       rootVote[p].vote  = -3;
1551fc02256fSLawrence Mitchell       rootVote[p].rank  = -3;
1552fc02256fSLawrence Mitchell       rootVote[p].index = -3;
1553f5bf2dbfSMichael Lange     }
15549566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(3, MPIU_INT, &datatype));
15559566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&datatype));
15569566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_create(&MaxLocCarry, 1, &op));
15579566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(migrationSF, datatype, leafVote, rootVote, op));
15589566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(migrationSF, datatype, leafVote, rootVote, op));
15599566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Op_free(&op));
15609566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&datatype));
1561c091126eSLawrence Mitchell     for (p = 0; p < nroots; p++) {
1562fc02256fSLawrence Mitchell       rootNodes[p].rank  = rootVote[p].rank;
1563fc02256fSLawrence Mitchell       rootNodes[p].index = rootVote[p].index;
1564c091126eSLawrence Mitchell     }
15659566063dSJacob Faibussowitsch     PetscCall(PetscFree(leafVote));
15669566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootVote));
1567f5bf2dbfSMichael Lange   } else {
1568f5bf2dbfSMichael Lange     for (p = 0; p < nroots; p++) {
1569f5bf2dbfSMichael Lange       rootNodes[p].index = -1;
1570f5bf2dbfSMichael Lange       rootNodes[p].rank  = rank;
1571fc02256fSLawrence Mitchell     }
1572f5bf2dbfSMichael Lange     for (p = 0; p < nleaves; p++) {
1573f5bf2dbfSMichael Lange       /* Write new local id into old location */
1574ad540459SPierre Jolivet       if (roots[p].rank == rank) rootNodes[roots[p].index].index = leaves ? leaves[p] : p;
1575f5bf2dbfSMichael Lange     }
1576f5bf2dbfSMichael Lange   }
15779566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(migrationSF, MPIU_2INT, rootNodes, leafNodes, MPI_REPLACE));
15789566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(migrationSF, MPIU_2INT, rootNodes, leafNodes, MPI_REPLACE));
1579f5bf2dbfSMichael Lange 
158023193802SMatthew G. Knepley   for (npointLeaves = 0, p = 0; p < nleaves; p++) {
1581b0e1264bSMatthew G. Knepley     if (leafNodes[p].rank != rank) npointLeaves++;
158223193802SMatthew G. Knepley   }
15839566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(npointLeaves, &pointLocal));
15849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(npointLeaves, &pointRemote));
1585f5bf2dbfSMichael Lange   for (idx = 0, p = 0; p < nleaves; p++) {
1586b0e1264bSMatthew G. Knepley     if (leafNodes[p].rank != rank) {
15873618482eSVaclav Hapla       /* Note that pointLocal is automatically sorted as it is sublist of 0, ..., nleaves-1 */
1588f5bf2dbfSMichael Lange       pointLocal[idx]  = p;
1589f5bf2dbfSMichael Lange       pointRemote[idx] = leafNodes[p];
1590f5bf2dbfSMichael Lange       idx++;
1591f5bf2dbfSMichael Lange     }
1592f5bf2dbfSMichael Lange   }
159323193802SMatthew G. Knepley   if (shift) {
15949566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(shifts, &shift));
15959566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shifts));
159623193802SMatthew G. Knepley   }
15979566063dSJacob Faibussowitsch   if (shiftDebug) PetscCall(PetscSynchronizedFlush(PetscObjectComm((PetscObject)dm), PETSC_STDOUT));
15989566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*pointSF, nleaves, npointLeaves, pointLocal, PETSC_OWN_POINTER, pointRemote, PETSC_OWN_POINTER));
15999566063dSJacob Faibussowitsch   PetscCall(PetscFree2(rootNodes, leafNodes));
16009566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CreatePointSF, dm, 0, 0, 0));
1601d7d32a9aSMatthew G. Knepley   if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, *pointSF, PETSC_FALSE));
16023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1603f5bf2dbfSMichael Lange }
1604f5bf2dbfSMichael Lange 
160515078cd4SMichael Lange /*@C
160620f4b53cSBarry Smith   DMPlexMigrate  - Migrates internal `DM` data over the supplied star forest
160715078cd4SMichael Lange 
160820f4b53cSBarry Smith   Collective
160983655b49SVáclav Hapla 
1610064ec1f3Sprj-   Input Parameters:
161120f4b53cSBarry Smith + dm - The source `DMPLEX` object
1612d8d19677SJose E. Roman - sf - The star forest communication context describing the migration pattern
161315078cd4SMichael Lange 
161415078cd4SMichael Lange   Output Parameter:
161520f4b53cSBarry Smith . targetDM - The target `DMPLEX` object
161615078cd4SMichael Lange 
1617b9f40539SMichael Lange   Level: intermediate
161815078cd4SMichael Lange 
161920f4b53cSBarry Smith .seealso: `DMPLEX`, `PetscSF`, `DM`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()`
162015078cd4SMichael Lange @*/
1621d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexMigrate(DM dm, PetscSF sf, DM targetDM)
1622d71ae5a4SJacob Faibussowitsch {
1623b9f40539SMichael Lange   MPI_Comm               comm;
1624cc1750acSStefano Zampini   PetscInt               dim, cdim, nroots;
1625b9f40539SMichael Lange   PetscSF                sfPoint;
162615078cd4SMichael Lange   ISLocalToGlobalMapping ltogMigration;
1627ac04eaf7SToby Isaac   ISLocalToGlobalMapping ltogOriginal = NULL;
162815078cd4SMichael Lange 
162915078cd4SMichael Lange   PetscFunctionBegin;
163015078cd4SMichael Lange   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
16319566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Migrate, dm, 0, 0, 0));
16329566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
16339566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
16349566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(targetDM, dim));
16359566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
16369566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(targetDM, cdim));
163715078cd4SMichael Lange 
1638bfb0467fSMichael Lange   /* Check for a one-to-all distribution pattern */
16399566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
16409566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL));
1641bfb0467fSMichael Lange   if (nroots >= 0) {
1642b9f40539SMichael Lange     IS        isOriginal;
1643ac04eaf7SToby Isaac     PetscInt  n, size, nleaves;
1644ac04eaf7SToby Isaac     PetscInt *numbering_orig, *numbering_new;
1645367003a6SStefano Zampini 
1646b9f40539SMichael Lange     /* Get the original point numbering */
16479566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePointNumbering(dm, &isOriginal));
16489566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateIS(isOriginal, &ltogOriginal));
16499566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetSize(ltogOriginal, &size));
16509566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltogOriginal, (const PetscInt **)&numbering_orig));
1651b9f40539SMichael Lange     /* Convert to positive global numbers */
16529371c9d4SSatish Balay     for (n = 0; n < size; n++) {
16539371c9d4SSatish Balay       if (numbering_orig[n] < 0) numbering_orig[n] = -(numbering_orig[n] + 1);
16549371c9d4SSatish Balay     }
1655b9f40539SMichael Lange     /* Derive the new local-to-global mapping from the old one */
16569566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, NULL, NULL));
16579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &numbering_new));
16589566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, numbering_orig, numbering_new, MPI_REPLACE));
16599566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, numbering_orig, numbering_new, MPI_REPLACE));
16609566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreate(comm, 1, nleaves, numbering_new, PETSC_OWN_POINTER, &ltogMigration));
16619566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogOriginal, (const PetscInt **)&numbering_orig));
16629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&isOriginal));
166315078cd4SMichael Lange   } else {
1664bfb0467fSMichael Lange     /* One-to-all distribution pattern: We can derive LToG from SF */
16659566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingCreateSF(sf, 0, &ltogMigration));
166615078cd4SMichael Lange   }
1667a5a902f7SVaclav Hapla   PetscCall(PetscObjectSetName((PetscObject)ltogMigration, "Point renumbering for DM migration"));
1668a5a902f7SVaclav Hapla   PetscCall(ISLocalToGlobalMappingViewFromOptions(ltogMigration, (PetscObject)dm, "-partition_view"));
166915078cd4SMichael Lange   /* Migrate DM data to target DM */
16709566063dSJacob Faibussowitsch   PetscCall(DMPlexDistributeCones(dm, sf, ltogOriginal, ltogMigration, targetDM));
16719566063dSJacob Faibussowitsch   PetscCall(DMPlexDistributeLabels(dm, sf, targetDM));
16729566063dSJacob Faibussowitsch   PetscCall(DMPlexDistributeCoordinates(dm, sf, targetDM));
16739566063dSJacob Faibussowitsch   PetscCall(DMPlexDistributeSetupTree(dm, sf, ltogOriginal, ltogMigration, targetDM));
16749566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltogOriginal));
16759566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&ltogMigration));
16769566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Migrate, dm, 0, 0, 0));
16773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
167815078cd4SMichael Lange }
167915078cd4SMichael Lange 
168000a1aa47SMatthew G. Knepley /*@
168100a1aa47SMatthew G. Knepley   DMPlexRemapMigrationSF - Rewrite the distribution SF to account for overlap
168200a1aa47SMatthew G. Knepley 
168300a1aa47SMatthew G. Knepley   Collective
168400a1aa47SMatthew G. Knepley 
168500a1aa47SMatthew G. Knepley   Input Parameters:
168600a1aa47SMatthew G. Knepley + sfOverlap   - The `PetscSF` object just for the overlap
168700a1aa47SMatthew G. Knepley - sfMigration - The original distribution `PetscSF` object
168800a1aa47SMatthew G. Knepley 
168900a1aa47SMatthew G. Knepley   Output Parameters:
169000a1aa47SMatthew G. Knepley . sfMigrationNew - A rewritten `PetscSF` object that incorporates the overlap
169100a1aa47SMatthew G. Knepley 
169200a1aa47SMatthew G. Knepley   Level: developer
169300a1aa47SMatthew G. Knepley 
169400a1aa47SMatthew G. Knepley .seealso: `DMPLEX`, `DM`, `DMPlexDistribute()`, `DMPlexDistributeOverlap()`, `DMPlexGetOverlap()`
169500a1aa47SMatthew G. Knepley @*/
169600a1aa47SMatthew G. Knepley PetscErrorCode DMPlexRemapMigrationSF(PetscSF sfOverlap, PetscSF sfMigration, PetscSF *sfMigrationNew)
169700a1aa47SMatthew G. Knepley {
169800a1aa47SMatthew G. Knepley   PetscSFNode       *newRemote, *permRemote;
169900a1aa47SMatthew G. Knepley   const PetscInt    *oldLeaves;
170000a1aa47SMatthew G. Knepley   const PetscSFNode *oldRemote;
170100a1aa47SMatthew G. Knepley   PetscInt           nroots, nleaves, noldleaves;
170200a1aa47SMatthew G. Knepley 
170300a1aa47SMatthew G. Knepley   PetscFunctionBegin;
170400a1aa47SMatthew G. Knepley   PetscCall(PetscSFGetGraph(sfMigration, &nroots, &noldleaves, &oldLeaves, &oldRemote));
170500a1aa47SMatthew G. Knepley   PetscCall(PetscSFGetGraph(sfOverlap, NULL, &nleaves, NULL, NULL));
170600a1aa47SMatthew G. Knepley   PetscCall(PetscMalloc1(nleaves, &newRemote));
170700a1aa47SMatthew G. Knepley   /* oldRemote: original root point mapping to original leaf point
170800a1aa47SMatthew G. Knepley      newRemote: original leaf point mapping to overlapped leaf point */
170900a1aa47SMatthew G. Knepley   if (oldLeaves) {
171000a1aa47SMatthew G. Knepley     /* After stratification, the migration remotes may not be in root (canonical) order, so we reorder using the leaf numbering */
171100a1aa47SMatthew G. Knepley     PetscCall(PetscMalloc1(noldleaves, &permRemote));
171200a1aa47SMatthew G. Knepley     for (PetscInt l = 0; l < noldleaves; ++l) permRemote[oldLeaves[l]] = oldRemote[l];
171300a1aa47SMatthew G. Knepley     oldRemote = permRemote;
171400a1aa47SMatthew G. Knepley   }
171500a1aa47SMatthew G. Knepley   PetscCall(PetscSFBcastBegin(sfOverlap, MPIU_2INT, oldRemote, newRemote, MPI_REPLACE));
171600a1aa47SMatthew G. Knepley   PetscCall(PetscSFBcastEnd(sfOverlap, MPIU_2INT, oldRemote, newRemote, MPI_REPLACE));
171700a1aa47SMatthew G. Knepley   if (oldLeaves) PetscCall(PetscFree(oldRemote));
171800a1aa47SMatthew G. Knepley   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfOverlap), sfMigrationNew));
171900a1aa47SMatthew G. Knepley   PetscCall(PetscSFSetGraph(*sfMigrationNew, nroots, nleaves, NULL, PETSC_OWN_POINTER, newRemote, PETSC_OWN_POINTER));
172000a1aa47SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
172100a1aa47SMatthew G. Knepley }
172200a1aa47SMatthew G. Knepley 
17233b8f15a2SMatthew G. Knepley /*@C
172470034214SMatthew G. Knepley   DMPlexDistribute - Distributes the mesh and any associated sections.
172570034214SMatthew G. Knepley 
172620f4b53cSBarry Smith   Collective
172770034214SMatthew G. Knepley 
1728064ec1f3Sprj-   Input Parameters:
172920f4b53cSBarry Smith + dm      - The original `DMPLEX` object
173070034214SMatthew G. Knepley - overlap - The overlap of partitions, 0 is the default
173170034214SMatthew G. Knepley 
1732064ec1f3Sprj-   Output Parameters:
173320f4b53cSBarry Smith + sf         - The `PetscSF` used for point distribution, or `NULL` if not needed
173420f4b53cSBarry Smith - dmParallel - The distributed `DMPLEX` object
173570034214SMatthew G. Knepley 
173670034214SMatthew G. Knepley   Level: intermediate
173770034214SMatthew G. Knepley 
173820f4b53cSBarry Smith   Note:
173920f4b53cSBarry Smith   If the mesh was not distributed, the output `dmParallel` will be `NULL`.
174020f4b53cSBarry Smith 
174120f4b53cSBarry Smith   The user can control the definition of adjacency for the mesh using `DMSetAdjacency()`. They should choose the combination appropriate for the function
174220f4b53cSBarry Smith   representation on the mesh.
174320f4b53cSBarry Smith 
174420f4b53cSBarry Smith .seealso: `DMPLEX`, `DM`, `DMPlexCreate()`, `DMSetAdjacency()`, `DMPlexGetOverlap()`
174570034214SMatthew G. Knepley @*/
1746d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistribute(DM dm, PetscInt overlap, PetscSF *sf, DM *dmParallel)
1747d71ae5a4SJacob Faibussowitsch {
174870034214SMatthew G. Knepley   MPI_Comm         comm;
174915078cd4SMichael Lange   PetscPartitioner partitioner;
1750f8987ae8SMichael Lange   IS               cellPart;
1751f8987ae8SMichael Lange   PetscSection     cellPartSection;
1752cf86098cSMatthew G. Knepley   DM               dmCoord;
1753f8987ae8SMichael Lange   DMLabel          lblPartition, lblMigration;
1754874ddda9SLisandro Dalcin   PetscSF          sfMigration, sfStratified, sfPoint;
175598ba2d7fSLawrence Mitchell   PetscBool        flg, balance;
1756874ddda9SLisandro Dalcin   PetscMPIInt      rank, size;
175770034214SMatthew G. Knepley 
175870034214SMatthew G. Knepley   PetscFunctionBegin;
175970034214SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1760d5c515a1SMatthew G. Knepley   PetscValidLogicalCollectiveInt(dm, overlap, 2);
17614f572ea9SToby Isaac   if (sf) PetscAssertPointer(sf, 3);
17624f572ea9SToby Isaac   PetscAssertPointer(dmParallel, 4);
176370034214SMatthew G. Knepley 
17640c86c063SLisandro Dalcin   if (sf) *sf = NULL;
17650c86c063SLisandro Dalcin   *dmParallel = NULL;
17669566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
17679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
17689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
17693ba16761SJacob Faibussowitsch   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
177070034214SMatthew G. Knepley 
17719566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Distribute, dm, 0, 0, 0));
177215078cd4SMichael Lange   /* Create cell partition */
17739566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_Partition, dm, 0, 0, 0));
17749566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &cellPartSection));
17759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetPartitioner(dm, &partitioner));
17769566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDMPlexPartition(partitioner, dm, NULL, cellPartSection, &cellPart));
17779566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_PartSelf, dm, 0, 0, 0));
1778f8987ae8SMichael Lange   {
1779f8987ae8SMichael Lange     /* Convert partition to DMLabel */
1780825f8a23SLisandro Dalcin     IS              is;
1781825f8a23SLisandro Dalcin     PetscHSetI      ht;
1782f8987ae8SMichael Lange     const PetscInt *points;
17838e330a33SStefano Zampini     PetscInt       *iranks;
17848e330a33SStefano Zampini     PetscInt        pStart, pEnd, proc, npoints, poff = 0, nranks;
1785825f8a23SLisandro Dalcin 
17869566063dSJacob Faibussowitsch     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Point Partition", &lblPartition));
1787825f8a23SLisandro Dalcin     /* Preallocate strata */
17889566063dSJacob Faibussowitsch     PetscCall(PetscHSetICreate(&ht));
17899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(cellPartSection, &pStart, &pEnd));
1790825f8a23SLisandro Dalcin     for (proc = pStart; proc < pEnd; proc++) {
17919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cellPartSection, proc, &npoints));
17929566063dSJacob Faibussowitsch       if (npoints) PetscCall(PetscHSetIAdd(ht, proc));
1793825f8a23SLisandro Dalcin     }
17949566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetSize(ht, &nranks));
17959566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nranks, &iranks));
17969566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetElems(ht, &poff, iranks));
17979566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&ht));
17989566063dSJacob Faibussowitsch     PetscCall(DMLabelAddStrata(lblPartition, nranks, iranks));
17999566063dSJacob Faibussowitsch     PetscCall(PetscFree(iranks));
1800825f8a23SLisandro Dalcin     /* Inline DMPlexPartitionLabelClosure() */
18019566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(cellPart, &points));
18029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(cellPartSection, &pStart, &pEnd));
1803f8987ae8SMichael Lange     for (proc = pStart; proc < pEnd; proc++) {
18049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(cellPartSection, proc, &npoints));
1805825f8a23SLisandro Dalcin       if (!npoints) continue;
18069566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(cellPartSection, proc, &poff));
18079566063dSJacob Faibussowitsch       PetscCall(DMPlexClosurePoints_Private(dm, npoints, points + poff, &is));
18089566063dSJacob Faibussowitsch       PetscCall(DMLabelSetStratumIS(lblPartition, proc, is));
18099566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is));
1810f8987ae8SMichael Lange     }
18119566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(cellPart, &points));
1812f8987ae8SMichael Lange   }
18139566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_PartSelf, dm, 0, 0, 0));
18146e203dd9SStefano Zampini 
18159566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Point migration", &lblMigration));
18169566063dSJacob Faibussowitsch   PetscCall(DMPlexPartitionLabelInvert(dm, lblPartition, NULL, lblMigration));
18173ac0285dSStefano Zampini   PetscCall(DMPlexPartitionLabelCreateSF(dm, lblMigration, PETSC_TRUE, &sfMigration));
18189566063dSJacob Faibussowitsch   PetscCall(DMPlexStratifyMigrationSF(dm, sfMigration, &sfStratified));
18199566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfMigration));
182043f7d02bSMichael Lange   sfMigration = sfStratified;
18219566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sfMigration));
18229566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Partition, dm, 0, 0, 0));
18239566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-partition_view", &flg));
182470034214SMatthew G. Knepley   if (flg) {
18259566063dSJacob Faibussowitsch     PetscCall(DMLabelView(lblPartition, PETSC_VIEWER_STDOUT_(comm)));
18269566063dSJacob Faibussowitsch     PetscCall(PetscSFView(sfMigration, PETSC_VIEWER_STDOUT_(comm)));
182770034214SMatthew G. Knepley   }
1828f8987ae8SMichael Lange 
182915078cd4SMichael Lange   /* Create non-overlapping parallel DM and migrate internal data */
18309566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(comm, dmParallel));
18319566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*dmParallel, "Parallel Mesh"));
18329566063dSJacob Faibussowitsch   PetscCall(DMPlexMigrate(dm, sfMigration, *dmParallel));
183370034214SMatthew G. Knepley 
1834a157612eSMichael Lange   /* Build the point SF without overlap */
18359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetPartitionBalance(dm, &balance));
18369566063dSJacob Faibussowitsch   PetscCall(DMPlexSetPartitionBalance(*dmParallel, balance));
18379566063dSJacob Faibussowitsch   PetscCall(DMPlexCreatePointSF(*dmParallel, sfMigration, PETSC_TRUE, &sfPoint));
18389566063dSJacob Faibussowitsch   PetscCall(DMSetPointSF(*dmParallel, sfPoint));
18395f06a3ddSJed Brown   PetscCall(DMPlexMigrateIsoperiodicFaceSF_Internal(dm, *dmParallel, sfMigration));
18409566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(*dmParallel, &dmCoord));
18419566063dSJacob Faibussowitsch   if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint));
18429566063dSJacob Faibussowitsch   if (flg) PetscCall(PetscSFView(sfPoint, NULL));
184370034214SMatthew G. Knepley 
1844a157612eSMichael Lange   if (overlap > 0) {
184515078cd4SMichael Lange     DM      dmOverlap;
184615078cd4SMichael Lange     PetscSF sfOverlap, sfOverlapPoint;
1847524e35f8SStefano Zampini 
1848a157612eSMichael Lange     /* Add the partition overlap to the distributed DM */
18499566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeOverlap(*dmParallel, overlap, &sfOverlap, &dmOverlap));
18509566063dSJacob Faibussowitsch     PetscCall(DMDestroy(dmParallel));
1851a157612eSMichael Lange     *dmParallel = dmOverlap;
1852c389ea9fSToby Isaac     if (flg) {
18539566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "Overlap Migration SF:\n"));
18549566063dSJacob Faibussowitsch       PetscCall(PetscSFView(sfOverlap, NULL));
1855c389ea9fSToby Isaac     }
185643331d4aSMichael Lange 
1857f8987ae8SMichael Lange     /* Re-map the migration SF to establish the full migration pattern */
185800a1aa47SMatthew G. Knepley     PetscCall(DMPlexRemapMigrationSF(sfOverlap, sfMigration, &sfOverlapPoint));
18599566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sfOverlap));
18609566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sfMigration));
186115078cd4SMichael Lange     sfMigration = sfOverlapPoint;
1862c389ea9fSToby Isaac   }
1863bf5244c7SMatthew G. Knepley   /* Cleanup Partition */
18649566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lblPartition));
18659566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lblMigration));
18669566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&cellPartSection));
18679566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellPart));
186812a88998SMatthew G. Knepley   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, *dmParallel));
186912a88998SMatthew G. Knepley   // Create sfNatural, need discretization information
18709566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *dmParallel));
187166fe0bfeSMatthew G. Knepley   if (dm->useNatural) {
187266fe0bfeSMatthew G. Knepley     PetscSection section;
187366fe0bfeSMatthew G. Knepley 
1874fc6a3818SBlaise Bourdin     PetscCall(DMSetUseNatural(*dmParallel, PETSC_TRUE));
1875fc6a3818SBlaise Bourdin     PetscCall(DMGetLocalSection(dm, &section));
1876fc6a3818SBlaise Bourdin 
18778aee0f92SAlexis Marboeuf     /* First DM with useNatural = PETSC_TRUE is considered natural */
18788aee0f92SAlexis Marboeuf     /* sfMigration and sfNatural are respectively the point and dofs SFs mapping to this natural DM */
1879fc6a3818SBlaise Bourdin     /* Compose with a previous sfNatural if present */
1880fc6a3818SBlaise Bourdin     if (dm->sfNatural) {
1881fc6a3818SBlaise Bourdin       PetscSF natSF;
1882fc6a3818SBlaise Bourdin 
1883fc6a3818SBlaise Bourdin       PetscCall(DMPlexCreateGlobalToNaturalSF(*dmParallel, section, sfMigration, &natSF));
1884fc6a3818SBlaise Bourdin       PetscCall(PetscSFCompose(dm->sfNatural, natSF, &(*dmParallel)->sfNatural));
1885fc6a3818SBlaise Bourdin       PetscCall(PetscSFDestroy(&natSF));
1886fc6a3818SBlaise Bourdin     } else {
1887fc6a3818SBlaise Bourdin       PetscCall(DMPlexCreateGlobalToNaturalSF(*dmParallel, section, sfMigration, &(*dmParallel)->sfNatural));
1888fc6a3818SBlaise Bourdin     }
18898aee0f92SAlexis Marboeuf     /* Compose with a previous sfMigration if present */
18908aee0f92SAlexis Marboeuf     if (dm->sfMigration) {
18918aee0f92SAlexis Marboeuf       PetscSF naturalPointSF;
18928aee0f92SAlexis Marboeuf 
18938aee0f92SAlexis Marboeuf       PetscCall(PetscSFCompose(dm->sfMigration, sfMigration, &naturalPointSF));
18948aee0f92SAlexis Marboeuf       PetscCall(PetscSFDestroy(&sfMigration));
18958aee0f92SAlexis Marboeuf       sfMigration = naturalPointSF;
18968aee0f92SAlexis Marboeuf     }
189766fe0bfeSMatthew G. Knepley   }
1898721cbd76SMatthew G. Knepley   /* Cleanup */
18999371c9d4SSatish Balay   if (sf) {
19009371c9d4SSatish Balay     *sf = sfMigration;
19019371c9d4SSatish Balay   } else PetscCall(PetscSFDestroy(&sfMigration));
19029566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfPoint));
19039566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_Distribute, dm, 0, 0, 0));
19043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
190570034214SMatthew G. Knepley }
1906a157612eSMichael Lange 
1907907a3e9cSStefano Zampini PetscErrorCode DMPlexDistributeOverlap_Internal(DM dm, PetscInt overlap, MPI_Comm newcomm, const char *ovlboundary, PetscSF *sf, DM *dmOverlap)
1908907a3e9cSStefano Zampini {
1909907a3e9cSStefano Zampini   DM_Plex     *mesh = (DM_Plex *)dm->data;
1910907a3e9cSStefano Zampini   MPI_Comm     comm;
1911907a3e9cSStefano Zampini   PetscMPIInt  size, rank;
1912907a3e9cSStefano Zampini   PetscSection rootSection, leafSection;
1913907a3e9cSStefano Zampini   IS           rootrank, leafrank;
1914907a3e9cSStefano Zampini   DM           dmCoord;
1915907a3e9cSStefano Zampini   DMLabel      lblOverlap;
1916907a3e9cSStefano Zampini   PetscSF      sfOverlap, sfStratified, sfPoint;
1917907a3e9cSStefano Zampini   PetscBool    clear_ovlboundary;
1918907a3e9cSStefano Zampini 
1919907a3e9cSStefano Zampini   PetscFunctionBegin;
1920907a3e9cSStefano Zampini   if (sf) *sf = NULL;
1921907a3e9cSStefano Zampini   *dmOverlap = NULL;
1922907a3e9cSStefano Zampini   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1923907a3e9cSStefano Zampini   PetscCallMPI(MPI_Comm_size(comm, &size));
1924907a3e9cSStefano Zampini   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1925907a3e9cSStefano Zampini   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
1926907a3e9cSStefano Zampini   {
1927907a3e9cSStefano Zampini     // We need to get options for the _already_distributed mesh, so it must be done here
1928907a3e9cSStefano Zampini     PetscInt    overlap;
1929907a3e9cSStefano Zampini     const char *prefix;
1930907a3e9cSStefano Zampini     char        oldPrefix[PETSC_MAX_PATH_LEN];
1931907a3e9cSStefano Zampini 
1932907a3e9cSStefano Zampini     oldPrefix[0] = '\0';
1933907a3e9cSStefano Zampini     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
1934907a3e9cSStefano Zampini     PetscCall(PetscStrncpy(oldPrefix, prefix, sizeof(oldPrefix)));
1935907a3e9cSStefano Zampini     PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, "dist_"));
1936907a3e9cSStefano Zampini     PetscCall(DMPlexGetOverlap(dm, &overlap));
1937907a3e9cSStefano Zampini     PetscObjectOptionsBegin((PetscObject)dm);
1938907a3e9cSStefano Zampini     PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap));
1939907a3e9cSStefano Zampini     PetscOptionsEnd();
1940907a3e9cSStefano Zampini     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldPrefix[0] == '\0' ? NULL : oldPrefix));
1941907a3e9cSStefano Zampini   }
1942907a3e9cSStefano Zampini   if (ovlboundary) {
1943907a3e9cSStefano Zampini     PetscBool flg;
1944907a3e9cSStefano Zampini     PetscCall(DMHasLabel(dm, ovlboundary, &flg));
1945907a3e9cSStefano Zampini     if (!flg) {
1946907a3e9cSStefano Zampini       DMLabel label;
1947907a3e9cSStefano Zampini 
1948907a3e9cSStefano Zampini       PetscCall(DMCreateLabel(dm, ovlboundary));
1949907a3e9cSStefano Zampini       PetscCall(DMGetLabel(dm, ovlboundary, &label));
1950907a3e9cSStefano Zampini       PetscCall(DMPlexMarkBoundaryFaces(dm, 1, label));
1951907a3e9cSStefano Zampini       clear_ovlboundary = PETSC_TRUE;
1952907a3e9cSStefano Zampini     }
1953907a3e9cSStefano Zampini   }
1954907a3e9cSStefano Zampini   PetscCall(PetscLogEventBegin(DMPLEX_DistributeOverlap, dm, 0, 0, 0));
1955907a3e9cSStefano Zampini   /* Compute point overlap with neighbouring processes on the distributed DM */
1956907a3e9cSStefano Zampini   PetscCall(PetscLogEventBegin(DMPLEX_Partition, dm, 0, 0, 0));
1957907a3e9cSStefano Zampini   PetscCall(PetscSectionCreate(newcomm, &rootSection));
1958907a3e9cSStefano Zampini   PetscCall(PetscSectionCreate(newcomm, &leafSection));
1959907a3e9cSStefano Zampini   PetscCall(DMPlexDistributeOwnership(dm, rootSection, &rootrank, leafSection, &leafrank));
1960907a3e9cSStefano Zampini   if (mesh->numOvLabels) PetscCall(DMPlexCreateOverlapLabelFromLabels(dm, mesh->numOvLabels, mesh->ovLabels, mesh->ovValues, mesh->numOvExLabels, mesh->ovExLabels, mesh->ovExValues, rootSection, rootrank, leafSection, leafrank, &lblOverlap));
1961907a3e9cSStefano Zampini   else PetscCall(DMPlexCreateOverlapLabel(dm, overlap, rootSection, rootrank, leafSection, leafrank, &lblOverlap));
1962907a3e9cSStefano Zampini   /* Convert overlap label to stratified migration SF */
19633ac0285dSStefano Zampini   PetscCall(DMPlexPartitionLabelCreateSF(dm, lblOverlap, PETSC_FALSE, &sfOverlap));
1964907a3e9cSStefano Zampini   PetscCall(DMPlexStratifyMigrationSF(dm, sfOverlap, &sfStratified));
1965907a3e9cSStefano Zampini   PetscCall(PetscSFDestroy(&sfOverlap));
1966907a3e9cSStefano Zampini   sfOverlap = sfStratified;
1967907a3e9cSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)sfOverlap, "Overlap SF"));
1968907a3e9cSStefano Zampini   PetscCall(PetscSFSetFromOptions(sfOverlap));
1969907a3e9cSStefano Zampini 
1970907a3e9cSStefano Zampini   PetscCall(PetscSectionDestroy(&rootSection));
1971907a3e9cSStefano Zampini   PetscCall(PetscSectionDestroy(&leafSection));
1972907a3e9cSStefano Zampini   PetscCall(ISDestroy(&rootrank));
1973907a3e9cSStefano Zampini   PetscCall(ISDestroy(&leafrank));
1974907a3e9cSStefano Zampini   PetscCall(PetscLogEventEnd(DMPLEX_Partition, dm, 0, 0, 0));
1975907a3e9cSStefano Zampini 
1976907a3e9cSStefano Zampini   /* Build the overlapping DM */
1977907a3e9cSStefano Zampini   PetscCall(DMPlexCreate(newcomm, dmOverlap));
1978907a3e9cSStefano Zampini   PetscCall(PetscObjectSetName((PetscObject)*dmOverlap, "Parallel Mesh"));
1979907a3e9cSStefano Zampini   PetscCall(DMPlexMigrate(dm, sfOverlap, *dmOverlap));
1980907a3e9cSStefano Zampini   /* Store the overlap in the new DM */
1981907a3e9cSStefano Zampini   PetscCall(DMPlexSetOverlap_Plex(*dmOverlap, dm, overlap));
1982907a3e9cSStefano Zampini   /* Build the new point SF */
1983907a3e9cSStefano Zampini   PetscCall(DMPlexCreatePointSF(*dmOverlap, sfOverlap, PETSC_FALSE, &sfPoint));
1984907a3e9cSStefano Zampini   PetscCall(DMSetPointSF(*dmOverlap, sfPoint));
1985907a3e9cSStefano Zampini   PetscCall(DMGetCoordinateDM(*dmOverlap, &dmCoord));
1986907a3e9cSStefano Zampini   if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint));
1987907a3e9cSStefano Zampini   PetscCall(DMGetCellCoordinateDM(*dmOverlap, &dmCoord));
1988907a3e9cSStefano Zampini   if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint));
1989907a3e9cSStefano Zampini   PetscCall(PetscSFDestroy(&sfPoint));
1990907a3e9cSStefano Zampini   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, *dmOverlap));
1991907a3e9cSStefano Zampini   /* TODO: labels stored inside the DS for regions should be handled here */
1992907a3e9cSStefano Zampini   PetscCall(DMCopyDisc(dm, *dmOverlap));
1993907a3e9cSStefano Zampini   /* Cleanup overlap partition */
1994907a3e9cSStefano Zampini   PetscCall(DMLabelDestroy(&lblOverlap));
1995907a3e9cSStefano Zampini   if (sf) *sf = sfOverlap;
1996907a3e9cSStefano Zampini   else PetscCall(PetscSFDestroy(&sfOverlap));
1997907a3e9cSStefano Zampini   if (ovlboundary) {
1998907a3e9cSStefano Zampini     DMLabel   label;
1999907a3e9cSStefano Zampini     PetscBool flg;
2000907a3e9cSStefano Zampini 
2001907a3e9cSStefano Zampini     if (clear_ovlboundary) PetscCall(DMRemoveLabel(dm, ovlboundary, NULL));
2002907a3e9cSStefano Zampini     PetscCall(DMHasLabel(*dmOverlap, ovlboundary, &flg));
200300045ab3SPierre Jolivet     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing %s label", ovlboundary);
2004907a3e9cSStefano Zampini     PetscCall(DMGetLabel(*dmOverlap, ovlboundary, &label));
2005907a3e9cSStefano Zampini     PetscCall(DMPlexMarkBoundaryFaces_Internal(*dmOverlap, 1, 0, label, PETSC_TRUE));
2006907a3e9cSStefano Zampini   }
2007907a3e9cSStefano Zampini   PetscCall(PetscLogEventEnd(DMPLEX_DistributeOverlap, dm, 0, 0, 0));
2008907a3e9cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
2009907a3e9cSStefano Zampini }
2010907a3e9cSStefano Zampini 
2011a157612eSMichael Lange /*@C
201220f4b53cSBarry Smith   DMPlexDistributeOverlap - Add partition overlap to a distributed non-overlapping `DM`.
2013a157612eSMichael Lange 
201420f4b53cSBarry Smith   Collective
2015a157612eSMichael Lange 
2016064ec1f3Sprj-   Input Parameters:
201720f4b53cSBarry Smith + dm      - The non-overlapping distributed `DMPLEX` object
201857fe9a49SVaclav Hapla - overlap - The overlap of partitions (the same on all ranks)
2019a157612eSMichael Lange 
2020064ec1f3Sprj-   Output Parameters:
2021*f13dfd9eSBarry Smith + sf        - The `PetscSF` used for point distribution, or pass `NULL` if not needed
2022*f13dfd9eSBarry Smith - dmOverlap - The overlapping distributed `DMPLEX` object
2023a157612eSMichael Lange 
2024c506a872SMatthew G. Knepley   Options Database Keys:
2025c506a872SMatthew G. Knepley + -dm_plex_overlap_labels <name1,name2,...> - List of overlap label names
2026c506a872SMatthew G. Knepley . -dm_plex_overlap_values <int1,int2,...>   - List of overlap label values
2027c506a872SMatthew G. Knepley . -dm_plex_overlap_exclude_label <name>     - Label used to exclude points from overlap
2028c506a872SMatthew G. Knepley - -dm_plex_overlap_exclude_value <int>      - Label value used to exclude points from overlap
2029c506a872SMatthew G. Knepley 
2030dccdeccaSVaclav Hapla   Level: advanced
2031a157612eSMichael Lange 
203220f4b53cSBarry Smith   Notes:
203320f4b53cSBarry Smith   If the mesh was not distributed, the return value is `NULL`.
203420f4b53cSBarry Smith 
203520f4b53cSBarry Smith   The user can control the definition of adjacency for the mesh using `DMSetAdjacency()`. They should choose the combination appropriate for the function
203620f4b53cSBarry Smith   representation on the mesh.
203720f4b53cSBarry Smith 
203820f4b53cSBarry Smith .seealso: `DMPLEX`, `PetscSF`, `DM`, `DMPlexCreate()`, `DMSetAdjacency()`, `DMPlexDistribute()`, `DMPlexCreateOverlapLabel()`, `DMPlexGetOverlap()`
2039a157612eSMichael Lange @*/
2040d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributeOverlap(DM dm, PetscInt overlap, PetscSF *sf, DM *dmOverlap)
2041d71ae5a4SJacob Faibussowitsch {
2042a157612eSMichael Lange   PetscFunctionBegin;
2043a157612eSMichael Lange   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
204457fe9a49SVaclav Hapla   PetscValidLogicalCollectiveInt(dm, overlap, 2);
20454f572ea9SToby Isaac   if (sf) PetscAssertPointer(sf, 3);
20464f572ea9SToby Isaac   PetscAssertPointer(dmOverlap, 4);
2047907a3e9cSStefano Zampini   PetscCall(DMPlexDistributeOverlap_Internal(dm, overlap, PetscObjectComm((PetscObject)dm), NULL, sf, dmOverlap));
20483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2049a157612eSMichael Lange }
20506462276dSToby Isaac 
2051d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetOverlap_Plex(DM dm, PetscInt *overlap)
2052d71ae5a4SJacob Faibussowitsch {
2053cb54e036SVaclav Hapla   DM_Plex *mesh = (DM_Plex *)dm->data;
2054cb54e036SVaclav Hapla 
2055cb54e036SVaclav Hapla   PetscFunctionBegin;
2056cb54e036SVaclav Hapla   *overlap = mesh->overlap;
20573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2058cb54e036SVaclav Hapla }
2059cb54e036SVaclav Hapla 
2060d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetOverlap_Plex(DM dm, DM dmSrc, PetscInt overlap)
2061d71ae5a4SJacob Faibussowitsch {
206260667520SVaclav Hapla   DM_Plex *mesh    = NULL;
206360667520SVaclav Hapla   DM_Plex *meshSrc = NULL;
206460667520SVaclav Hapla 
206560667520SVaclav Hapla   PetscFunctionBegin;
206660667520SVaclav Hapla   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMPLEX);
206760667520SVaclav Hapla   mesh = (DM_Plex *)dm->data;
206860667520SVaclav Hapla   if (dmSrc) {
206960667520SVaclav Hapla     PetscValidHeaderSpecificType(dmSrc, DM_CLASSID, 2, DMPLEX);
207060667520SVaclav Hapla     meshSrc       = (DM_Plex *)dmSrc->data;
20719ed9361bSToby Isaac     mesh->overlap = meshSrc->overlap;
20729ed9361bSToby Isaac   } else {
20739ed9361bSToby Isaac     mesh->overlap = 0;
207460667520SVaclav Hapla   }
20759ed9361bSToby Isaac   mesh->overlap += overlap;
20763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
207760667520SVaclav Hapla }
207860667520SVaclav Hapla 
2079cb54e036SVaclav Hapla /*@
2080c506a872SMatthew G. Knepley   DMPlexGetOverlap - Get the width of the cell overlap
2081cb54e036SVaclav Hapla 
208220f4b53cSBarry Smith   Not Collective
2083cb54e036SVaclav Hapla 
2084cb54e036SVaclav Hapla   Input Parameter:
208520f4b53cSBarry Smith . dm - The `DM`
2086cb54e036SVaclav Hapla 
2087064ec1f3Sprj-   Output Parameter:
2088c506a872SMatthew G. Knepley . overlap - the width of the cell overlap
2089cb54e036SVaclav Hapla 
2090cb54e036SVaclav Hapla   Level: intermediate
2091cb54e036SVaclav Hapla 
209220f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexSetOverlap()`, `DMPlexDistribute()`
2093cb54e036SVaclav Hapla @*/
2094d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetOverlap(DM dm, PetscInt *overlap)
2095d71ae5a4SJacob Faibussowitsch {
2096cb54e036SVaclav Hapla   PetscFunctionBegin;
2097cb54e036SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20984f572ea9SToby Isaac   PetscAssertPointer(overlap, 2);
2099cac4c232SBarry Smith   PetscUseMethod(dm, "DMPlexGetOverlap_C", (DM, PetscInt *), (dm, overlap));
21003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2101cb54e036SVaclav Hapla }
2102cb54e036SVaclav Hapla 
2103c506a872SMatthew G. Knepley /*@
2104c506a872SMatthew G. Knepley   DMPlexSetOverlap - Set the width of the cell overlap
2105c506a872SMatthew G. Knepley 
210620f4b53cSBarry Smith   Logically Collective
2107c506a872SMatthew G. Knepley 
2108c506a872SMatthew G. Knepley   Input Parameters:
210920f4b53cSBarry Smith + dm      - The `DM`
211020f4b53cSBarry Smith . dmSrc   - The `DM` that produced this one, or `NULL`
2111c506a872SMatthew G. Knepley - overlap - the width of the cell overlap
2112c506a872SMatthew G. Knepley 
2113c506a872SMatthew G. Knepley   Level: intermediate
2114c506a872SMatthew G. Knepley 
211520f4b53cSBarry Smith   Note:
211620f4b53cSBarry Smith   The overlap from `dmSrc` is added to `dm`
211720f4b53cSBarry Smith 
211820f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexGetOverlap()`, `DMPlexDistribute()`
2119c506a872SMatthew G. Knepley @*/
2120d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetOverlap(DM dm, DM dmSrc, PetscInt overlap)
2121d71ae5a4SJacob Faibussowitsch {
2122c506a872SMatthew G. Knepley   PetscFunctionBegin;
2123c506a872SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2124c506a872SMatthew G. Knepley   PetscValidLogicalCollectiveInt(dm, overlap, 3);
2125c506a872SMatthew G. Knepley   PetscTryMethod(dm, "DMPlexSetOverlap_C", (DM, DM, PetscInt), (dm, dmSrc, overlap));
21263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2127c506a872SMatthew G. Knepley }
2128c506a872SMatthew G. Knepley 
2129d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributeSetDefault_Plex(DM dm, PetscBool dist)
2130d71ae5a4SJacob Faibussowitsch {
2131e600fa54SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
2132e600fa54SMatthew G. Knepley 
2133e600fa54SMatthew G. Knepley   PetscFunctionBegin;
2134e600fa54SMatthew G. Knepley   mesh->distDefault = dist;
21353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2136e600fa54SMatthew G. Knepley }
2137e600fa54SMatthew G. Knepley 
2138e600fa54SMatthew G. Knepley /*@
213920f4b53cSBarry Smith   DMPlexDistributeSetDefault - Set flag indicating whether the `DM` should be distributed by default
2140e600fa54SMatthew G. Knepley 
214120f4b53cSBarry Smith   Logically Collective
2142e600fa54SMatthew G. Knepley 
2143e600fa54SMatthew G. Knepley   Input Parameters:
214420f4b53cSBarry Smith + dm   - The `DM`
2145e600fa54SMatthew G. Knepley - dist - Flag for distribution
2146e600fa54SMatthew G. Knepley 
2147e600fa54SMatthew G. Knepley   Level: intermediate
2148e600fa54SMatthew G. Knepley 
214920f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexDistributeGetDefault()`, `DMPlexDistribute()`
2150e600fa54SMatthew G. Knepley @*/
2151d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributeSetDefault(DM dm, PetscBool dist)
2152d71ae5a4SJacob Faibussowitsch {
2153e600fa54SMatthew G. Knepley   PetscFunctionBegin;
2154e600fa54SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2155e600fa54SMatthew G. Knepley   PetscValidLogicalCollectiveBool(dm, dist, 2);
2156cac4c232SBarry Smith   PetscTryMethod(dm, "DMPlexDistributeSetDefault_C", (DM, PetscBool), (dm, dist));
21573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2158e600fa54SMatthew G. Knepley }
2159e600fa54SMatthew G. Knepley 
2160d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributeGetDefault_Plex(DM dm, PetscBool *dist)
2161d71ae5a4SJacob Faibussowitsch {
2162e600fa54SMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
2163e600fa54SMatthew G. Knepley 
2164e600fa54SMatthew G. Knepley   PetscFunctionBegin;
2165e600fa54SMatthew G. Knepley   *dist = mesh->distDefault;
21663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2167e600fa54SMatthew G. Knepley }
2168e600fa54SMatthew G. Knepley 
2169e600fa54SMatthew G. Knepley /*@
217020f4b53cSBarry Smith   DMPlexDistributeGetDefault - Get flag indicating whether the `DM` should be distributed by default
2171e600fa54SMatthew G. Knepley 
217220f4b53cSBarry Smith   Not Collective
2173e600fa54SMatthew G. Knepley 
2174e600fa54SMatthew G. Knepley   Input Parameter:
217520f4b53cSBarry Smith . dm - The `DM`
2176e600fa54SMatthew G. Knepley 
2177e600fa54SMatthew G. Knepley   Output Parameter:
2178e600fa54SMatthew G. Knepley . dist - Flag for distribution
2179e600fa54SMatthew G. Knepley 
2180e600fa54SMatthew G. Knepley   Level: intermediate
2181e600fa54SMatthew G. Knepley 
218220f4b53cSBarry Smith .seealso: `DMPLEX`, `DM`, `DMPlexDistributeSetDefault()`, `DMPlexDistribute()`
2183e600fa54SMatthew G. Knepley @*/
2184d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributeGetDefault(DM dm, PetscBool *dist)
2185d71ae5a4SJacob Faibussowitsch {
2186e600fa54SMatthew G. Knepley   PetscFunctionBegin;
2187e600fa54SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
21884f572ea9SToby Isaac   PetscAssertPointer(dist, 2);
2189cac4c232SBarry Smith   PetscUseMethod(dm, "DMPlexDistributeGetDefault_C", (DM, PetscBool *), (dm, dist));
21903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2191e600fa54SMatthew G. Knepley }
2192e600fa54SMatthew G. Knepley 
21936462276dSToby Isaac /*@C
219420f4b53cSBarry Smith   DMPlexGetGatherDM - Get a copy of the `DMPLEX` that gathers all points on the
21956462276dSToby Isaac   root process of the original's communicator.
21966462276dSToby Isaac 
219720f4b53cSBarry Smith   Collective
219883655b49SVáclav Hapla 
2199064ec1f3Sprj-   Input Parameter:
220020f4b53cSBarry Smith . dm - the original `DMPLEX` object
22016462276dSToby Isaac 
22026462276dSToby Isaac   Output Parameters:
220320f4b53cSBarry Smith + sf         - the `PetscSF` used for point distribution (optional)
220420f4b53cSBarry Smith - gatherMesh - the gathered `DM` object, or `NULL`
22056462276dSToby Isaac 
22066462276dSToby Isaac   Level: intermediate
22076462276dSToby Isaac 
220820f4b53cSBarry Smith .seealso: `DMPLEX`, `DM`, `PetscSF`, `DMPlexDistribute()`, `DMPlexGetRedundantDM()`
22096462276dSToby Isaac @*/
2210d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGatherDM(DM dm, PetscSF *sf, DM *gatherMesh)
2211d71ae5a4SJacob Faibussowitsch {
22126462276dSToby Isaac   MPI_Comm         comm;
22136462276dSToby Isaac   PetscMPIInt      size;
22146462276dSToby Isaac   PetscPartitioner oldPart, gatherPart;
22156462276dSToby Isaac 
22166462276dSToby Isaac   PetscFunctionBegin;
22176462276dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22184f572ea9SToby Isaac   PetscAssertPointer(gatherMesh, 3);
22190c86c063SLisandro Dalcin   *gatherMesh = NULL;
2220a13df41bSStefano Zampini   if (sf) *sf = NULL;
22216462276dSToby Isaac   comm = PetscObjectComm((PetscObject)dm);
22229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
22233ba16761SJacob Faibussowitsch   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
22249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetPartitioner(dm, &oldPart));
22259566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)oldPart));
22269566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerCreate(comm, &gatherPart));
22279566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerSetType(gatherPart, PETSCPARTITIONERGATHER));
22289566063dSJacob Faibussowitsch   PetscCall(DMPlexSetPartitioner(dm, gatherPart));
22299566063dSJacob Faibussowitsch   PetscCall(DMPlexDistribute(dm, 0, sf, gatherMesh));
2230a13df41bSStefano Zampini 
22319566063dSJacob Faibussowitsch   PetscCall(DMPlexSetPartitioner(dm, oldPart));
22329566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&gatherPart));
22339566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&oldPart));
22343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22356462276dSToby Isaac }
22366462276dSToby Isaac 
22376462276dSToby Isaac /*@C
223820f4b53cSBarry Smith   DMPlexGetRedundantDM - Get a copy of the `DMPLEX` that is completely copied on each process.
22396462276dSToby Isaac 
224020f4b53cSBarry Smith   Collective
224183655b49SVáclav Hapla 
2242064ec1f3Sprj-   Input Parameter:
224320f4b53cSBarry Smith . dm - the original `DMPLEX` object
22446462276dSToby Isaac 
22456462276dSToby Isaac   Output Parameters:
224620f4b53cSBarry Smith + sf            - the `PetscSF` used for point distribution (optional)
224720f4b53cSBarry Smith - redundantMesh - the redundant `DM` object, or `NULL`
22486462276dSToby Isaac 
22496462276dSToby Isaac   Level: intermediate
22506462276dSToby Isaac 
225160225df5SJacob Faibussowitsch .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexGetGatherDM()`
22526462276dSToby Isaac @*/
2253d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetRedundantDM(DM dm, PetscSF *sf, DM *redundantMesh)
2254d71ae5a4SJacob Faibussowitsch {
22556462276dSToby Isaac   MPI_Comm     comm;
22566462276dSToby Isaac   PetscMPIInt  size, rank;
22576462276dSToby Isaac   PetscInt     pStart, pEnd, p;
22586462276dSToby Isaac   PetscInt     numPoints = -1;
2259a13df41bSStefano Zampini   PetscSF      migrationSF, sfPoint, gatherSF;
22606462276dSToby Isaac   DM           gatherDM, dmCoord;
22616462276dSToby Isaac   PetscSFNode *points;
22626462276dSToby Isaac 
22636462276dSToby Isaac   PetscFunctionBegin;
22646462276dSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22654f572ea9SToby Isaac   PetscAssertPointer(redundantMesh, 3);
22660c86c063SLisandro Dalcin   *redundantMesh = NULL;
22676462276dSToby Isaac   comm           = PetscObjectComm((PetscObject)dm);
22689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
226968dbc166SMatthew G. Knepley   if (size == 1) {
22709566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
227168dbc166SMatthew G. Knepley     *redundantMesh = dm;
2272a13df41bSStefano Zampini     if (sf) *sf = NULL;
22733ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
227468dbc166SMatthew G. Knepley   }
22759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGatherDM(dm, &gatherSF, &gatherDM));
22763ba16761SJacob Faibussowitsch   if (!gatherDM) PetscFunctionReturn(PETSC_SUCCESS);
22779566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
22789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(gatherDM, &pStart, &pEnd));
22796462276dSToby Isaac   numPoints = pEnd - pStart;
22809566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&numPoints, 1, MPIU_INT, 0, comm));
22819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &points));
22829566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &migrationSF));
22836462276dSToby Isaac   for (p = 0; p < numPoints; p++) {
22846462276dSToby Isaac     points[p].index = p;
22856462276dSToby Isaac     points[p].rank  = 0;
22866462276dSToby Isaac   }
22879566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(migrationSF, pEnd - pStart, numPoints, NULL, PETSC_OWN_POINTER, points, PETSC_OWN_POINTER));
22889566063dSJacob Faibussowitsch   PetscCall(DMPlexCreate(comm, redundantMesh));
22899566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*redundantMesh, "Redundant Mesh"));
22909566063dSJacob Faibussowitsch   PetscCall(DMPlexMigrate(gatherDM, migrationSF, *redundantMesh));
22912e28cf0cSVaclav Hapla   /* This is to express that all point are in overlap */
22922e28cf0cSVaclav Hapla   PetscCall(DMPlexSetOverlap_Plex(*redundantMesh, NULL, PETSC_MAX_INT));
22939566063dSJacob Faibussowitsch   PetscCall(DMPlexCreatePointSF(*redundantMesh, migrationSF, PETSC_FALSE, &sfPoint));
22949566063dSJacob Faibussowitsch   PetscCall(DMSetPointSF(*redundantMesh, sfPoint));
22959566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(*redundantMesh, &dmCoord));
22969566063dSJacob Faibussowitsch   if (dmCoord) PetscCall(DMSetPointSF(dmCoord, sfPoint));
22979566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfPoint));
2298a13df41bSStefano Zampini   if (sf) {
2299a13df41bSStefano Zampini     PetscSF tsf;
2300a13df41bSStefano Zampini 
23019566063dSJacob Faibussowitsch     PetscCall(PetscSFCompose(gatherSF, migrationSF, &tsf));
23029566063dSJacob Faibussowitsch     PetscCall(DMPlexStratifyMigrationSF(dm, tsf, sf));
23039566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&tsf));
2304a13df41bSStefano Zampini   }
23059566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&migrationSF));
23069566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&gatherSF));
23079566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&gatherDM));
23089566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *redundantMesh));
23095de52c6dSVaclav Hapla   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, *redundantMesh));
23103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23116462276dSToby Isaac }
23125fa78c88SVaclav Hapla 
23135fa78c88SVaclav Hapla /*@
231420f4b53cSBarry Smith   DMPlexIsDistributed - Find out whether this `DM` is distributed, i.e. more than one rank owns some points.
23155fa78c88SVaclav Hapla 
23165fa78c88SVaclav Hapla   Collective
23175fa78c88SVaclav Hapla 
23185fa78c88SVaclav Hapla   Input Parameter:
231920f4b53cSBarry Smith . dm - The `DM` object
23205fa78c88SVaclav Hapla 
23215fa78c88SVaclav Hapla   Output Parameter:
232220f4b53cSBarry Smith . distributed - Flag whether the `DM` is distributed
23235fa78c88SVaclav Hapla 
23245fa78c88SVaclav Hapla   Level: intermediate
23255fa78c88SVaclav Hapla 
23265fa78c88SVaclav Hapla   Notes:
23275fa78c88SVaclav Hapla   This currently finds out whether at least two ranks have any DAG points.
232820f4b53cSBarry Smith   This involves `MPI_Allreduce()` with one integer.
23295fa78c88SVaclav Hapla   The result is currently not stashed so every call to this routine involves this global communication.
23305fa78c88SVaclav Hapla 
233160225df5SJacob Faibussowitsch .seealso: `DMPLEX`, `DMPlexDistribute()`, `DMPlexGetOverlap()`, `DMPlexIsInterpolated()`
23325fa78c88SVaclav Hapla @*/
2333d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexIsDistributed(DM dm, PetscBool *distributed)
2334d71ae5a4SJacob Faibussowitsch {
23355fa78c88SVaclav Hapla   PetscInt    pStart, pEnd, count;
23365fa78c88SVaclav Hapla   MPI_Comm    comm;
233735d70e31SStefano Zampini   PetscMPIInt size;
23385fa78c88SVaclav Hapla 
23395fa78c88SVaclav Hapla   PetscFunctionBegin;
23405fa78c88SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
23414f572ea9SToby Isaac   PetscAssertPointer(distributed, 2);
23429566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
23439566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
23449371c9d4SSatish Balay   if (size == 1) {
23459371c9d4SSatish Balay     *distributed = PETSC_FALSE;
23463ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
23479371c9d4SSatish Balay   }
23489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
234935d70e31SStefano Zampini   count = (pEnd - pStart) > 0 ? 1 : 0;
2350712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &count, 1, MPIU_INT, MPI_SUM, comm));
23515fa78c88SVaclav Hapla   *distributed = count > 1 ? PETSC_TRUE : PETSC_FALSE;
23523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23535fa78c88SVaclav Hapla }
23541d1f2f2aSksagiyam 
23551d1f2f2aSksagiyam /*@C
23561d1f2f2aSksagiyam   DMPlexDistributionSetName - Set the name of the specific parallel distribution
23571d1f2f2aSksagiyam 
23581d1f2f2aSksagiyam   Input Parameters:
235920f4b53cSBarry Smith + dm   - The `DM`
23601d1f2f2aSksagiyam - name - The name of the specific parallel distribution
23611d1f2f2aSksagiyam 
23621d1f2f2aSksagiyam   Level: developer
23631d1f2f2aSksagiyam 
236420f4b53cSBarry Smith   Note:
236520f4b53cSBarry Smith   If distribution name is set when saving, `DMPlexTopologyView()` saves the plex's
236620f4b53cSBarry Smith   parallel distribution (i.e., partition, ownership, and local ordering of points) under
236720f4b53cSBarry Smith   this name. Conversely, if distribution name is set when loading, `DMPlexTopologyLoad()`
236820f4b53cSBarry Smith   loads the parallel distribution stored in file under this name.
236920f4b53cSBarry Smith 
237020f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexDistributionGetName()`, `DMPlexTopologyView()`, `DMPlexTopologyLoad()`
23711d1f2f2aSksagiyam @*/
2372d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributionSetName(DM dm, const char name[])
2373d71ae5a4SJacob Faibussowitsch {
23741d1f2f2aSksagiyam   DM_Plex *mesh = (DM_Plex *)dm->data;
23751d1f2f2aSksagiyam 
23761d1f2f2aSksagiyam   PetscFunctionBegin;
23771d1f2f2aSksagiyam   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMPLEX);
23784f572ea9SToby Isaac   if (name) PetscAssertPointer(name, 2);
23791d1f2f2aSksagiyam   PetscCall(PetscFree(mesh->distributionName));
23801d1f2f2aSksagiyam   PetscCall(PetscStrallocpy(name, &mesh->distributionName));
23813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23821d1f2f2aSksagiyam }
23831d1f2f2aSksagiyam 
23841d1f2f2aSksagiyam /*@C
23851d1f2f2aSksagiyam   DMPlexDistributionGetName - Retrieve the name of the specific parallel distribution
23861d1f2f2aSksagiyam 
23871d1f2f2aSksagiyam   Input Parameter:
238820f4b53cSBarry Smith . dm - The `DM`
23891d1f2f2aSksagiyam 
23901d1f2f2aSksagiyam   Output Parameter:
23911d1f2f2aSksagiyam . name - The name of the specific parallel distribution
23921d1f2f2aSksagiyam 
23931d1f2f2aSksagiyam   Level: developer
23941d1f2f2aSksagiyam 
239520f4b53cSBarry Smith   Note:
239620f4b53cSBarry Smith   If distribution name is set when saving, `DMPlexTopologyView()` saves the plex's
239720f4b53cSBarry Smith   parallel distribution (i.e., partition, ownership, and local ordering of points) under
239820f4b53cSBarry Smith   this name. Conversely, if distribution name is set when loading, `DMPlexTopologyLoad()`
239920f4b53cSBarry Smith   loads the parallel distribution stored in file under this name.
240020f4b53cSBarry Smith 
240120f4b53cSBarry Smith .seealso: `DMPLEX`, `DMPlexDistributionSetName()`, `DMPlexTopologyView()`, `DMPlexTopologyLoad()`
24021d1f2f2aSksagiyam @*/
2403d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexDistributionGetName(DM dm, const char *name[])
2404d71ae5a4SJacob Faibussowitsch {
24051d1f2f2aSksagiyam   DM_Plex *mesh = (DM_Plex *)dm->data;
24061d1f2f2aSksagiyam 
24071d1f2f2aSksagiyam   PetscFunctionBegin;
24081d1f2f2aSksagiyam   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMPLEX);
24094f572ea9SToby Isaac   PetscAssertPointer(name, 2);
24101d1f2f2aSksagiyam   *name = mesh->distributionName;
24113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24121d1f2f2aSksagiyam }
2413