xref: /petsc/src/dm/impls/plex/plexpartition.c (revision 5f80ce2ab25dff0f4601e710601cbbcecf323266)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2abe9303eSLisandro Dalcin #include <petsc/private/partitionerimpl.h>
3e8f14785SLisandro Dalcin #include <petsc/private/hashseti.h>
470034214SMatthew G. Knepley 
54b876568SBarry Smith const char * const DMPlexCSRAlgorithms[] = {"mat", "graph", "overlap", "DMPlexCSRAlgorithm", "DM_PLEX_CSR_",NULL};
65a107427SMatthew G. Knepley 
79fbee547SJacob Faibussowitsch static inline PetscInt DMPlex_GlobalID(PetscInt point) { return point >= 0 ? point : -(point+1); }
80134a67bSLisandro Dalcin 
95a107427SMatthew G. Knepley static PetscErrorCode DMPlexCreatePartitionerGraph_Overlap(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
105a107427SMatthew G. Knepley {
115a107427SMatthew G. Knepley   DM              ovdm;
125a107427SMatthew G. Knepley   PetscSF         sfPoint;
135a107427SMatthew G. Knepley   IS              cellNumbering;
145a107427SMatthew G. Knepley   const PetscInt *cellNum;
155a107427SMatthew G. Knepley   PetscInt       *adj = NULL, *vOffsets = NULL, *vAdj = NULL;
165a107427SMatthew G. Knepley   PetscBool       useCone, useClosure;
175a107427SMatthew G. Knepley   PetscInt        dim, depth, overlap, cStart, cEnd, c, v;
185a107427SMatthew G. Knepley   PetscMPIInt     rank, size;
195a107427SMatthew G. Knepley 
205a107427SMatthew G. Knepley   PetscFunctionBegin;
21*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
22*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size));
23*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(dm, &dim));
24*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepth(dm, &depth));
255a107427SMatthew G. Knepley   if (dim != depth) {
265a107427SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
27*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
285a107427SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
29*5f80ce2aSJacob Faibussowitsch     if (globalNumbering) CHKERRQ(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
305a107427SMatthew G. Knepley     /* Different behavior for empty graphs */
315a107427SMatthew G. Knepley     if (!*numVertices) {
32*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(1, offsets));
335a107427SMatthew G. Knepley       (*offsets)[0] = 0;
345a107427SMatthew G. Knepley     }
355a107427SMatthew G. Knepley     /* Broken in parallel */
36*5f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices,PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
375a107427SMatthew G. Knepley     PetscFunctionReturn(0);
385a107427SMatthew G. Knepley   }
395a107427SMatthew G. Knepley   /* Always use FVM adjacency to create partitioner graph */
40*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetBasicAdjacency(dm, &useCone, &useClosure));
41*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
425a107427SMatthew G. Knepley   /* Need overlap >= 1 */
43*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetOverlap(dm, &overlap));
445a107427SMatthew G. Knepley   if (size && overlap < 1) {
45*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexDistributeOverlap(dm, 1, NULL, &ovdm));
465a107427SMatthew G. Knepley   } else {
47*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject) dm));
485a107427SMatthew G. Knepley     ovdm = dm;
495a107427SMatthew G. Knepley   }
50*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetPointSF(ovdm, &sfPoint));
51*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetHeightStratum(ovdm, height, &cStart, &cEnd));
52*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateNumbering_Plex(ovdm, cStart, cEnd, 0, NULL, sfPoint, &cellNumbering));
535a107427SMatthew G. Knepley   if (globalNumbering) {
54*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject) cellNumbering));
555a107427SMatthew G. Knepley     *globalNumbering = cellNumbering;
565a107427SMatthew G. Knepley   }
57*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(cellNumbering, &cellNum));
585a107427SMatthew G. Knepley   /* Determine sizes */
595a107427SMatthew G. Knepley   for (*numVertices = 0, c = cStart; c < cEnd; ++c) {
605a107427SMatthew G. Knepley     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
615a107427SMatthew G. Knepley     if (cellNum[c] < 0) continue;
625a107427SMatthew G. Knepley     (*numVertices)++;
635a107427SMatthew G. Knepley   }
64*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc1(*numVertices+1, &vOffsets));
655a107427SMatthew G. Knepley   for (c = cStart, v = 0; c < cEnd; ++c) {
665a107427SMatthew G. Knepley     PetscInt adjSize = PETSC_DETERMINE, a, vsize = 0;
675a107427SMatthew G. Knepley 
685a107427SMatthew G. Knepley     if (cellNum[c] < 0) continue;
69*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetAdjacency(ovdm, c, &adjSize, &adj));
705a107427SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
715a107427SMatthew G. Knepley       const PetscInt point = adj[a];
725a107427SMatthew G. Knepley       if (point != c && cStart <= point && point < cEnd) ++vsize;
735a107427SMatthew G. Knepley     }
745a107427SMatthew G. Knepley     vOffsets[v+1] = vOffsets[v] + vsize;
755a107427SMatthew G. Knepley     ++v;
765a107427SMatthew G. Knepley   }
775a107427SMatthew G. Knepley   /* Determine adjacency */
78*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(vOffsets[*numVertices], &vAdj));
795a107427SMatthew G. Knepley   for (c = cStart, v = 0; c < cEnd; ++c) {
805a107427SMatthew G. Knepley     PetscInt adjSize = PETSC_DETERMINE, a, off = vOffsets[v];
815a107427SMatthew G. Knepley 
825a107427SMatthew G. Knepley     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
835a107427SMatthew G. Knepley     if (cellNum[c] < 0) continue;
84*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetAdjacency(ovdm, c, &adjSize, &adj));
855a107427SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
865a107427SMatthew G. Knepley       const PetscInt point = adj[a];
875a107427SMatthew G. Knepley       if (point != c && cStart <= point && point < cEnd) {
885a107427SMatthew G. Knepley         vAdj[off++] = DMPlex_GlobalID(cellNum[point]);
895a107427SMatthew G. Knepley       }
905a107427SMatthew G. Knepley     }
91*5f80ce2aSJacob Faibussowitsch     PetscCheck(off == vOffsets[v+1],PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Offsets %D should be %D", off, vOffsets[v+1]);
925a107427SMatthew G. Knepley     /* Sort adjacencies (not strictly necessary) */
93*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSortInt(off-vOffsets[v], &vAdj[vOffsets[v]]));
945a107427SMatthew G. Knepley     ++v;
955a107427SMatthew G. Knepley   }
96*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(adj));
97*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(cellNumbering, &cellNum));
98*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&cellNumbering));
99*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetBasicAdjacency(dm, useCone, useClosure));
100*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&ovdm));
1015a107427SMatthew G. Knepley   if (offsets)   {*offsets = vOffsets;}
102*5f80ce2aSJacob Faibussowitsch   else           CHKERRQ(PetscFree(vOffsets));
1035a107427SMatthew G. Knepley   if (adjacency) {*adjacency = vAdj;}
104*5f80ce2aSJacob Faibussowitsch   else           CHKERRQ(PetscFree(vAdj));
1055a107427SMatthew G. Knepley   PetscFunctionReturn(0);
1065a107427SMatthew G. Knepley }
1075a107427SMatthew G. Knepley 
108bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
109532c4e7dSMichael Lange {
110ffbd6163SMatthew G. Knepley   PetscInt       dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
111389e55d8SMichael Lange   PetscInt      *adj = NULL, *vOffsets = NULL, *graph = NULL;
1128cfe4c1fSMichael Lange   IS             cellNumbering;
1138cfe4c1fSMichael Lange   const PetscInt *cellNum;
114532c4e7dSMichael Lange   PetscBool      useCone, useClosure;
115532c4e7dSMichael Lange   PetscSection   section;
116532c4e7dSMichael Lange   PetscSegBuffer adjBuffer;
1178cfe4c1fSMichael Lange   PetscSF        sfPoint;
1188f4e72b9SMatthew G. Knepley   PetscInt       *adjCells = NULL, *remoteCells = NULL;
1198f4e72b9SMatthew G. Knepley   const PetscInt *local;
1208f4e72b9SMatthew G. Knepley   PetscInt       nroots, nleaves, l;
121532c4e7dSMichael Lange   PetscMPIInt    rank;
122532c4e7dSMichael Lange 
123532c4e7dSMichael Lange   PetscFunctionBegin;
124*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
125*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(dm, &dim));
126*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepth(dm, &depth));
127ffbd6163SMatthew G. Knepley   if (dim != depth) {
128ffbd6163SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
129*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
130ffbd6163SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
131*5f80ce2aSJacob Faibussowitsch     if (globalNumbering) CHKERRQ(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
132ffbd6163SMatthew G. Knepley     /* Different behavior for empty graphs */
133ffbd6163SMatthew G. Knepley     if (!*numVertices) {
134*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(1, offsets));
135ffbd6163SMatthew G. Knepley       (*offsets)[0] = 0;
136ffbd6163SMatthew G. Knepley     }
137ffbd6163SMatthew G. Knepley     /* Broken in parallel */
138*5f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices,PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
139ffbd6163SMatthew G. Knepley     PetscFunctionReturn(0);
140ffbd6163SMatthew G. Knepley   }
141*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetPointSF(dm, &sfPoint));
142*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetHeightStratum(dm, height, &pStart, &pEnd));
143532c4e7dSMichael Lange   /* Build adjacency graph via a section/segbuffer */
144*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &section));
145*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(section, pStart, pEnd));
146*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSegBufferCreate(sizeof(PetscInt),1000,&adjBuffer));
147532c4e7dSMichael Lange   /* Always use FVM adjacency to create partitioner graph */
148*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetBasicAdjacency(dm, &useCone, &useClosure));
149*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
150*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, sfPoint, &cellNumbering));
1513fa7752dSToby Isaac   if (globalNumbering) {
152*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)cellNumbering));
1533fa7752dSToby Isaac     *globalNumbering = cellNumbering;
1543fa7752dSToby Isaac   }
155*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(cellNumbering, &cellNum));
1568f4e72b9SMatthew G. Knepley   /* For all boundary faces (including faces adjacent to a ghost cell), record the local cell in adjCells
1578f4e72b9SMatthew G. Knepley      Broadcast adjCells to remoteCells (to get cells from roots) and Reduce adjCells to remoteCells (to get cells from leaves)
1588f4e72b9SMatthew G. Knepley    */
159*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGetGraph(sfPoint, &nroots, &nleaves, &local, NULL));
1608f4e72b9SMatthew G. Knepley   if (nroots >= 0) {
1618f4e72b9SMatthew G. Knepley     PetscInt fStart, fEnd, f;
1628f4e72b9SMatthew G. Knepley 
163*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc2(nroots, &adjCells, nroots, &remoteCells));
164*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd));
1658f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) adjCells[l] = -3;
1668f4e72b9SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
1678f4e72b9SMatthew G. Knepley       const PetscInt *support;
1688f4e72b9SMatthew G. Knepley       PetscInt        supportSize;
1698f4e72b9SMatthew G. Knepley 
170*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetSupport(dm, f, &support));
171*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetSupportSize(dm, f, &supportSize));
1720134a67bSLisandro Dalcin       if (supportSize == 1) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
1738f4e72b9SMatthew G. Knepley       else if (supportSize == 2) {
174*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscFindInt(support[0], nleaves, local, &p));
1750134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1]]);
176*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscFindInt(support[1], nleaves, local, &p));
1770134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
1780134a67bSLisandro Dalcin       }
1790134a67bSLisandro Dalcin       /* Handle non-conforming meshes */
1800134a67bSLisandro Dalcin       if (supportSize > 2) {
1810134a67bSLisandro Dalcin         PetscInt        numChildren, i;
1820134a67bSLisandro Dalcin         const PetscInt *children;
1830134a67bSLisandro Dalcin 
184*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeChildren(dm, f, &numChildren, &children));
1850134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1860134a67bSLisandro Dalcin           const PetscInt child = children[i];
1870134a67bSLisandro Dalcin           if (fStart <= child && child < fEnd) {
188*5f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexGetSupport(dm, child, &support));
189*5f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexGetSupportSize(dm, child, &supportSize));
1900134a67bSLisandro Dalcin             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
1910134a67bSLisandro Dalcin             else if (supportSize == 2) {
192*5f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscFindInt(support[0], nleaves, local, &p));
1930134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1]]);
194*5f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscFindInt(support[1], nleaves, local, &p));
1950134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
1960134a67bSLisandro Dalcin             }
1970134a67bSLisandro Dalcin           }
1980134a67bSLisandro Dalcin         }
1998f4e72b9SMatthew G. Knepley       }
2008f4e72b9SMatthew G. Knepley     }
2018f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) remoteCells[l] = -1;
202*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastBegin(dm->sf, MPIU_INT, adjCells, remoteCells,MPI_REPLACE));
203*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastEnd(dm->sf, MPIU_INT, adjCells, remoteCells,MPI_REPLACE));
204*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFReduceBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX));
205*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFReduceEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX));
2068f4e72b9SMatthew G. Knepley   }
2078f4e72b9SMatthew G. Knepley   /* Combine local and global adjacencies */
2088cfe4c1fSMichael Lange   for (*numVertices = 0, p = pStart; p < pEnd; p++) {
2098cfe4c1fSMichael Lange     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
2108cfe4c1fSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
2118f4e72b9SMatthew G. Knepley     /* Add remote cells */
2128f4e72b9SMatthew G. Knepley     if (remoteCells) {
2130134a67bSLisandro Dalcin       const PetscInt gp = DMPlex_GlobalID(cellNum[p]);
2140134a67bSLisandro Dalcin       PetscInt       coneSize, numChildren, c, i;
2150134a67bSLisandro Dalcin       const PetscInt *cone, *children;
2160134a67bSLisandro Dalcin 
217*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetCone(dm, p, &cone));
218*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetConeSize(dm, p, &coneSize));
2198f4e72b9SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
2200134a67bSLisandro Dalcin         const PetscInt point = cone[c];
2210134a67bSLisandro Dalcin         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
2228f4e72b9SMatthew G. Knepley           PetscInt *PETSC_RESTRICT pBuf;
223*5f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionAddDof(section, p, 1));
224*5f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2250134a67bSLisandro Dalcin           *pBuf = remoteCells[point];
2260134a67bSLisandro Dalcin         }
2270134a67bSLisandro Dalcin         /* Handle non-conforming meshes */
228*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
2290134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
2300134a67bSLisandro Dalcin           const PetscInt child = children[i];
2310134a67bSLisandro Dalcin           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
2320134a67bSLisandro Dalcin             PetscInt *PETSC_RESTRICT pBuf;
233*5f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionAddDof(section, p, 1));
234*5f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2350134a67bSLisandro Dalcin             *pBuf = remoteCells[child];
2360134a67bSLisandro Dalcin           }
2378f4e72b9SMatthew G. Knepley         }
2388f4e72b9SMatthew G. Knepley       }
2398f4e72b9SMatthew G. Knepley     }
2408f4e72b9SMatthew G. Knepley     /* Add local cells */
241532c4e7dSMichael Lange     adjSize = PETSC_DETERMINE;
242*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
243532c4e7dSMichael Lange     for (a = 0; a < adjSize; ++a) {
244532c4e7dSMichael Lange       const PetscInt point = adj[a];
245532c4e7dSMichael Lange       if (point != p && pStart <= point && point < pEnd) {
246532c4e7dSMichael Lange         PetscInt *PETSC_RESTRICT pBuf;
247*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionAddDof(section, p, 1));
248*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2490134a67bSLisandro Dalcin         *pBuf = DMPlex_GlobalID(cellNum[point]);
250532c4e7dSMichael Lange       }
251532c4e7dSMichael Lange     }
2528cfe4c1fSMichael Lange     (*numVertices)++;
253532c4e7dSMichael Lange   }
254*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(adj));
255*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(adjCells, remoteCells));
256*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetBasicAdjacency(dm, useCone, useClosure));
2574e468a93SLisandro Dalcin 
258532c4e7dSMichael Lange   /* Derive CSR graph from section/segbuffer */
259*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(section));
260*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(section, &size));
261*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(*numVertices+1, &vOffsets));
26243f7d02bSMichael Lange   for (idx = 0, p = pStart; p < pEnd; p++) {
26343f7d02bSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
264*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(section, p, &(vOffsets[idx++])));
26543f7d02bSMichael Lange   }
266532c4e7dSMichael Lange   vOffsets[*numVertices] = size;
267*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSegBufferExtractAlloc(adjBuffer, &graph));
2684e468a93SLisandro Dalcin 
2694e468a93SLisandro Dalcin   if (nroots >= 0) {
2704e468a93SLisandro Dalcin     /* Filter out duplicate edges using section/segbuffer */
271*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionReset(section));
272*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetChart(section, 0, *numVertices));
2734e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2744e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
2754e468a93SLisandro Dalcin       PetscInt numEdges = end-start, *PETSC_RESTRICT edges;
276*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSortRemoveDupsInt(&numEdges, &graph[start]));
277*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(section, p, numEdges));
278*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSegBufferGetInts(adjBuffer, numEdges, &edges));
279*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscArraycpy(edges, &graph[start], numEdges));
2804e468a93SLisandro Dalcin     }
281*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(vOffsets));
282*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(graph));
2834e468a93SLisandro Dalcin     /* Derive CSR graph from section/segbuffer */
284*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(section));
285*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(section, &size));
286*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(*numVertices+1, &vOffsets));
2874e468a93SLisandro Dalcin     for (idx = 0, p = 0; p < *numVertices; p++) {
288*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(section, p, &(vOffsets[idx++])));
2894e468a93SLisandro Dalcin     }
2904e468a93SLisandro Dalcin     vOffsets[*numVertices] = size;
291*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSegBufferExtractAlloc(adjBuffer, &graph));
2924e468a93SLisandro Dalcin   } else {
2934e468a93SLisandro Dalcin     /* Sort adjacencies (not strictly necessary) */
2944e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2954e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
296*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSortInt(end-start, &graph[start]));
2974e468a93SLisandro Dalcin     }
2984e468a93SLisandro Dalcin   }
2994e468a93SLisandro Dalcin 
3004e468a93SLisandro Dalcin   if (offsets) *offsets = vOffsets;
301389e55d8SMichael Lange   if (adjacency) *adjacency = graph;
3024e468a93SLisandro Dalcin 
303532c4e7dSMichael Lange   /* Cleanup */
304*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSegBufferDestroy(&adjBuffer));
305*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&section));
306*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(cellNumbering, &cellNum));
307*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&cellNumbering));
308532c4e7dSMichael Lange   PetscFunctionReturn(0);
309532c4e7dSMichael Lange }
310532c4e7dSMichael Lange 
311bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
312bbbc8e51SStefano Zampini {
313bbbc8e51SStefano Zampini   Mat            conn, CSR;
314bbbc8e51SStefano Zampini   IS             fis, cis, cis_own;
315bbbc8e51SStefano Zampini   PetscSF        sfPoint;
316bbbc8e51SStefano Zampini   const PetscInt *rows, *cols, *ii, *jj;
317bbbc8e51SStefano Zampini   PetscInt       *idxs,*idxs2;
31883c5d788SMatthew G. Knepley   PetscInt       dim, depth, floc, cloc, i, M, N, c, lm, m, cStart, cEnd, fStart, fEnd;
319bbbc8e51SStefano Zampini   PetscMPIInt    rank;
320bbbc8e51SStefano Zampini   PetscBool      flg;
321bbbc8e51SStefano Zampini 
322bbbc8e51SStefano Zampini   PetscFunctionBegin;
323*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
324*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(dm, &dim));
325*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepth(dm, &depth));
326bbbc8e51SStefano Zampini   if (dim != depth) {
327bbbc8e51SStefano Zampini     /* We do not handle the uninterpolated case here */
328*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
329bbbc8e51SStefano Zampini     /* DMPlexCreateNeighborCSR does not make a numbering */
330*5f80ce2aSJacob Faibussowitsch     if (globalNumbering) CHKERRQ(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
331bbbc8e51SStefano Zampini     /* Different behavior for empty graphs */
332bbbc8e51SStefano Zampini     if (!*numVertices) {
333*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(1, offsets));
334bbbc8e51SStefano Zampini       (*offsets)[0] = 0;
335bbbc8e51SStefano Zampini     }
336bbbc8e51SStefano Zampini     /* Broken in parallel */
337*5f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices,PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
338bbbc8e51SStefano Zampini     PetscFunctionReturn(0);
339bbbc8e51SStefano Zampini   }
340bbbc8e51SStefano Zampini   /* Interpolated and parallel case */
341bbbc8e51SStefano Zampini 
342bbbc8e51SStefano Zampini   /* numbering */
343*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetPointSF(dm, &sfPoint));
344*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd));
345*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd));
346*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, &N, sfPoint, &cis));
347*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateNumbering_Plex(dm, fStart, fEnd, 0, &M, sfPoint, &fis));
348bbbc8e51SStefano Zampini   if (globalNumbering) {
349*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDuplicate(cis, globalNumbering));
350bbbc8e51SStefano Zampini   }
351bbbc8e51SStefano Zampini 
352bbbc8e51SStefano Zampini   /* get positive global ids and local sizes for facets and cells */
353*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetLocalSize(fis, &m));
354*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(fis, &rows));
355*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(m, &idxs));
356bbbc8e51SStefano Zampini   for (i = 0, floc = 0; i < m; i++) {
357bbbc8e51SStefano Zampini     const PetscInt p = rows[i];
358bbbc8e51SStefano Zampini 
359bbbc8e51SStefano Zampini     if (p < 0) {
360bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
361bbbc8e51SStefano Zampini     } else {
362bbbc8e51SStefano Zampini       idxs[i] = p;
363bbbc8e51SStefano Zampini       floc   += 1;
364bbbc8e51SStefano Zampini     }
365bbbc8e51SStefano Zampini   }
366*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(fis, &rows));
367*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&fis));
368*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis));
369bbbc8e51SStefano Zampini 
370*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetLocalSize(cis, &m));
371*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(cis, &cols));
372*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(m, &idxs));
373*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(m, &idxs2));
374bbbc8e51SStefano Zampini   for (i = 0, cloc = 0; i < m; i++) {
375bbbc8e51SStefano Zampini     const PetscInt p = cols[i];
376bbbc8e51SStefano Zampini 
377bbbc8e51SStefano Zampini     if (p < 0) {
378bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
379bbbc8e51SStefano Zampini     } else {
380bbbc8e51SStefano Zampini       idxs[i]       = p;
381bbbc8e51SStefano Zampini       idxs2[cloc++] = p;
382bbbc8e51SStefano Zampini     }
383bbbc8e51SStefano Zampini   }
384*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(cis, &cols));
385*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&cis));
386*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis));
387*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own));
388bbbc8e51SStefano Zampini 
389bbbc8e51SStefano Zampini   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
390*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreate(PetscObjectComm((PetscObject)dm), &conn));
391*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetSizes(conn, floc, cloc, M, N));
392*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetType(conn, MATMPIAIJ));
393*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetMaxSizes(dm, NULL, &lm));
394*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Allreduce(&lm, &m, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm)));
395*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL));
396bbbc8e51SStefano Zampini 
397bbbc8e51SStefano Zampini   /* Assemble matrix */
398*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(fis, &rows));
399*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(cis, &cols));
400bbbc8e51SStefano Zampini   for (c = cStart; c < cEnd; c++) {
401bbbc8e51SStefano Zampini     const PetscInt *cone;
402bbbc8e51SStefano Zampini     PetscInt        coneSize, row, col, f;
403bbbc8e51SStefano Zampini 
404bbbc8e51SStefano Zampini     col  = cols[c-cStart];
405*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCone(dm, c, &cone));
406*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeSize(dm, c, &coneSize));
407bbbc8e51SStefano Zampini     for (f = 0; f < coneSize; f++) {
408bbbc8e51SStefano Zampini       const PetscScalar v = 1.0;
409bbbc8e51SStefano Zampini       const PetscInt *children;
410bbbc8e51SStefano Zampini       PetscInt        numChildren, ch;
411bbbc8e51SStefano Zampini 
412bbbc8e51SStefano Zampini       row  = rows[cone[f]-fStart];
413*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES));
414bbbc8e51SStefano Zampini 
415bbbc8e51SStefano Zampini       /* non-conforming meshes */
416*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children));
417bbbc8e51SStefano Zampini       for (ch = 0; ch < numChildren; ch++) {
418bbbc8e51SStefano Zampini         const PetscInt child = children[ch];
419bbbc8e51SStefano Zampini 
420bbbc8e51SStefano Zampini         if (child < fStart || child >= fEnd) continue;
421bbbc8e51SStefano Zampini         row  = rows[child-fStart];
422*5f80ce2aSJacob Faibussowitsch         CHKERRQ(MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES));
423bbbc8e51SStefano Zampini       }
424bbbc8e51SStefano Zampini     }
425bbbc8e51SStefano Zampini   }
426*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(fis, &rows));
427*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(cis, &cols));
428*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&fis));
429*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&cis));
430*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY));
431*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY));
432bbbc8e51SStefano Zampini 
433bbbc8e51SStefano Zampini   /* Get parallel CSR by doing conn^T * conn */
434*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR));
435*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&conn));
436bbbc8e51SStefano Zampini 
437bbbc8e51SStefano Zampini   /* extract local part of the CSR */
438*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn));
439*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&CSR));
440*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
441*5f80ce2aSJacob Faibussowitsch   PetscCheck(flg,PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
442bbbc8e51SStefano Zampini 
443bbbc8e51SStefano Zampini   /* get back requested output */
444bbbc8e51SStefano Zampini   if (numVertices) *numVertices = m;
445bbbc8e51SStefano Zampini   if (offsets) {
446*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc1(m+1, &idxs));
447bbbc8e51SStefano Zampini     for (i = 1; i < m+1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
448bbbc8e51SStefano Zampini     *offsets = idxs;
449bbbc8e51SStefano Zampini   }
450bbbc8e51SStefano Zampini   if (adjacency) {
451*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(ii[m] - m, &idxs));
452*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetIndices(cis_own, &rows));
453bbbc8e51SStefano Zampini     for (i = 0, c = 0; i < m; i++) {
454bbbc8e51SStefano Zampini       PetscInt j, g = rows[i];
455bbbc8e51SStefano Zampini 
456bbbc8e51SStefano Zampini       for (j = ii[i]; j < ii[i+1]; j++) {
457bbbc8e51SStefano Zampini         if (jj[j] == g) continue; /* again, self-connectivity */
458bbbc8e51SStefano Zampini         idxs[c++] = jj[j];
459bbbc8e51SStefano Zampini       }
460bbbc8e51SStefano Zampini     }
461*5f80ce2aSJacob Faibussowitsch     PetscCheck(c == ii[m] - m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %D != %D",c,ii[m]-m);
462*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISRestoreIndices(cis_own, &rows));
463bbbc8e51SStefano Zampini     *adjacency = idxs;
464bbbc8e51SStefano Zampini   }
465bbbc8e51SStefano Zampini 
466bbbc8e51SStefano Zampini   /* cleanup */
467*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&cis_own));
468*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
469*5f80ce2aSJacob Faibussowitsch   PetscCheck(flg,PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
470*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&conn));
471bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
472bbbc8e51SStefano Zampini }
473bbbc8e51SStefano Zampini 
474bbbc8e51SStefano Zampini /*@C
475bbbc8e51SStefano Zampini   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
476bbbc8e51SStefano Zampini 
477bbbc8e51SStefano Zampini   Input Parameters:
478bbbc8e51SStefano Zampini + dm      - The mesh DM dm
479bbbc8e51SStefano Zampini - height  - Height of the strata from which to construct the graph
480bbbc8e51SStefano Zampini 
481d8d19677SJose E. Roman   Output Parameters:
482bbbc8e51SStefano Zampini + numVertices     - Number of vertices in the graph
483bbbc8e51SStefano Zampini . offsets         - Point offsets in the graph
484bbbc8e51SStefano Zampini . adjacency       - Point connectivity in the graph
485bbbc8e51SStefano Zampini - globalNumbering - A map from the local cell numbering to the global numbering used in "adjacency".  Negative indicates that the cell is a duplicate from another process.
486bbbc8e51SStefano Zampini 
487bbbc8e51SStefano Zampini   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
488bbbc8e51SStefano Zampini   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
489bbbc8e51SStefano Zampini 
4905a107427SMatthew G. Knepley   Options Database Keys:
4915a107427SMatthew G. Knepley . -dm_plex_csr_alg <mat,graph,overlap> - Choose the algorithm for computing the CSR graph
4925a107427SMatthew G. Knepley 
493bbbc8e51SStefano Zampini   Level: developer
494bbbc8e51SStefano Zampini 
495bbbc8e51SStefano Zampini .seealso: PetscPartitionerGetType(), PetscPartitionerCreate(), DMSetAdjacency()
496bbbc8e51SStefano Zampini @*/
497bbbc8e51SStefano Zampini PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
498bbbc8e51SStefano Zampini {
4995a107427SMatthew G. Knepley   DMPlexCSRAlgorithm alg = DM_PLEX_CSR_GRAPH;
500bbbc8e51SStefano Zampini 
501bbbc8e51SStefano Zampini   PetscFunctionBegin;
502*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsGetEnum(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_csr_alg", DMPlexCSRAlgorithms, (PetscEnum *) &alg, NULL));
5035a107427SMatthew G. Knepley   switch (alg) {
5045a107427SMatthew G. Knepley     case DM_PLEX_CSR_MAT:
505*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering));break;
5065a107427SMatthew G. Knepley     case DM_PLEX_CSR_GRAPH:
507*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering));break;
5085a107427SMatthew G. Knepley     case DM_PLEX_CSR_OVERLAP:
509*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexCreatePartitionerGraph_Overlap(dm, height, numVertices, offsets, adjacency, globalNumbering));break;
510bbbc8e51SStefano Zampini   }
511bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
512bbbc8e51SStefano Zampini }
513bbbc8e51SStefano Zampini 
514d5577e40SMatthew G. Knepley /*@C
515d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
516d5577e40SMatthew G. Knepley 
517fe2efc57SMark   Collective on DM
518d5577e40SMatthew G. Knepley 
5194165533cSJose E. Roman   Input Parameters:
520d5577e40SMatthew G. Knepley + dm - The DMPlex
521d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
522d5577e40SMatthew G. Knepley 
5234165533cSJose E. Roman   Output Parameters:
524d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
525d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
526d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
527d5577e40SMatthew G. Knepley 
528d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
529d5577e40SMatthew G. Knepley 
530d5577e40SMatthew G. Knepley   Level: advanced
531d5577e40SMatthew G. Knepley 
532d5577e40SMatthew G. Knepley .seealso: DMPlexCreate()
533d5577e40SMatthew G. Knepley @*/
53470034214SMatthew G. Knepley PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
53570034214SMatthew G. Knepley {
53670034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
53770034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
53870034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
53970034214SMatthew G. Knepley   PetscInt      *off, *adj;
54070034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
54170034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
54270034214SMatthew G. Knepley 
54370034214SMatthew G. Knepley   PetscFunctionBegin;
54470034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
545*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(dm, &dim));
54670034214SMatthew G. Knepley   cellDim = dim - cellHeight;
547*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepth(dm, &depth));
548*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
54970034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
55070034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
55170034214SMatthew G. Knepley     if (offsets)   *offsets   = NULL;
55270034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
55370034214SMatthew G. Knepley     PetscFunctionReturn(0);
55470034214SMatthew G. Knepley   }
55570034214SMatthew G. Knepley   numCells  = cEnd - cStart;
55670034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
55770034214SMatthew G. Knepley   if (dim == depth) {
55870034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
55970034214SMatthew G. Knepley 
560*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc1(numCells+1, &off));
56170034214SMatthew G. Knepley     /* Count neighboring cells */
562*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd));
56370034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
56470034214SMatthew G. Knepley       const PetscInt *support;
56570034214SMatthew G. Knepley       PetscInt        supportSize;
566*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetSupportSize(dm, f, &supportSize));
567*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetSupport(dm, f, &support));
56870034214SMatthew G. Knepley       if (supportSize == 2) {
5699ffc88e4SToby Isaac         PetscInt numChildren;
5709ffc88e4SToby Isaac 
571*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeChildren(dm,f,&numChildren,NULL));
5729ffc88e4SToby Isaac         if (!numChildren) {
57370034214SMatthew G. Knepley           ++off[support[0]-cStart+1];
57470034214SMatthew G. Knepley           ++off[support[1]-cStart+1];
57570034214SMatthew G. Knepley         }
57670034214SMatthew G. Knepley       }
5779ffc88e4SToby Isaac     }
57870034214SMatthew G. Knepley     /* Prefix sum */
57970034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
58070034214SMatthew G. Knepley     if (adjacency) {
58170034214SMatthew G. Knepley       PetscInt *tmp;
58270034214SMatthew G. Knepley 
583*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(off[numCells], &adj));
584*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(numCells+1, &tmp));
585*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscArraycpy(tmp, off, numCells+1));
58670034214SMatthew G. Knepley       /* Get neighboring cells */
58770034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
58870034214SMatthew G. Knepley         const PetscInt *support;
58970034214SMatthew G. Knepley         PetscInt        supportSize;
590*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetSupportSize(dm, f, &supportSize));
591*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetSupport(dm, f, &support));
59270034214SMatthew G. Knepley         if (supportSize == 2) {
5939ffc88e4SToby Isaac           PetscInt numChildren;
5949ffc88e4SToby Isaac 
595*5f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetTreeChildren(dm,f,&numChildren,NULL));
5969ffc88e4SToby Isaac           if (!numChildren) {
59770034214SMatthew G. Knepley             adj[tmp[support[0]-cStart]++] = support[1];
59870034214SMatthew G. Knepley             adj[tmp[support[1]-cStart]++] = support[0];
59970034214SMatthew G. Knepley           }
60070034214SMatthew G. Knepley         }
6019ffc88e4SToby Isaac       }
602*5f80ce2aSJacob Faibussowitsch       for (c = 0; c < cEnd-cStart; ++c) PetscAssert(tmp[c] == off[c+1],PETSC_COMM_SELF, PETSC_ERR_PLIB, "Offset %d != %d for cell %d", tmp[c], off[c], c+cStart);
603*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(tmp));
60470034214SMatthew G. Knepley     }
60570034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
60670034214SMatthew G. Knepley     if (offsets)   *offsets   = off;
60770034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
60870034214SMatthew G. Knepley     PetscFunctionReturn(0);
60970034214SMatthew G. Knepley   }
61070034214SMatthew G. Knepley   /* Setup face recognition */
61170034214SMatthew G. Knepley   if (faceDepth == 1) {
61270034214SMatthew G. Knepley     PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */
61370034214SMatthew G. Knepley 
61470034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
61570034214SMatthew G. Knepley       PetscInt corners;
61670034214SMatthew G. Knepley 
617*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetConeSize(dm, c, &corners));
61870034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
61970034214SMatthew G. Knepley         PetscInt nFV;
62070034214SMatthew G. Knepley 
621*5f80ce2aSJacob Faibussowitsch         PetscCheck(numFaceCases < maxFaceCases,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
62270034214SMatthew G. Knepley         cornersSeen[corners] = 1;
62370034214SMatthew G. Knepley 
624*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV));
62570034214SMatthew G. Knepley 
62670034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
62770034214SMatthew G. Knepley       }
62870034214SMatthew G. Knepley     }
62970034214SMatthew G. Knepley   }
630*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc1(numCells+1, &off));
63170034214SMatthew G. Knepley   /* Count neighboring cells */
63270034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
63370034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
63470034214SMatthew G. Knepley 
635*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
63670034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
63770034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
63870034214SMatthew G. Knepley       PetscInt        cellPair[2];
63970034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
64070034214SMatthew G. Knepley       PetscInt        meetSize = 0;
64170034214SMatthew G. Knepley       const PetscInt *meet    = NULL;
64270034214SMatthew G. Knepley 
64370034214SMatthew G. Knepley       cellPair[0] = cell; cellPair[1] = neighborCells[n];
64470034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
64570034214SMatthew G. Knepley       if (!found) {
646*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
64770034214SMatthew G. Knepley         if (meetSize) {
64870034214SMatthew G. Knepley           PetscInt f;
64970034214SMatthew G. Knepley 
65070034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
65170034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
65270034214SMatthew G. Knepley               found = PETSC_TRUE;
65370034214SMatthew G. Knepley               break;
65470034214SMatthew G. Knepley             }
65570034214SMatthew G. Knepley           }
65670034214SMatthew G. Knepley         }
657*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
65870034214SMatthew G. Knepley       }
65970034214SMatthew G. Knepley       if (found) ++off[cell-cStart+1];
66070034214SMatthew G. Knepley     }
66170034214SMatthew G. Knepley   }
66270034214SMatthew G. Knepley   /* Prefix sum */
66370034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
66470034214SMatthew G. Knepley 
66570034214SMatthew G. Knepley   if (adjacency) {
666*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(off[numCells], &adj));
66770034214SMatthew G. Knepley     /* Get neighboring cells */
66870034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
66970034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
67070034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
67170034214SMatthew G. Knepley 
672*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
67370034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
67470034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
67570034214SMatthew G. Knepley         PetscInt        cellPair[2];
67670034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
67770034214SMatthew G. Knepley         PetscInt        meetSize = 0;
67870034214SMatthew G. Knepley         const PetscInt *meet    = NULL;
67970034214SMatthew G. Knepley 
68070034214SMatthew G. Knepley         cellPair[0] = cell; cellPair[1] = neighborCells[n];
68170034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
68270034214SMatthew G. Knepley         if (!found) {
683*5f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
68470034214SMatthew G. Knepley           if (meetSize) {
68570034214SMatthew G. Knepley             PetscInt f;
68670034214SMatthew G. Knepley 
68770034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
68870034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
68970034214SMatthew G. Knepley                 found = PETSC_TRUE;
69070034214SMatthew G. Knepley                 break;
69170034214SMatthew G. Knepley               }
69270034214SMatthew G. Knepley             }
69370034214SMatthew G. Knepley           }
694*5f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
69570034214SMatthew G. Knepley         }
69670034214SMatthew G. Knepley         if (found) {
69770034214SMatthew G. Knepley           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
69870034214SMatthew G. Knepley           ++cellOffset;
69970034214SMatthew G. Knepley         }
70070034214SMatthew G. Knepley       }
70170034214SMatthew G. Knepley     }
70270034214SMatthew G. Knepley   }
703*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(neighborCells));
70470034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
70570034214SMatthew G. Knepley   if (offsets)   *offsets   = off;
70670034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
70770034214SMatthew G. Knepley   PetscFunctionReturn(0);
70870034214SMatthew G. Knepley }
70970034214SMatthew G. Knepley 
71077623264SMatthew G. Knepley /*@
7113c41b853SStefano Zampini   PetscPartitionerDMPlexPartition - Create a non-overlapping partition of the cells in the mesh
71277623264SMatthew G. Knepley 
713fe2efc57SMark   Collective on PetscPartitioner
71477623264SMatthew G. Knepley 
71577623264SMatthew G. Knepley   Input Parameters:
71677623264SMatthew G. Knepley + part    - The PetscPartitioner
7173c41b853SStefano Zampini . targetSection - The PetscSection describing the absolute weight of each partition (can be NULL)
718f8987ae8SMichael Lange - dm      - The mesh DM
71977623264SMatthew G. Knepley 
72077623264SMatthew G. Knepley   Output Parameters:
72177623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
722f8987ae8SMichael Lange - partition       - The list of points by partition
72377623264SMatthew G. Knepley 
7243c41b853SStefano Zampini   Notes:
7253c41b853SStefano Zampini     If the DM has a local section associated, each point to be partitioned will be weighted by the total number of dofs identified
7263c41b853SStefano Zampini     by the section in the transitive closure of the point.
72777623264SMatthew G. Knepley 
72877623264SMatthew G. Knepley   Level: developer
72977623264SMatthew G. Knepley 
7303c41b853SStefano Zampini .seealso DMPlexDistribute(), PetscPartitionerCreate(), PetscSectionCreate(), PetscSectionSetChart(), PetscPartitionerPartition()
7314b15ede2SMatthew G. Knepley @*/
7323c41b853SStefano Zampini PetscErrorCode PetscPartitionerDMPlexPartition(PetscPartitioner part, DM dm, PetscSection targetSection, PetscSection partSection, IS *partition)
73377623264SMatthew G. Knepley {
73477623264SMatthew G. Knepley   PetscMPIInt    size;
7353c41b853SStefano Zampini   PetscBool      isplex;
7363c41b853SStefano Zampini   PetscSection   vertSection = NULL;
73777623264SMatthew G. Knepley 
73877623264SMatthew G. Knepley   PetscFunctionBegin;
73977623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
74077623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
7413c41b853SStefano Zampini   if (targetSection) PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 3);
74277623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
74377623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
744*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isplex));
745*5f80ce2aSJacob Faibussowitsch   PetscCheck(isplex,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Not for type %s",((PetscObject)dm)->type_name);
746*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_size(PetscObjectComm((PetscObject) part), &size));
74777623264SMatthew G. Knepley   if (size == 1) {
74877623264SMatthew G. Knepley     PetscInt *points;
74977623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
75077623264SMatthew G. Knepley 
751*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
752*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionReset(partSection));
753*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetChart(partSection, 0, size));
754*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetDof(partSection, 0, cEnd-cStart));
755*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(partSection));
756*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(cEnd-cStart, &points));
75777623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
758*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition));
75977623264SMatthew G. Knepley     PetscFunctionReturn(0);
76077623264SMatthew G. Knepley   }
76177623264SMatthew G. Knepley   if (part->height == 0) {
762074d466cSStefano Zampini     PetscInt numVertices = 0;
76377623264SMatthew G. Knepley     PetscInt *start     = NULL;
76477623264SMatthew G. Knepley     PetscInt *adjacency = NULL;
7653fa7752dSToby Isaac     IS       globalNumbering;
76677623264SMatthew G. Knepley 
767074d466cSStefano Zampini     if (!part->noGraph || part->viewGraph) {
768*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering));
76913911537SStefano Zampini     } else { /* only compute the number of owned local vertices */
770074d466cSStefano Zampini       const PetscInt *idxs;
771074d466cSStefano Zampini       PetscInt       p, pStart, pEnd;
772074d466cSStefano Zampini 
773*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
774*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering));
775*5f80ce2aSJacob Faibussowitsch       CHKERRQ(ISGetIndices(globalNumbering, &idxs));
776074d466cSStefano Zampini       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
777*5f80ce2aSJacob Faibussowitsch       CHKERRQ(ISRestoreIndices(globalNumbering, &idxs));
778074d466cSStefano Zampini     }
7793c41b853SStefano Zampini     if (part->usevwgt) {
7803c41b853SStefano Zampini       PetscSection   section = dm->localSection, clSection = NULL;
7813c41b853SStefano Zampini       IS             clPoints = NULL;
7823c41b853SStefano Zampini       const PetscInt *gid,*clIdx;
7833c41b853SStefano Zampini       PetscInt       v, p, pStart, pEnd;
7840358368aSMatthew G. Knepley 
7853c41b853SStefano Zampini       /* dm->localSection encodes degrees of freedom per point, not per cell. We need to get the closure index to properly specify cell weights (aka dofs) */
7863c41b853SStefano Zampini       /* We do this only if the local section has been set */
7873c41b853SStefano Zampini       if (section) {
788*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, NULL));
7893c41b853SStefano Zampini         if (!clSection) {
790*5f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexCreateClosureIndex(dm,NULL));
7913c41b853SStefano Zampini         }
792*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, &clPoints));
793*5f80ce2aSJacob Faibussowitsch         CHKERRQ(ISGetIndices(clPoints,&clIdx));
7943c41b853SStefano Zampini       }
795*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
796*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionCreate(PETSC_COMM_SELF, &vertSection));
797*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetChart(vertSection, 0, numVertices));
7983c41b853SStefano Zampini       if (globalNumbering) {
799*5f80ce2aSJacob Faibussowitsch         CHKERRQ(ISGetIndices(globalNumbering,&gid));
8003c41b853SStefano Zampini       } else gid = NULL;
8013c41b853SStefano Zampini       for (p = pStart, v = 0; p < pEnd; ++p) {
8023c41b853SStefano Zampini         PetscInt dof = 1;
8030358368aSMatthew G. Knepley 
8043c41b853SStefano Zampini         /* skip cells in the overlap */
8053c41b853SStefano Zampini         if (gid && gid[p-pStart] < 0) continue;
8063c41b853SStefano Zampini 
8073c41b853SStefano Zampini         if (section) {
8083c41b853SStefano Zampini           PetscInt cl, clSize, clOff;
8093c41b853SStefano Zampini 
8103c41b853SStefano Zampini           dof  = 0;
811*5f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetDof(clSection, p, &clSize));
812*5f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetOffset(clSection, p, &clOff));
8133c41b853SStefano Zampini           for (cl = 0; cl < clSize; cl+=2) {
8143c41b853SStefano Zampini             PetscInt clDof, clPoint = clIdx[clOff + cl]; /* odd indices are reserved for orientations */
8153c41b853SStefano Zampini 
816*5f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionGetDof(section, clPoint, &clDof));
8173c41b853SStefano Zampini             dof += clDof;
8180358368aSMatthew G. Knepley           }
8190358368aSMatthew G. Knepley         }
820*5f80ce2aSJacob Faibussowitsch         PetscCheck(dof,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of dofs for point %D in the local section should be positive",p);
821*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionSetDof(vertSection, v, dof));
8223c41b853SStefano Zampini         v++;
8233c41b853SStefano Zampini       }
8243c41b853SStefano Zampini       if (globalNumbering) {
825*5f80ce2aSJacob Faibussowitsch         CHKERRQ(ISRestoreIndices(globalNumbering,&gid));
8263c41b853SStefano Zampini       }
8273c41b853SStefano Zampini       if (clPoints) {
828*5f80ce2aSJacob Faibussowitsch         CHKERRQ(ISRestoreIndices(clPoints,&clIdx));
8293c41b853SStefano Zampini       }
830*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetUp(vertSection));
8313c41b853SStefano Zampini     }
832*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscPartitionerPartition(part, size, numVertices, start, adjacency, vertSection, targetSection, partSection, partition));
833*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(start));
834*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(adjacency));
8353fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
8363fa7752dSToby Isaac       const PetscInt *globalNum;
8373fa7752dSToby Isaac       const PetscInt *partIdx;
8383fa7752dSToby Isaac       PetscInt       *map, cStart, cEnd;
8393fa7752dSToby Isaac       PetscInt       *adjusted, i, localSize, offset;
8403fa7752dSToby Isaac       IS             newPartition;
8413fa7752dSToby Isaac 
842*5f80ce2aSJacob Faibussowitsch       CHKERRQ(ISGetLocalSize(*partition,&localSize));
843*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(localSize,&adjusted));
844*5f80ce2aSJacob Faibussowitsch       CHKERRQ(ISGetIndices(globalNumbering,&globalNum));
845*5f80ce2aSJacob Faibussowitsch       CHKERRQ(ISGetIndices(*partition,&partIdx));
846*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(localSize,&map));
847*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
8483fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
8493fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
8503fa7752dSToby Isaac       }
8513fa7752dSToby Isaac       for (i = 0; i < localSize; i++) {
8523fa7752dSToby Isaac         adjusted[i] = map[partIdx[i]];
8533fa7752dSToby Isaac       }
854*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(map));
855*5f80ce2aSJacob Faibussowitsch       CHKERRQ(ISRestoreIndices(*partition,&partIdx));
856*5f80ce2aSJacob Faibussowitsch       CHKERRQ(ISRestoreIndices(globalNumbering,&globalNum));
857*5f80ce2aSJacob Faibussowitsch       CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition));
858*5f80ce2aSJacob Faibussowitsch       CHKERRQ(ISDestroy(&globalNumbering));
859*5f80ce2aSJacob Faibussowitsch       CHKERRQ(ISDestroy(partition));
8603fa7752dSToby Isaac       *partition = newPartition;
8613fa7752dSToby Isaac     }
86298921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height);
863*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&vertSection));
86477623264SMatthew G. Knepley   PetscFunctionReturn(0);
86577623264SMatthew G. Knepley }
86677623264SMatthew G. Knepley 
8675680f57bSMatthew G. Knepley /*@
8685680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
8695680f57bSMatthew G. Knepley 
8705680f57bSMatthew G. Knepley   Not collective
8715680f57bSMatthew G. Knepley 
8725680f57bSMatthew G. Knepley   Input Parameter:
8735680f57bSMatthew G. Knepley . dm - The DM
8745680f57bSMatthew G. Knepley 
8755680f57bSMatthew G. Knepley   Output Parameter:
8765680f57bSMatthew G. Knepley . part - The PetscPartitioner
8775680f57bSMatthew G. Knepley 
8785680f57bSMatthew G. Knepley   Level: developer
8795680f57bSMatthew G. Knepley 
88098599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
88198599a47SLawrence Mitchell 
8823c41b853SStefano Zampini .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerDMPlexPartition(), PetscPartitionerCreate()
8835680f57bSMatthew G. Knepley @*/
8845680f57bSMatthew G. Knepley PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
8855680f57bSMatthew G. Knepley {
8865680f57bSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex *) dm->data;
8875680f57bSMatthew G. Knepley 
8885680f57bSMatthew G. Knepley   PetscFunctionBegin;
8895680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8905680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
8915680f57bSMatthew G. Knepley   *part = mesh->partitioner;
8925680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
8935680f57bSMatthew G. Knepley }
8945680f57bSMatthew G. Knepley 
89571bb2955SLawrence Mitchell /*@
89671bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
89771bb2955SLawrence Mitchell 
898fe2efc57SMark   logically collective on DM
89971bb2955SLawrence Mitchell 
90071bb2955SLawrence Mitchell   Input Parameters:
90171bb2955SLawrence Mitchell + dm - The DM
90271bb2955SLawrence Mitchell - part - The partitioner
90371bb2955SLawrence Mitchell 
90471bb2955SLawrence Mitchell   Level: developer
90571bb2955SLawrence Mitchell 
90671bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
90771bb2955SLawrence Mitchell 
90871bb2955SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate()
90971bb2955SLawrence Mitchell @*/
91071bb2955SLawrence Mitchell PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
91171bb2955SLawrence Mitchell {
91271bb2955SLawrence Mitchell   DM_Plex       *mesh = (DM_Plex *) dm->data;
91371bb2955SLawrence Mitchell 
91471bb2955SLawrence Mitchell   PetscFunctionBegin;
91571bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
91671bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
917*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectReference((PetscObject)part));
918*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscPartitionerDestroy(&mesh->partitioner));
91971bb2955SLawrence Mitchell   mesh->partitioner = part;
92071bb2955SLawrence Mitchell   PetscFunctionReturn(0);
92171bb2955SLawrence Mitchell }
92271bb2955SLawrence Mitchell 
9238e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point)
9248e330a33SStefano Zampini {
9258e330a33SStefano Zampini   const PetscInt *cone;
9268e330a33SStefano Zampini   PetscInt       coneSize, c;
9278e330a33SStefano Zampini   PetscBool      missing;
9288e330a33SStefano Zampini 
9298e330a33SStefano Zampini   PetscFunctionBeginHot;
930*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscHSetIQueryAdd(ht, point, &missing));
9318e330a33SStefano Zampini   if (missing) {
932*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCone(dm, point, &cone));
933*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeSize(dm, point, &coneSize));
9348e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
935*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexAddClosure_Private(dm, ht, cone[c]));
9368e330a33SStefano Zampini     }
9378e330a33SStefano Zampini   }
9388e330a33SStefano Zampini   PetscFunctionReturn(0);
9398e330a33SStefano Zampini }
9408e330a33SStefano Zampini 
9418e330a33SStefano Zampini PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
942270bba0cSToby Isaac {
943270bba0cSToby Isaac   PetscFunctionBegin;
9446a5a2ffdSToby Isaac   if (up) {
9456a5a2ffdSToby Isaac     PetscInt parent;
9466a5a2ffdSToby Isaac 
947*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeParent(dm,point,&parent,NULL));
9486a5a2ffdSToby Isaac     if (parent != point) {
9496a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
9506a5a2ffdSToby Isaac 
951*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
952270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
953270bba0cSToby Isaac         PetscInt cpoint = closure[2*i];
954270bba0cSToby Isaac 
955*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscHSetIAdd(ht, cpoint));
956*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE));
957270bba0cSToby Isaac       }
958*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
9596a5a2ffdSToby Isaac     }
9606a5a2ffdSToby Isaac   }
9616a5a2ffdSToby Isaac   if (down) {
9626a5a2ffdSToby Isaac     PetscInt numChildren;
9636a5a2ffdSToby Isaac     const PetscInt *children;
9646a5a2ffdSToby Isaac 
965*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeChildren(dm,point,&numChildren,&children));
9666a5a2ffdSToby Isaac     if (numChildren) {
9676a5a2ffdSToby Isaac       PetscInt i;
9686a5a2ffdSToby Isaac 
9696a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
9706a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
9716a5a2ffdSToby Isaac 
972*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscHSetIAdd(ht, cpoint));
973*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE));
9746a5a2ffdSToby Isaac       }
9756a5a2ffdSToby Isaac     }
9766a5a2ffdSToby Isaac   }
977270bba0cSToby Isaac   PetscFunctionReturn(0);
978270bba0cSToby Isaac }
979270bba0cSToby Isaac 
9808e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point)
9818e330a33SStefano Zampini {
9828e330a33SStefano Zampini   PetscInt       parent;
983825f8a23SLisandro Dalcin 
9848e330a33SStefano Zampini   PetscFunctionBeginHot;
985*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetTreeParent(dm, point, &parent,NULL));
9868e330a33SStefano Zampini   if (point != parent) {
9878e330a33SStefano Zampini     const PetscInt *cone;
9888e330a33SStefano Zampini     PetscInt       coneSize, c;
9898e330a33SStefano Zampini 
990*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexAddClosureTree_Up_Private(dm, ht, parent));
991*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexAddClosure_Private(dm, ht, parent));
992*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCone(dm, parent, &cone));
993*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeSize(dm, parent, &coneSize));
9948e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
9958e330a33SStefano Zampini       const PetscInt cp = cone[c];
9968e330a33SStefano Zampini 
997*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexAddClosureTree_Up_Private(dm, ht, cp));
9988e330a33SStefano Zampini     }
9998e330a33SStefano Zampini   }
10008e330a33SStefano Zampini   PetscFunctionReturn(0);
10018e330a33SStefano Zampini }
10028e330a33SStefano Zampini 
10038e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point)
10048e330a33SStefano Zampini {
10058e330a33SStefano Zampini   PetscInt       i, numChildren;
10068e330a33SStefano Zampini   const PetscInt *children;
10078e330a33SStefano Zampini 
10088e330a33SStefano Zampini   PetscFunctionBeginHot;
1009*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
10108e330a33SStefano Zampini   for (i = 0; i < numChildren; i++) {
1011*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscHSetIAdd(ht, children[i]));
10128e330a33SStefano Zampini   }
10138e330a33SStefano Zampini   PetscFunctionReturn(0);
10148e330a33SStefano Zampini }
10158e330a33SStefano Zampini 
10168e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point)
10178e330a33SStefano Zampini {
10188e330a33SStefano Zampini   const PetscInt *cone;
10198e330a33SStefano Zampini   PetscInt       coneSize, c;
10208e330a33SStefano Zampini 
10218e330a33SStefano Zampini   PetscFunctionBeginHot;
1022*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscHSetIAdd(ht, point));
1023*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexAddClosureTree_Up_Private(dm, ht, point));
1024*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexAddClosureTree_Down_Private(dm, ht, point));
1025*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetCone(dm, point, &cone));
1026*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetConeSize(dm, point, &coneSize));
10278e330a33SStefano Zampini   for (c = 0; c < coneSize; c++) {
1028*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexAddClosureTree_Private(dm, ht, cone[c]));
10298e330a33SStefano Zampini   }
10308e330a33SStefano Zampini   PetscFunctionReturn(0);
10318e330a33SStefano Zampini }
10328e330a33SStefano Zampini 
10338e330a33SStefano Zampini PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS)
1034825f8a23SLisandro Dalcin {
1035825f8a23SLisandro Dalcin   DM_Plex         *mesh = (DM_Plex *)dm->data;
10368e330a33SStefano Zampini   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
10378e330a33SStefano Zampini   PetscInt        nelems, *elems, off = 0, p;
103827104ee2SJacob Faibussowitsch   PetscHSetI      ht = NULL;
1039825f8a23SLisandro Dalcin 
1040825f8a23SLisandro Dalcin   PetscFunctionBegin;
1041*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscHSetICreate(&ht));
1042*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscHSetIResize(ht, numPoints*16));
10438e330a33SStefano Zampini   if (!hasTree) {
10448e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
1045*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexAddClosure_Private(dm, ht, points[p]));
10468e330a33SStefano Zampini     }
10478e330a33SStefano Zampini   } else {
10488e330a33SStefano Zampini #if 1
10498e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
1050*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexAddClosureTree_Private(dm, ht, points[p]));
10518e330a33SStefano Zampini     }
10528e330a33SStefano Zampini #else
10538e330a33SStefano Zampini     PetscInt  *closure = NULL, closureSize, c;
1054825f8a23SLisandro Dalcin     for (p = 0; p < numPoints; ++p) {
1055*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure));
1056825f8a23SLisandro Dalcin       for (c = 0; c < closureSize*2; c += 2) {
1057*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscHSetIAdd(ht, closure[c]));
1058*5f80ce2aSJacob Faibussowitsch         if (hasTree) CHKERRQ(DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE));
1059825f8a23SLisandro Dalcin       }
1060825f8a23SLisandro Dalcin     }
1061*5f80ce2aSJacob Faibussowitsch     if (closure) CHKERRQ(DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure));
10628e330a33SStefano Zampini #endif
10638e330a33SStefano Zampini   }
1064*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscHSetIGetSize(ht, &nelems));
1065*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(nelems, &elems));
1066*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscHSetIGetElems(ht, &off, elems));
1067*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscHSetIDestroy(&ht));
1068*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSortInt(nelems, elems));
1069*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS));
1070825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
1071825f8a23SLisandro Dalcin }
1072825f8a23SLisandro Dalcin 
10735abbe4feSMichael Lange /*@
10745abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
10755abbe4feSMichael Lange 
10765abbe4feSMichael Lange   Input Parameters:
10775abbe4feSMichael Lange + dm     - The DM
1078a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
10795abbe4feSMichael Lange 
10805abbe4feSMichael Lange   Level: developer
10815abbe4feSMichael Lange 
108230b0ce1bSStefano Zampini .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
10835abbe4feSMichael Lange @*/
10845abbe4feSMichael Lange PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
10859ffc88e4SToby Isaac {
1086825f8a23SLisandro Dalcin   IS              rankIS,   pointIS, closureIS;
10875abbe4feSMichael Lange   const PetscInt *ranks,   *points;
1088825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
10899ffc88e4SToby Isaac 
10909ffc88e4SToby Isaac   PetscFunctionBegin;
1091*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelGetValueIS(label, &rankIS));
1092*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetLocalSize(rankIS, &numRanks));
1093*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(rankIS, &ranks));
10945abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
10955abbe4feSMichael Lange     const PetscInt rank = ranks[r];
1096*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumIS(label, rank, &pointIS));
1097*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetLocalSize(pointIS, &numPoints));
1098*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetIndices(pointIS, &points));
1099*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS));
1100*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISRestoreIndices(pointIS, &points));
1101*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&pointIS));
1102*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelSetStratumIS(label, rank, closureIS));
1103*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&closureIS));
11049ffc88e4SToby Isaac   }
1105*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(rankIS, &ranks));
1106*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&rankIS));
11079ffc88e4SToby Isaac   PetscFunctionReturn(0);
11089ffc88e4SToby Isaac }
11099ffc88e4SToby Isaac 
111024d039d7SMichael Lange /*@
111124d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
111224d039d7SMichael Lange 
111324d039d7SMichael Lange   Input Parameters:
111424d039d7SMichael Lange + dm     - The DM
1115a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
111624d039d7SMichael Lange 
111724d039d7SMichael Lange   Level: developer
111824d039d7SMichael Lange 
11192d4ee042Sprj- .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
112024d039d7SMichael Lange @*/
112124d039d7SMichael Lange PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
112270034214SMatthew G. Knepley {
112324d039d7SMichael Lange   IS              rankIS,   pointIS;
112424d039d7SMichael Lange   const PetscInt *ranks,   *points;
112524d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
112624d039d7SMichael Lange   PetscInt       *adj = NULL;
112770034214SMatthew G. Knepley 
112870034214SMatthew G. Knepley   PetscFunctionBegin;
1129*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelGetValueIS(label, &rankIS));
1130*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetLocalSize(rankIS, &numRanks));
1131*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(rankIS, &ranks));
113224d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
113324d039d7SMichael Lange     const PetscInt rank = ranks[r];
113470034214SMatthew G. Knepley 
1135*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumIS(label, rank, &pointIS));
1136*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetLocalSize(pointIS, &numPoints));
1137*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetIndices(pointIS, &points));
113870034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
113924d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
1140*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetAdjacency(dm, points[p], &adjSize, &adj));
1141*5f80ce2aSJacob Faibussowitsch       for (a = 0; a < adjSize; ++a) CHKERRQ(DMLabelSetValue(label, adj[a], rank));
114270034214SMatthew G. Knepley     }
1143*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISRestoreIndices(pointIS, &points));
1144*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&pointIS));
114570034214SMatthew G. Knepley   }
1146*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(rankIS, &ranks));
1147*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&rankIS));
1148*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(adj));
114924d039d7SMichael Lange   PetscFunctionReturn(0);
115070034214SMatthew G. Knepley }
115170034214SMatthew G. Knepley 
1152be200f8dSMichael Lange /*@
1153be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
1154be200f8dSMichael Lange 
1155be200f8dSMichael Lange   Input Parameters:
1156be200f8dSMichael Lange + dm     - The DM
1157a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
1158be200f8dSMichael Lange 
1159be200f8dSMichael Lange   Level: developer
1160be200f8dSMichael Lange 
1161be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
1162be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
1163be200f8dSMichael Lange 
11642d4ee042Sprj- .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
1165be200f8dSMichael Lange @*/
1166be200f8dSMichael Lange PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
1167be200f8dSMichael Lange {
1168be200f8dSMichael Lange   MPI_Comm        comm;
1169be200f8dSMichael Lange   PetscMPIInt     rank;
1170be200f8dSMichael Lange   PetscSF         sfPoint;
11715d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
1172be200f8dSMichael Lange   IS              rankIS, pointIS;
1173be200f8dSMichael Lange   const PetscInt *ranks;
1174be200f8dSMichael Lange   PetscInt        numRanks, r;
1175be200f8dSMichael Lange 
1176be200f8dSMichael Lange   PetscFunctionBegin;
1177*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject) dm, &comm));
1178*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm, &rank));
1179*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetPointSF(dm, &sfPoint));
11805d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
1181*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelGather(label, sfPoint, &lblLeaves));
1182*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelGetValueIS(lblLeaves, &rankIS));
1183*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetLocalSize(rankIS, &numRanks));
1184*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(rankIS, &ranks));
11855d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
11865d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
11875d04f6ebSMichael Lange     if (remoteRank == rank) continue;
1188*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS));
1189*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelInsertIS(label, pointIS, remoteRank));
1190*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&pointIS));
11915d04f6ebSMichael Lange   }
1192*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(rankIS, &ranks));
1193*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&rankIS));
1194*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelDestroy(&lblLeaves));
1195be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
1196*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelDistribute(label, sfPoint, &lblRoots));
1197*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelGetValueIS(lblRoots, &rankIS));
1198*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetLocalSize(rankIS, &numRanks));
1199*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(rankIS, &ranks));
1200be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
1201be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
1202be200f8dSMichael Lange     if (remoteRank == rank) continue;
1203*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS));
1204*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelInsertIS(label, pointIS, remoteRank));
1205*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&pointIS));
1206be200f8dSMichael Lange   }
1207*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(rankIS, &ranks));
1208*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&rankIS));
1209*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelDestroy(&lblRoots));
1210be200f8dSMichael Lange   PetscFunctionReturn(0);
1211be200f8dSMichael Lange }
1212be200f8dSMichael Lange 
12131fd9873aSMichael Lange /*@
12141fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
12151fd9873aSMichael Lange 
12161fd9873aSMichael Lange   Input Parameters:
12171fd9873aSMichael Lange + dm        - The DM
1218a5b23f4aSJose E. Roman . rootLabel - DMLabel assigning ranks to local roots
1219fe2efc57SMark - processSF - A star forest mapping into the local index on each remote rank
12201fd9873aSMichael Lange 
12211fd9873aSMichael Lange   Output Parameter:
1222a5b23f4aSJose E. Roman . leafLabel - DMLabel assigning ranks to remote roots
12231fd9873aSMichael Lange 
12241fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
12251fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
12261fd9873aSMichael Lange 
12271fd9873aSMichael Lange   Level: developer
12281fd9873aSMichael Lange 
12292d4ee042Sprj- .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
12301fd9873aSMichael Lange @*/
12311fd9873aSMichael Lange PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
12321fd9873aSMichael Lange {
12331fd9873aSMichael Lange   MPI_Comm           comm;
1234874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
1235874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
12361fd9873aSMichael Lange   PetscSF            sfPoint;
1237874ddda9SLisandro Dalcin   PetscSection       rootSection;
12381fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
12391fd9873aSMichael Lange   const PetscSFNode *remote;
12401fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
12411fd9873aSMichael Lange   IS                 valueIS;
1242874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
12431fd9873aSMichael Lange 
12441fd9873aSMichael Lange   PetscFunctionBegin;
1245*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogEventBegin(DMPLEX_PartLabelInvert,dm,0,0,0));
1246*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject) dm, &comm));
1247*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm, &rank));
1248*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_size(comm, &size));
1249*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetPointSF(dm, &sfPoint));
12501fd9873aSMichael Lange 
12511fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
1252*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(comm, &rootSection));
1253*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(rootSection, 0, size));
1254*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelGetValueIS(rootLabel, &valueIS));
1255*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetLocalSize(valueIS, &numNeighbors));
1256*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(valueIS, &neighbors));
12571fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
1258*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints));
1259*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionAddDof(rootSection, neighbors[n], numPoints));
12601fd9873aSMichael Lange   }
1261*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(rootSection));
1262*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(rootSection, &rootSize));
1263*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(rootSize, &rootPoints));
1264*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote));
12651fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
12661fd9873aSMichael Lange     IS              pointIS;
12671fd9873aSMichael Lange     const PetscInt *points;
12681fd9873aSMichael Lange 
1269*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(rootSection, neighbors[n], &off));
1270*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS));
1271*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetLocalSize(pointIS, &numPoints));
1272*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetIndices(pointIS, &points));
12731fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
1274*5f80ce2aSJacob Faibussowitsch       if (local) CHKERRQ(PetscFindInt(points[p], nleaves, local, &l));
1275f8987ae8SMichael Lange       else       {l = -1;}
12761fd9873aSMichael Lange       if (l >= 0) {rootPoints[off+p] = remote[l];}
12771fd9873aSMichael Lange       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
12781fd9873aSMichael Lange     }
1279*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISRestoreIndices(pointIS, &points));
1280*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&pointIS));
12811fd9873aSMichael Lange   }
1282874ddda9SLisandro Dalcin 
1283874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
1284874ddda9SLisandro Dalcin   if (!processSF) {
1285874ddda9SLisandro Dalcin     PetscInt64  counter = 0;
1286874ddda9SLisandro Dalcin     PetscBool   locOverflow = PETSC_FALSE;
1287874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
1288874ddda9SLisandro Dalcin 
1289*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls));
1290874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
1291*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(rootSection, neighbors[n], &dof));
1292*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(rootSection, neighbors[n], &off));
1293874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
1294874ddda9SLisandro Dalcin       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
1295874ddda9SLisandro Dalcin       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
1296874ddda9SLisandro Dalcin #endif
1297874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt) dof;
1298874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt) off;
1299874ddda9SLisandro Dalcin     }
1300*5f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm));
1301874ddda9SLisandro Dalcin     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
1302874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
1303*5f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm));
1304874ddda9SLisandro Dalcin     if (!mpiOverflow) {
1305*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscInfo(dm,"Using Alltoallv for mesh distribution\n"));
1306874ddda9SLisandro Dalcin       leafSize = (PetscInt) counter;
1307*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(leafSize, &leafPoints));
1308*5f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm));
1309874ddda9SLisandro Dalcin     }
1310*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree4(scounts, sdispls, rcounts, rdispls));
1311874ddda9SLisandro Dalcin   }
1312874ddda9SLisandro Dalcin 
1313874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
1314874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
1315874ddda9SLisandro Dalcin     PetscSF      procSF;
1316874ddda9SLisandro Dalcin     PetscSection leafSection;
1317874ddda9SLisandro Dalcin 
1318874ddda9SLisandro Dalcin     if (processSF) {
1319*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscInfo(dm,"Using processSF for mesh distribution\n"));
1320*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectReference((PetscObject)processSF));
1321874ddda9SLisandro Dalcin       procSF = processSF;
1322874ddda9SLisandro Dalcin     } else {
1323*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscInfo(dm,"Using processSF for mesh distribution (MPI overflow)\n"));
1324*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFCreate(comm,&procSF));
1325*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFSetGraphWithPattern(procSF,NULL,PETSCSF_PATTERN_ALLTOALL));
1326874ddda9SLisandro Dalcin     }
1327874ddda9SLisandro Dalcin 
1328*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection));
1329*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexDistributeData(dm, procSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints));
1330*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetStorageSize(leafSection, &leafSize));
1331*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&leafSection));
1332*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&procSF));
1333874ddda9SLisandro Dalcin   }
1334874ddda9SLisandro Dalcin 
1335874ddda9SLisandro Dalcin   for (p = 0; p < leafSize; p++) {
1336*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank));
13371fd9873aSMichael Lange   }
1338874ddda9SLisandro Dalcin 
1339*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISRestoreIndices(valueIS, &neighbors));
1340*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&valueIS));
1341*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&rootSection));
1342*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(rootPoints));
1343*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(leafPoints));
1344*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogEventEnd(DMPLEX_PartLabelInvert,dm,0,0,0));
13451fd9873aSMichael Lange   PetscFunctionReturn(0);
13461fd9873aSMichael Lange }
13471fd9873aSMichael Lange 
1348aa3148a8SMichael Lange /*@
1349aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
1350aa3148a8SMichael Lange 
1351aa3148a8SMichael Lange   Input Parameters:
1352aa3148a8SMichael Lange + dm    - The DM
1353a5b23f4aSJose E. Roman - label - DMLabel assigning ranks to remote roots
1354aa3148a8SMichael Lange 
1355aa3148a8SMichael Lange   Output Parameter:
1356fe2efc57SMark . sf    - The star forest communication context encapsulating the defined mapping
1357aa3148a8SMichael Lange 
1358aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
1359aa3148a8SMichael Lange 
1360aa3148a8SMichael Lange   Level: developer
1361aa3148a8SMichael Lange 
136230b0ce1bSStefano Zampini .seealso: DMPlexDistribute(), DMPlexCreateOverlap()
1363aa3148a8SMichael Lange @*/
1364aa3148a8SMichael Lange PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
1365aa3148a8SMichael Lange {
13666e203dd9SStefano Zampini   PetscMPIInt     rank;
13676e203dd9SStefano Zampini   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
1368aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
13696e203dd9SStefano Zampini   IS              remoteRootIS, neighborsIS;
13706e203dd9SStefano Zampini   const PetscInt *remoteRoots, *neighbors;
1371aa3148a8SMichael Lange 
1372aa3148a8SMichael Lange   PetscFunctionBegin;
1373*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogEventBegin(DMPLEX_PartLabelCreateSF,dm,0,0,0));
1374*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
1375aa3148a8SMichael Lange 
1376*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelGetValueIS(label, &neighborsIS));
13776e203dd9SStefano Zampini #if 0
13786e203dd9SStefano Zampini   {
13796e203dd9SStefano Zampini     IS is;
1380*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDuplicate(neighborsIS, &is));
1381*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISSort(is));
1382*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&neighborsIS));
13836e203dd9SStefano Zampini     neighborsIS = is;
13846e203dd9SStefano Zampini   }
13856e203dd9SStefano Zampini #endif
1386*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetLocalSize(neighborsIS, &nNeighbors));
1387*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISGetIndices(neighborsIS, &neighbors));
13886e203dd9SStefano Zampini   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
1389*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumSize(label, neighbors[n], &numPoints));
1390aa3148a8SMichael Lange     numRemote += numPoints;
1391aa3148a8SMichael Lange   }
1392*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(numRemote, &remotePoints));
139343f7d02bSMichael Lange   /* Put owned points first */
1394*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMLabelGetStratumSize(label, rank, &numPoints));
139543f7d02bSMichael Lange   if (numPoints > 0) {
1396*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumIS(label, rank, &remoteRootIS));
1397*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetIndices(remoteRootIS, &remoteRoots));
139843f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
139943f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
140043f7d02bSMichael Lange       remotePoints[idx].rank = rank;
140143f7d02bSMichael Lange       idx++;
140243f7d02bSMichael Lange     }
1403*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISRestoreIndices(remoteRootIS, &remoteRoots));
1404*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&remoteRootIS));
140543f7d02bSMichael Lange   }
140643f7d02bSMichael Lange   /* Now add remote points */
14076e203dd9SStefano Zampini   for (n = 0; n < nNeighbors; ++n) {
14086e203dd9SStefano Zampini     const PetscInt nn = neighbors[n];
14096e203dd9SStefano Zampini 
1410*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumSize(label, nn, &numPoints));
14116e203dd9SStefano Zampini     if (nn == rank || numPoints <= 0) continue;
1412*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLabelGetStratumIS(label, nn, &remoteRootIS));
1413*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetIndices(remoteRootIS, &remoteRoots));
1414aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
1415aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
14166e203dd9SStefano Zampini       remotePoints[idx].rank = nn;
1417aa3148a8SMichael Lange       idx++;
1418aa3148a8SMichael Lange     }
1419*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISRestoreIndices(remoteRootIS, &remoteRoots));
1420*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&remoteRootIS));
1421aa3148a8SMichael Lange   }
1422*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFCreate(PetscObjectComm((PetscObject) dm), sf));
1423*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
1424*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER));
1425*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFSetUp(*sf));
1426*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&neighborsIS));
1427*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogEventEnd(DMPLEX_PartLabelCreateSF,dm,0,0,0));
142870034214SMatthew G. Knepley   PetscFunctionReturn(0);
142970034214SMatthew G. Knepley }
1430cb87ef4cSFlorian Wechsung 
1431abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PARMETIS)
1432abe9303eSLisandro Dalcin #include <parmetis.h>
1433abe9303eSLisandro Dalcin #endif
1434abe9303eSLisandro Dalcin 
14356a3739e5SFlorian Wechsung /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
14366a3739e5SFlorian Wechsung  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
14376a3739e5SFlorian Wechsung  * them out in that case. */
14386a3739e5SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
14397a82c785SFlorian Wechsung /*@C
14407f57c1a4SFlorian Wechsung 
14417f57c1a4SFlorian Wechsung   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).
14427f57c1a4SFlorian Wechsung 
14437f57c1a4SFlorian Wechsung   Input parameters:
14447f57c1a4SFlorian Wechsung + dm                - The DMPlex object.
1445fe2efc57SMark . n                 - The number of points.
1446fe2efc57SMark . pointsToRewrite   - The points in the SF whose ownership will change.
1447fe2efc57SMark . targetOwners      - New owner for each element in pointsToRewrite.
1448fe2efc57SMark - degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.
14497f57c1a4SFlorian Wechsung 
14507f57c1a4SFlorian Wechsung   Level: developer
14517f57c1a4SFlorian Wechsung 
14527f57c1a4SFlorian Wechsung @*/
14537f57c1a4SFlorian Wechsung static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
14547f57c1a4SFlorian Wechsung {
1455*5f80ce2aSJacob Faibussowitsch   PetscInt      pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
14567f57c1a4SFlorian Wechsung   PetscInt     *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
14577f57c1a4SFlorian Wechsung   PetscSFNode  *leafLocationsNew;
14587f57c1a4SFlorian Wechsung   const         PetscSFNode *iremote;
14597f57c1a4SFlorian Wechsung   const         PetscInt *ilocal;
14607f57c1a4SFlorian Wechsung   PetscBool    *isLeaf;
14617f57c1a4SFlorian Wechsung   PetscSF       sf;
14627f57c1a4SFlorian Wechsung   MPI_Comm      comm;
14635a30b08bSFlorian Wechsung   PetscMPIInt   rank, size;
14647f57c1a4SFlorian Wechsung 
14657f57c1a4SFlorian Wechsung   PetscFunctionBegin;
1466*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject) dm, &comm));
1467*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm, &rank));
1468*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_size(comm, &size));
1469*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
14707f57c1a4SFlorian Wechsung 
1471*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetPointSF(dm, &sf));
1472*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
1473*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &isLeaf));
14747f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
14757f57c1a4SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
14767f57c1a4SFlorian Wechsung   }
14777f57c1a4SFlorian Wechsung   for (i=0; i<nleafs; i++) {
14787f57c1a4SFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
14797f57c1a4SFlorian Wechsung   }
14807f57c1a4SFlorian Wechsung 
1481*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart+1, &cumSumDegrees));
14827f57c1a4SFlorian Wechsung   cumSumDegrees[0] = 0;
14837f57c1a4SFlorian Wechsung   for (i=1; i<=pEnd-pStart; i++) {
14847f57c1a4SFlorian Wechsung     cumSumDegrees[i] = cumSumDegrees[i-1] + degrees[i-1];
14857f57c1a4SFlorian Wechsung   }
14867f57c1a4SFlorian Wechsung   sumDegrees = cumSumDegrees[pEnd-pStart];
14877f57c1a4SFlorian Wechsung   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
14887f57c1a4SFlorian Wechsung 
1489*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(sumDegrees, &locationsOfLeafs));
1490*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &rankOnLeafs));
14917f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
14927f57c1a4SFlorian Wechsung     rankOnLeafs[i] = rank;
14937f57c1a4SFlorian Wechsung   }
1494*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
1495*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
1496*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(rankOnLeafs));
14977f57c1a4SFlorian Wechsung 
14987f57c1a4SFlorian Wechsung   /* get the remote local points of my leaves */
1499*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs));
1500*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &points));
15017f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
15027f57c1a4SFlorian Wechsung     points[i] = pStart+i;
15037f57c1a4SFlorian Wechsung   }
1504*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
1505*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
1506*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(points));
15077f57c1a4SFlorian Wechsung   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
1508*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &newOwners));
1509*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &newNumbers));
15107f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
15117f57c1a4SFlorian Wechsung     newOwners[i] = -1;
15127f57c1a4SFlorian Wechsung     newNumbers[i] = -1;
15137f57c1a4SFlorian Wechsung   }
15147f57c1a4SFlorian Wechsung   {
15157f57c1a4SFlorian Wechsung     PetscInt oldNumber, newNumber, oldOwner, newOwner;
15167f57c1a4SFlorian Wechsung     for (i=0; i<n; i++) {
15177f57c1a4SFlorian Wechsung       oldNumber = pointsToRewrite[i];
15187f57c1a4SFlorian Wechsung       newNumber = -1;
15197f57c1a4SFlorian Wechsung       oldOwner = rank;
15207f57c1a4SFlorian Wechsung       newOwner = targetOwners[i];
15217f57c1a4SFlorian Wechsung       if (oldOwner == newOwner) {
15227f57c1a4SFlorian Wechsung         newNumber = oldNumber;
15237f57c1a4SFlorian Wechsung       } else {
15247f57c1a4SFlorian Wechsung         for (j=0; j<degrees[oldNumber]; j++) {
15257f57c1a4SFlorian Wechsung           if (locationsOfLeafs[cumSumDegrees[oldNumber]+j] == newOwner) {
15267f57c1a4SFlorian Wechsung             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber]+j];
15277f57c1a4SFlorian Wechsung             break;
15287f57c1a4SFlorian Wechsung           }
15297f57c1a4SFlorian Wechsung         }
15307f57c1a4SFlorian Wechsung       }
1531*5f80ce2aSJacob Faibussowitsch       PetscCheck(newNumber != -1,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
15327f57c1a4SFlorian Wechsung 
15337f57c1a4SFlorian Wechsung       newOwners[oldNumber] = newOwner;
15347f57c1a4SFlorian Wechsung       newNumbers[oldNumber] = newNumber;
15357f57c1a4SFlorian Wechsung     }
15367f57c1a4SFlorian Wechsung   }
1537*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(cumSumDegrees));
1538*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(locationsOfLeafs));
1539*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(remoteLocalPointOfLeafs));
15407f57c1a4SFlorian Wechsung 
1541*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners,MPI_REPLACE));
1542*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners,MPI_REPLACE));
1543*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers,MPI_REPLACE));
1544*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers,MPI_REPLACE));
15457f57c1a4SFlorian Wechsung 
15467f57c1a4SFlorian Wechsung   /* Now count how many leafs we have on each processor. */
15477f57c1a4SFlorian Wechsung   leafCounter=0;
15487f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
15497f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
15507f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
15517f57c1a4SFlorian Wechsung         leafCounter++;
15527f57c1a4SFlorian Wechsung       }
15537f57c1a4SFlorian Wechsung     } else {
15547f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
15557f57c1a4SFlorian Wechsung         leafCounter++;
15567f57c1a4SFlorian Wechsung       }
15577f57c1a4SFlorian Wechsung     }
15587f57c1a4SFlorian Wechsung   }
15597f57c1a4SFlorian Wechsung 
15607f57c1a4SFlorian Wechsung   /* Now set up the new sf by creating the leaf arrays */
1561*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(leafCounter, &leafsNew));
1562*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(leafCounter, &leafLocationsNew));
15637f57c1a4SFlorian Wechsung 
15647f57c1a4SFlorian Wechsung   leafCounter = 0;
15657f57c1a4SFlorian Wechsung   counter = 0;
15667f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
15677f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
15687f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
15697f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
15707f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = newOwners[i];
15717f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = newNumbers[i];
15727f57c1a4SFlorian Wechsung         leafCounter++;
15737f57c1a4SFlorian Wechsung       }
15747f57c1a4SFlorian Wechsung     } else {
15757f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
15767f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
15777f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = iremote[counter].rank;
15787f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = iremote[counter].index;
15797f57c1a4SFlorian Wechsung         leafCounter++;
15807f57c1a4SFlorian Wechsung       }
15817f57c1a4SFlorian Wechsung     }
15827f57c1a4SFlorian Wechsung     if (isLeaf[i]) {
15837f57c1a4SFlorian Wechsung       counter++;
15847f57c1a4SFlorian Wechsung     }
15857f57c1a4SFlorian Wechsung   }
15867f57c1a4SFlorian Wechsung 
1587*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER));
1588*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(newOwners));
1589*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(newNumbers));
1590*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(isLeaf));
15917f57c1a4SFlorian Wechsung   PetscFunctionReturn(0);
15927f57c1a4SFlorian Wechsung }
15937f57c1a4SFlorian Wechsung 
1594125d2a8fSFlorian Wechsung static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
1595125d2a8fSFlorian Wechsung {
1596*5f80ce2aSJacob Faibussowitsch   PetscInt    *distribution, min, max, sum;
15975a30b08bSFlorian Wechsung   PetscMPIInt rank, size;
1598*5f80ce2aSJacob Faibussowitsch 
1599125d2a8fSFlorian Wechsung   PetscFunctionBegin;
1600*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_size(comm, &size));
1601*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm, &rank));
1602*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc1(size, &distribution));
1603*5f80ce2aSJacob Faibussowitsch   for (PetscInt i=0; i<n; i++) {
1604125d2a8fSFlorian Wechsung     if (part) distribution[part[i]] += vtxwgt[skip*i];
1605125d2a8fSFlorian Wechsung     else distribution[rank] += vtxwgt[skip*i];
1606125d2a8fSFlorian Wechsung   }
1607*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm));
1608125d2a8fSFlorian Wechsung   min = distribution[0];
1609125d2a8fSFlorian Wechsung   max = distribution[0];
1610125d2a8fSFlorian Wechsung   sum = distribution[0];
1611*5f80ce2aSJacob Faibussowitsch   for (PetscInt i=1; i<size; i++) {
1612125d2a8fSFlorian Wechsung     if (distribution[i]<min) min=distribution[i];
1613125d2a8fSFlorian Wechsung     if (distribution[i]>max) max=distribution[i];
1614125d2a8fSFlorian Wechsung     sum += distribution[i];
1615125d2a8fSFlorian Wechsung   }
1616*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerASCIIPrintf(viewer, "Min: %D, Avg: %D, Max: %D, Balance: %f\n", min, sum/size, max, (max*1.*size)/sum));
1617*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(distribution));
1618125d2a8fSFlorian Wechsung   PetscFunctionReturn(0);
1619125d2a8fSFlorian Wechsung }
1620125d2a8fSFlorian Wechsung 
16216a3739e5SFlorian Wechsung #endif
16226a3739e5SFlorian Wechsung 
1623cb87ef4cSFlorian Wechsung /*@
16245dc86ac1SFlorian Wechsung   DMPlexRebalanceSharedPoints - Redistribute points in the plex that are shared in order to achieve better balancing. This routine updates the PointSF of the DM inplace.
1625cb87ef4cSFlorian Wechsung 
1626cb87ef4cSFlorian Wechsung   Input parameters:
1627ed44d270SFlorian Wechsung + dm               - The DMPlex object.
1628fe2efc57SMark . entityDepth      - depth of the entity to balance (0 -> balance vertices).
1629fe2efc57SMark . useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
1630fe2efc57SMark - parallel         - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.
1631cb87ef4cSFlorian Wechsung 
16328b879b41SFlorian Wechsung   Output parameters:
1633fe2efc57SMark . success          - whether the graph partitioning was successful or not. If not, try useInitialGuess=True and parallel=True.
16348b879b41SFlorian Wechsung 
163590ea27d8SSatish Balay   Level: intermediate
1636cb87ef4cSFlorian Wechsung 
1637cb87ef4cSFlorian Wechsung @*/
1638cb87ef4cSFlorian Wechsung 
16398b879b41SFlorian Wechsung PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
1640cb87ef4cSFlorian Wechsung {
164141525646SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
1642cb87ef4cSFlorian Wechsung   PetscSF     sf;
16430faf6628SFlorian Wechsung   PetscInt    ierr, i, j, idx, jdx;
16447f57c1a4SFlorian Wechsung   PetscInt    eBegin, eEnd, nroots, nleafs, pStart, pEnd;
16457f57c1a4SFlorian Wechsung   const       PetscInt *degrees, *ilocal;
16467f57c1a4SFlorian Wechsung   const       PetscSFNode *iremote;
1647cb87ef4cSFlorian Wechsung   PetscBool   *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
1648cf818975SFlorian Wechsung   PetscInt    numExclusivelyOwned, numNonExclusivelyOwned;
1649cb87ef4cSFlorian Wechsung   PetscMPIInt rank, size;
16507f57c1a4SFlorian Wechsung   PetscInt    *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
16515dc86ac1SFlorian Wechsung   const       PetscInt *cumSumVertices;
1652cb87ef4cSFlorian Wechsung   PetscInt    offset, counter;
16537f57c1a4SFlorian Wechsung   PetscInt    lenadjncy;
1654cb87ef4cSFlorian Wechsung   PetscInt    *xadj, *adjncy, *vtxwgt;
1655cb87ef4cSFlorian Wechsung   PetscInt    lenxadj;
1656cb87ef4cSFlorian Wechsung   PetscInt    *adjwgt = NULL;
1657cb87ef4cSFlorian Wechsung   PetscInt    *part, *options;
1658cf818975SFlorian Wechsung   PetscInt    nparts, wgtflag, numflag, ncon, edgecut;
1659cb87ef4cSFlorian Wechsung   real_t      *ubvec;
1660cb87ef4cSFlorian Wechsung   PetscInt    *firstVertices, *renumbering;
1661cb87ef4cSFlorian Wechsung   PetscInt    failed, failedGlobal;
1662cb87ef4cSFlorian Wechsung   MPI_Comm    comm;
16634baf1206SFlorian Wechsung   Mat         A, Apre;
166412617df9SFlorian Wechsung   const char *prefix = NULL;
16657d197802SFlorian Wechsung   PetscViewer       viewer;
16667d197802SFlorian Wechsung   PetscViewerFormat format;
16675a30b08bSFlorian Wechsung   PetscLayout layout;
166812617df9SFlorian Wechsung 
166912617df9SFlorian Wechsung   PetscFunctionBegin;
16708b879b41SFlorian Wechsung   if (success) *success = PETSC_FALSE;
1671*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject) dm, &comm));
1672*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm, &rank));
1673*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_size(comm, &size));
16747f57c1a4SFlorian Wechsung   if (size==1) PetscFunctionReturn(0);
16757f57c1a4SFlorian Wechsung 
1676*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
167741525646SFlorian Wechsung 
1678*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsGetViewer(comm,((PetscObject)dm)->options, prefix,"-dm_rebalance_partition_view",&viewer,&format,NULL));
16795dc86ac1SFlorian Wechsung   if (viewer) {
1680*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerPushFormat(viewer,format));
16817d197802SFlorian Wechsung   }
16827d197802SFlorian Wechsung 
1683ed44d270SFlorian Wechsung   /* Figure out all points in the plex that we are interested in balancing. */
1684*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd));
1685*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(dm, &pStart, &pEnd));
1686*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &toBalance));
1687cf818975SFlorian Wechsung 
1688cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
16895a7e692eSFlorian Wechsung     toBalance[i] = (PetscBool)(i-pStart>=eBegin && i-pStart<eEnd);
1690cb87ef4cSFlorian Wechsung   }
1691cb87ef4cSFlorian Wechsung 
1692cf818975SFlorian Wechsung   /* There are three types of points:
1693cf818975SFlorian Wechsung    * exclusivelyOwned: points that are owned by this process and only seen by this process
1694cf818975SFlorian Wechsung    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
1695cf818975SFlorian Wechsung    * leaf: a point that is seen by this process but owned by a different process
1696cf818975SFlorian Wechsung    */
1697*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetPointSF(dm, &sf));
1698*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
1699*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &isLeaf));
1700*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &isNonExclusivelyOwned));
1701*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &isExclusivelyOwned));
1702cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
1703cb87ef4cSFlorian Wechsung     isNonExclusivelyOwned[i] = PETSC_FALSE;
1704cb87ef4cSFlorian Wechsung     isExclusivelyOwned[i] = PETSC_FALSE;
1705cf818975SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
1706cb87ef4cSFlorian Wechsung   }
1707cf818975SFlorian Wechsung 
1708cf818975SFlorian Wechsung   /* start by marking all the leafs */
1709cb87ef4cSFlorian Wechsung   for (i=0; i<nleafs; i++) {
1710cb87ef4cSFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
1711cb87ef4cSFlorian Wechsung   }
1712cb87ef4cSFlorian Wechsung 
1713cf818975SFlorian Wechsung   /* for an owned point, we can figure out whether another processor sees it or
1714cf818975SFlorian Wechsung    * not by calculating its degree */
1715*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFComputeDegreeBegin(sf, &degrees));
1716*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFComputeDegreeEnd(sf, &degrees));
1717cf818975SFlorian Wechsung 
1718cb87ef4cSFlorian Wechsung   numExclusivelyOwned = 0;
1719cb87ef4cSFlorian Wechsung   numNonExclusivelyOwned = 0;
1720cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
1721cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
17227f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1723cb87ef4cSFlorian Wechsung         isNonExclusivelyOwned[i] = PETSC_TRUE;
1724cb87ef4cSFlorian Wechsung         numNonExclusivelyOwned += 1;
1725cb87ef4cSFlorian Wechsung       } else {
1726cb87ef4cSFlorian Wechsung         if (!isLeaf[i]) {
1727cb87ef4cSFlorian Wechsung           isExclusivelyOwned[i] = PETSC_TRUE;
1728cb87ef4cSFlorian Wechsung           numExclusivelyOwned += 1;
1729cb87ef4cSFlorian Wechsung         }
1730cb87ef4cSFlorian Wechsung       }
1731cb87ef4cSFlorian Wechsung     }
1732cb87ef4cSFlorian Wechsung   }
1733cb87ef4cSFlorian Wechsung 
1734cf818975SFlorian Wechsung   /* We are going to build a graph with one vertex per core representing the
1735cf818975SFlorian Wechsung    * exclusively owned points and then one vertex per nonExclusively owned
1736cf818975SFlorian Wechsung    * point. */
1737cb87ef4cSFlorian Wechsung 
1738*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutCreate(comm, &layout));
1739*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned));
1740*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutSetUp(layout));
1741*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutGetRanges(layout, &cumSumVertices));
17425dc86ac1SFlorian Wechsung 
1743*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &globalNumbersOfLocalOwnedVertices));
17445a427404SJunchao Zhang   for (i=0; i<pEnd-pStart; i++) {globalNumbersOfLocalOwnedVertices[i] = pStart - 1;}
1745cb87ef4cSFlorian Wechsung   offset = cumSumVertices[rank];
1746cb87ef4cSFlorian Wechsung   counter = 0;
1747cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
1748cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
17497f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1750cb87ef4cSFlorian Wechsung         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
1751cb87ef4cSFlorian Wechsung         counter++;
1752cb87ef4cSFlorian Wechsung       }
1753cb87ef4cSFlorian Wechsung     }
1754cb87ef4cSFlorian Wechsung   }
1755cb87ef4cSFlorian Wechsung 
1756cb87ef4cSFlorian Wechsung   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
1757*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(pEnd-pStart, &leafGlobalNumbers));
1758*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers,MPI_REPLACE));
1759*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers,MPI_REPLACE));
1760cb87ef4cSFlorian Wechsung 
17610faf6628SFlorian Wechsung   /* Now start building the data structure for ParMETIS */
1762cb87ef4cSFlorian Wechsung 
1763*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreate(comm, &Apre));
1764*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetType(Apre, MATPREALLOCATOR));
1765*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetSizes(Apre, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]));
1766*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetUp(Apre));
17678c9a1619SFlorian Wechsung 
17688c9a1619SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
17698c9a1619SFlorian Wechsung     if (toBalance[i]) {
17700faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
17710faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
17720faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
17730faf6628SFlorian Wechsung       else continue;
1774*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetValue(Apre, idx, jdx, 1, INSERT_VALUES));
1775*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetValue(Apre, jdx, idx, 1, INSERT_VALUES));
17764baf1206SFlorian Wechsung     }
17774baf1206SFlorian Wechsung   }
17784baf1206SFlorian Wechsung 
1779*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(Apre, MAT_FINAL_ASSEMBLY));
1780*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(Apre, MAT_FINAL_ASSEMBLY));
17814baf1206SFlorian Wechsung 
1782*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreate(comm, &A));
1783*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetType(A, MATMPIAIJ));
1784*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetSizes(A, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]));
1785*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatPreallocatorPreallocate(Apre, PETSC_FALSE, A));
1786*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Apre));
17874baf1206SFlorian Wechsung 
17884baf1206SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
17894baf1206SFlorian Wechsung     if (toBalance[i]) {
17900faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
17910faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
17920faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
17930faf6628SFlorian Wechsung       else continue;
1794*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetValue(A, idx, jdx, 1, INSERT_VALUES));
1795*5f80ce2aSJacob Faibussowitsch       CHKERRQ(MatSetValue(A, jdx, idx, 1, INSERT_VALUES));
17960941debbSFlorian Wechsung     }
17970941debbSFlorian Wechsung   }
17988c9a1619SFlorian Wechsung 
1799*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1800*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1801*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(leafGlobalNumbers));
1802*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(globalNumbersOfLocalOwnedVertices));
18034baf1206SFlorian Wechsung 
180441525646SFlorian Wechsung   nparts = size;
180541525646SFlorian Wechsung   wgtflag = 2;
180641525646SFlorian Wechsung   numflag = 0;
180741525646SFlorian Wechsung   ncon = 2;
180841525646SFlorian Wechsung   real_t *tpwgts;
1809*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(ncon * nparts, &tpwgts));
181041525646SFlorian Wechsung   for (i=0; i<ncon*nparts; i++) {
181141525646SFlorian Wechsung     tpwgts[i] = 1./(nparts);
181241525646SFlorian Wechsung   }
181341525646SFlorian Wechsung 
1814*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(ncon, &ubvec));
181541525646SFlorian Wechsung   ubvec[0] = 1.01;
18165a30b08bSFlorian Wechsung   ubvec[1] = 1.01;
18178c9a1619SFlorian Wechsung   lenadjncy = 0;
18188c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
18198c9a1619SFlorian Wechsung     PetscInt temp=0;
1820*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL));
18218c9a1619SFlorian Wechsung     lenadjncy += temp;
1822*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatRestoreRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL));
18238c9a1619SFlorian Wechsung   }
1824*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(lenadjncy, &adjncy));
18257407ba93SFlorian Wechsung   lenxadj = 2 + numNonExclusivelyOwned;
1826*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(lenxadj, &xadj));
18270941debbSFlorian Wechsung   xadj[0] = 0;
18288c9a1619SFlorian Wechsung   counter = 0;
18298c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
18302953a68cSFlorian Wechsung     PetscInt        temp=0;
18312953a68cSFlorian Wechsung     const PetscInt *cols;
1832*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL));
1833*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscArraycpy(&adjncy[counter], cols, temp));
18348c9a1619SFlorian Wechsung     counter += temp;
18350941debbSFlorian Wechsung     xadj[i+1] = counter;
1836*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatRestoreRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL));
18378c9a1619SFlorian Wechsung   }
18388c9a1619SFlorian Wechsung 
1839*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(cumSumVertices[rank+1]-cumSumVertices[rank], &part));
1840*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(ncon*(1 + numNonExclusivelyOwned), &vtxwgt));
184141525646SFlorian Wechsung   vtxwgt[0] = numExclusivelyOwned;
184241525646SFlorian Wechsung   if (ncon>1) vtxwgt[1] = 1;
184341525646SFlorian Wechsung   for (i=0; i<numNonExclusivelyOwned; i++) {
184441525646SFlorian Wechsung     vtxwgt[ncon*(i+1)] = 1;
184541525646SFlorian Wechsung     if (ncon>1) vtxwgt[ncon*(i+1)+1] = 0;
184641525646SFlorian Wechsung   }
18478c9a1619SFlorian Wechsung 
18485dc86ac1SFlorian Wechsung   if (viewer) {
1849*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %D on interface of mesh distribution.\n", entityDepth));
1850*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %D\n", cumSumVertices[size]));
185112617df9SFlorian Wechsung   }
185241525646SFlorian Wechsung   if (parallel) {
1853*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(4, &options));
18545a30b08bSFlorian Wechsung     options[0] = 1;
18555a30b08bSFlorian Wechsung     options[1] = 0; /* Verbosity */
18565a30b08bSFlorian Wechsung     options[2] = 0; /* Seed */
18575a30b08bSFlorian Wechsung     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
1858*5f80ce2aSJacob Faibussowitsch     if (viewer) CHKERRQ(PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n"));
18598c9a1619SFlorian Wechsung     if (useInitialGuess) {
1860*5f80ce2aSJacob Faibussowitsch       if (viewer) CHKERRQ(PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n"));
18618c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_RefineKway");
18625dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_RefineKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
1863*5f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
18648c9a1619SFlorian Wechsung       PetscStackPop;
18658c9a1619SFlorian Wechsung     } else {
18668c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_PartKway");
18675dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_PartKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
18688c9a1619SFlorian Wechsung       PetscStackPop;
1869*5f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
18708c9a1619SFlorian Wechsung     }
1871*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(options));
187241525646SFlorian Wechsung   } else {
1873*5f80ce2aSJacob Faibussowitsch     if (viewer) CHKERRQ(PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n"));
187441525646SFlorian Wechsung     Mat As;
187541525646SFlorian Wechsung     PetscInt numRows;
187641525646SFlorian Wechsung     PetscInt *partGlobal;
1877*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCreateRedundantMatrix(A, size, MPI_COMM_NULL, MAT_INITIAL_MATRIX, &As));
1878cb87ef4cSFlorian Wechsung 
187941525646SFlorian Wechsung     PetscInt *numExclusivelyOwnedAll;
1880*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(size, &numExclusivelyOwnedAll));
188141525646SFlorian Wechsung     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
1882*5f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,numExclusivelyOwnedAll,1,MPIU_INT,comm));
1883cb87ef4cSFlorian Wechsung 
1884*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetSize(As, &numRows, NULL));
1885*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numRows, &partGlobal));
1886dd400576SPatrick Sanan     if (rank == 0) {
188741525646SFlorian Wechsung       PetscInt *adjncy_g, *xadj_g, *vtxwgt_g;
188841525646SFlorian Wechsung       lenadjncy = 0;
188941525646SFlorian Wechsung 
189041525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
189141525646SFlorian Wechsung         PetscInt temp=0;
1892*5f80ce2aSJacob Faibussowitsch         CHKERRQ(MatGetRow(As, i, &temp, NULL, NULL));
189341525646SFlorian Wechsung         lenadjncy += temp;
1894*5f80ce2aSJacob Faibussowitsch         CHKERRQ(MatRestoreRow(As, i, &temp, NULL, NULL));
189541525646SFlorian Wechsung       }
1896*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(lenadjncy, &adjncy_g));
189741525646SFlorian Wechsung       lenxadj = 1 + numRows;
1898*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(lenxadj, &xadj_g));
189941525646SFlorian Wechsung       xadj_g[0] = 0;
190041525646SFlorian Wechsung       counter = 0;
190141525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
19022953a68cSFlorian Wechsung         PetscInt        temp=0;
19032953a68cSFlorian Wechsung         const PetscInt *cols;
1904*5f80ce2aSJacob Faibussowitsch         CHKERRQ(MatGetRow(As, i, &temp, &cols, NULL));
1905*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscArraycpy(&adjncy_g[counter], cols, temp));
190641525646SFlorian Wechsung         counter += temp;
190741525646SFlorian Wechsung         xadj_g[i+1] = counter;
1908*5f80ce2aSJacob Faibussowitsch         CHKERRQ(MatRestoreRow(As, i, &temp, &cols, NULL));
190941525646SFlorian Wechsung       }
1910*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(2*numRows, &vtxwgt_g));
191141525646SFlorian Wechsung       for (i=0; i<size; i++) {
191241525646SFlorian Wechsung         vtxwgt_g[ncon*cumSumVertices[i]] = numExclusivelyOwnedAll[i];
191341525646SFlorian Wechsung         if (ncon>1) vtxwgt_g[ncon*cumSumVertices[i]+1] = 1;
191441525646SFlorian Wechsung         for (j=cumSumVertices[i]+1; j<cumSumVertices[i+1]; j++) {
191541525646SFlorian Wechsung           vtxwgt_g[ncon*j] = 1;
191641525646SFlorian Wechsung           if (ncon>1) vtxwgt_g[2*j+1] = 0;
191741525646SFlorian Wechsung         }
191841525646SFlorian Wechsung       }
1919*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(64, &options));
192041525646SFlorian Wechsung       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
1921*5f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
192241525646SFlorian Wechsung       options[METIS_OPTION_CONTIG] = 1;
192341525646SFlorian Wechsung       PetscStackPush("METIS_PartGraphKway");
192406b3913eSFlorian Wechsung       ierr = METIS_PartGraphKway(&numRows, &ncon, xadj_g, adjncy_g, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
192541525646SFlorian Wechsung       PetscStackPop;
1926*5f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
1927*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(options));
1928*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(xadj_g));
1929*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(adjncy_g));
1930*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(vtxwgt_g));
193141525646SFlorian Wechsung     }
1932*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(numExclusivelyOwnedAll));
193341525646SFlorian Wechsung 
19345dc86ac1SFlorian Wechsung     /* Now scatter the parts array. */
19355dc86ac1SFlorian Wechsung     {
193681a13b52SFlorian Wechsung       PetscMPIInt *counts, *mpiCumSumVertices;
1937*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(size, &counts));
1938*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(size+1, &mpiCumSumVertices));
19395dc86ac1SFlorian Wechsung       for (i=0; i<size; i++) {
1940*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscMPIIntCast(cumSumVertices[i+1] - cumSumVertices[i], &(counts[i])));
194141525646SFlorian Wechsung       }
194281a13b52SFlorian Wechsung       for (i=0; i<=size; i++) {
1943*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i])));
194481a13b52SFlorian Wechsung       }
1945*5f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm));
1946*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(counts));
1947*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(mpiCumSumVertices));
19485dc86ac1SFlorian Wechsung     }
19495dc86ac1SFlorian Wechsung 
1950*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(partGlobal));
1951*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&As));
195241525646SFlorian Wechsung   }
1953cb87ef4cSFlorian Wechsung 
1954*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&A));
1955*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(ubvec));
1956*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(tpwgts));
1957cb87ef4cSFlorian Wechsung 
1958cb87ef4cSFlorian Wechsung   /* Now rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
1959cb87ef4cSFlorian Wechsung 
1960*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(size, &firstVertices));
1961*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(size, &renumbering));
1962cb87ef4cSFlorian Wechsung   firstVertices[rank] = part[0];
1963*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,firstVertices,1,MPIU_INT,comm));
1964cb87ef4cSFlorian Wechsung   for (i=0; i<size; i++) {
1965cb87ef4cSFlorian Wechsung     renumbering[firstVertices[i]] = i;
1966cb87ef4cSFlorian Wechsung   }
1967cb87ef4cSFlorian Wechsung   for (i=0; i<cumSumVertices[rank+1]-cumSumVertices[rank]; i++) {
1968cb87ef4cSFlorian Wechsung     part[i] = renumbering[part[i]];
1969cb87ef4cSFlorian Wechsung   }
1970cb87ef4cSFlorian Wechsung   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
1971cb87ef4cSFlorian Wechsung   failed = (PetscInt)(part[0] != rank);
1972*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm));
1973cb87ef4cSFlorian Wechsung 
1974*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(firstVertices));
1975*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(renumbering));
19767f57c1a4SFlorian Wechsung 
1977cb87ef4cSFlorian Wechsung   if (failedGlobal > 0) {
1978*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLayoutDestroy(&layout));
1979*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(xadj));
1980*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(adjncy));
1981*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(vtxwgt));
1982*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(toBalance));
1983*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(isLeaf));
1984*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(isNonExclusivelyOwned));
1985*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(isExclusivelyOwned));
1986*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(part));
19877f57c1a4SFlorian Wechsung     if (viewer) {
1988*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerPopFormat(viewer));
1989*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerDestroy(&viewer));
19907f57c1a4SFlorian Wechsung     }
1991*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
19928b879b41SFlorian Wechsung     PetscFunctionReturn(0);
1993cb87ef4cSFlorian Wechsung   }
1994cb87ef4cSFlorian Wechsung 
19957407ba93SFlorian Wechsung   /*Let's check how well we did distributing points*/
19965dc86ac1SFlorian Wechsung   if (viewer) {
1997*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer, "Comparing number of owned entities of depth %D on each process before rebalancing, after rebalancing, and after consistency checks.\n", entityDepth));
1998*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer, "Initial.     "));
1999*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, NULL, viewer));
2000*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer, "Rebalanced.  "));
2001*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer));
20027407ba93SFlorian Wechsung   }
20037407ba93SFlorian Wechsung 
2004cb87ef4cSFlorian Wechsung   /* Now check that every vertex is owned by a process that it is actually connected to. */
200541525646SFlorian Wechsung   for (i=1; i<=numNonExclusivelyOwned; i++) {
2006cb87ef4cSFlorian Wechsung     PetscInt loc = 0;
2007*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFindInt(cumSumVertices[part[i]], xadj[i+1]-xadj[i], &adjncy[xadj[i]], &loc));
20087407ba93SFlorian Wechsung     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
2009cb87ef4cSFlorian Wechsung     if (loc<0) {
201041525646SFlorian Wechsung       part[i] = rank;
2011cb87ef4cSFlorian Wechsung     }
2012cb87ef4cSFlorian Wechsung   }
2013cb87ef4cSFlorian Wechsung 
20147407ba93SFlorian Wechsung   /* Let's see how significant the influences of the previous fixing up step was.*/
20155dc86ac1SFlorian Wechsung   if (viewer) {
2016*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer, "After.       "));
2017*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer));
20187407ba93SFlorian Wechsung   }
20197407ba93SFlorian Wechsung 
2020*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLayoutDestroy(&layout));
2021*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(xadj));
2022*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(adjncy));
2023*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(vtxwgt));
2024cb87ef4cSFlorian Wechsung 
20257f57c1a4SFlorian Wechsung   /* Almost done, now rewrite the SF to reflect the new ownership. */
2026cf818975SFlorian Wechsung   {
20277f57c1a4SFlorian Wechsung     PetscInt *pointsToRewrite;
2028*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite));
20297f57c1a4SFlorian Wechsung     counter = 0;
2030cb87ef4cSFlorian Wechsung     for (i=0; i<pEnd-pStart; i++) {
2031cb87ef4cSFlorian Wechsung       if (toBalance[i]) {
2032cb87ef4cSFlorian Wechsung         if (isNonExclusivelyOwned[i]) {
20337f57c1a4SFlorian Wechsung           pointsToRewrite[counter] = i + pStart;
2034cb87ef4cSFlorian Wechsung           counter++;
2035cb87ef4cSFlorian Wechsung         }
2036cb87ef4cSFlorian Wechsung       }
2037cb87ef4cSFlorian Wechsung     }
2038*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part+1, degrees));
2039*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(pointsToRewrite));
2040cf818975SFlorian Wechsung   }
2041cb87ef4cSFlorian Wechsung 
2042*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(toBalance));
2043*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(isLeaf));
2044*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(isNonExclusivelyOwned));
2045*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(isExclusivelyOwned));
2046*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(part));
20475dc86ac1SFlorian Wechsung   if (viewer) {
2048*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerPopFormat(viewer));
2049*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerDestroy(&viewer));
20507d197802SFlorian Wechsung   }
20518b879b41SFlorian Wechsung   if (success) *success = PETSC_TRUE;
2052*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
2053b458e8f1SJose E. Roman   PetscFunctionReturn(0);
2054240408d3SFlorian Wechsung #else
20555f441e9bSFlorian Wechsung   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
205641525646SFlorian Wechsung #endif
2057cb87ef4cSFlorian Wechsung }
2058