xref: /petsc/src/dm/impls/plex/plexpartition.c (revision b458e8f169278db94fa1d489e1d3db410fc8a4c8)
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 
50134a67bSLisandro Dalcin PETSC_STATIC_INLINE PetscInt DMPlex_GlobalID(PetscInt point) { return point >= 0 ? point : -(point+1); }
60134a67bSLisandro Dalcin 
7bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
8532c4e7dSMichael Lange {
9ffbd6163SMatthew G. Knepley   PetscInt       dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
10389e55d8SMichael Lange   PetscInt      *adj = NULL, *vOffsets = NULL, *graph = NULL;
118cfe4c1fSMichael Lange   IS             cellNumbering;
128cfe4c1fSMichael Lange   const PetscInt *cellNum;
13532c4e7dSMichael Lange   PetscBool      useCone, useClosure;
14532c4e7dSMichael Lange   PetscSection   section;
15532c4e7dSMichael Lange   PetscSegBuffer adjBuffer;
168cfe4c1fSMichael Lange   PetscSF        sfPoint;
178f4e72b9SMatthew G. Knepley   PetscInt       *adjCells = NULL, *remoteCells = NULL;
188f4e72b9SMatthew G. Knepley   const PetscInt *local;
198f4e72b9SMatthew G. Knepley   PetscInt       nroots, nleaves, l;
20532c4e7dSMichael Lange   PetscMPIInt    rank;
21532c4e7dSMichael Lange   PetscErrorCode ierr;
22532c4e7dSMichael Lange 
23532c4e7dSMichael Lange   PetscFunctionBegin;
24532c4e7dSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
25ffbd6163SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
26ffbd6163SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
27ffbd6163SMatthew G. Knepley   if (dim != depth) {
28ffbd6163SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
29ffbd6163SMatthew G. Knepley     ierr = DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);CHKERRQ(ierr);
30ffbd6163SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
31ffbd6163SMatthew G. Knepley     if (globalNumbering) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);CHKERRQ(ierr);}
32ffbd6163SMatthew G. Knepley     /* Different behavior for empty graphs */
33ffbd6163SMatthew G. Knepley     if (!*numVertices) {
34ffbd6163SMatthew G. Knepley       ierr = PetscMalloc1(1, offsets);CHKERRQ(ierr);
35ffbd6163SMatthew G. Knepley       (*offsets)[0] = 0;
36ffbd6163SMatthew G. Knepley     }
37ffbd6163SMatthew G. Knepley     /* Broken in parallel */
38ffbd6163SMatthew G. Knepley     if (rank && *numVertices) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
39ffbd6163SMatthew G. Knepley     PetscFunctionReturn(0);
40ffbd6163SMatthew G. Knepley   }
418cfe4c1fSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
420134a67bSLisandro Dalcin   ierr = DMPlexGetHeightStratum(dm, height, &pStart, &pEnd);CHKERRQ(ierr);
43532c4e7dSMichael Lange   /* Build adjacency graph via a section/segbuffer */
44532c4e7dSMichael Lange   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &section);CHKERRQ(ierr);
45532c4e7dSMichael Lange   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
46532c4e7dSMichael Lange   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&adjBuffer);CHKERRQ(ierr);
47532c4e7dSMichael Lange   /* Always use FVM adjacency to create partitioner graph */
48b0441da4SMatthew G. Knepley   ierr = DMGetBasicAdjacency(dm, &useCone, &useClosure);CHKERRQ(ierr);
49b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE);CHKERRQ(ierr);
509886b8cfSStefano Zampini   ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, sfPoint, &cellNumbering);CHKERRQ(ierr);
513fa7752dSToby Isaac   if (globalNumbering) {
523fa7752dSToby Isaac     ierr = PetscObjectReference((PetscObject)cellNumbering);CHKERRQ(ierr);
533fa7752dSToby Isaac     *globalNumbering = cellNumbering;
543fa7752dSToby Isaac   }
558cfe4c1fSMichael Lange   ierr = ISGetIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
568f4e72b9SMatthew G. Knepley   /* For all boundary faces (including faces adjacent to a ghost cell), record the local cell in adjCells
578f4e72b9SMatthew G. Knepley      Broadcast adjCells to remoteCells (to get cells from roots) and Reduce adjCells to remoteCells (to get cells from leaves)
588f4e72b9SMatthew G. Knepley    */
590134a67bSLisandro Dalcin   ierr = PetscSFGetGraph(sfPoint, &nroots, &nleaves, &local, NULL);CHKERRQ(ierr);
608f4e72b9SMatthew G. Knepley   if (nroots >= 0) {
618f4e72b9SMatthew G. Knepley     PetscInt fStart, fEnd, f;
628f4e72b9SMatthew G. Knepley 
638f4e72b9SMatthew G. Knepley     ierr = PetscCalloc2(nroots, &adjCells, nroots, &remoteCells);CHKERRQ(ierr);
640134a67bSLisandro Dalcin     ierr = DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);CHKERRQ(ierr);
658f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) adjCells[l] = -3;
668f4e72b9SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
678f4e72b9SMatthew G. Knepley       const PetscInt *support;
688f4e72b9SMatthew G. Knepley       PetscInt        supportSize;
698f4e72b9SMatthew G. Knepley 
708f4e72b9SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
718f4e72b9SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
720134a67bSLisandro Dalcin       if (supportSize == 1) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
738f4e72b9SMatthew G. Knepley       else if (supportSize == 2) {
748f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
750134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1]]);
768f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
770134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
780134a67bSLisandro Dalcin       }
790134a67bSLisandro Dalcin       /* Handle non-conforming meshes */
800134a67bSLisandro Dalcin       if (supportSize > 2) {
810134a67bSLisandro Dalcin         PetscInt        numChildren, i;
820134a67bSLisandro Dalcin         const PetscInt *children;
830134a67bSLisandro Dalcin 
840134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, f, &numChildren, &children);CHKERRQ(ierr);
850134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
860134a67bSLisandro Dalcin           const PetscInt child = children[i];
870134a67bSLisandro Dalcin           if (fStart <= child && child < fEnd) {
880134a67bSLisandro Dalcin             ierr = DMPlexGetSupport(dm, child, &support);CHKERRQ(ierr);
890134a67bSLisandro Dalcin             ierr = DMPlexGetSupportSize(dm, child, &supportSize);CHKERRQ(ierr);
900134a67bSLisandro Dalcin             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
910134a67bSLisandro Dalcin             else if (supportSize == 2) {
920134a67bSLisandro Dalcin               ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
930134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1]]);
940134a67bSLisandro Dalcin               ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
950134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
960134a67bSLisandro Dalcin             }
970134a67bSLisandro Dalcin           }
980134a67bSLisandro Dalcin         }
998f4e72b9SMatthew G. Knepley       }
1008f4e72b9SMatthew G. Knepley     }
1018f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) remoteCells[l] = -1;
1028f4e72b9SMatthew G. Knepley     ierr = PetscSFBcastBegin(dm->sf, MPIU_INT, adjCells, remoteCells);CHKERRQ(ierr);
1038f4e72b9SMatthew G. Knepley     ierr = PetscSFBcastEnd(dm->sf, MPIU_INT, adjCells, remoteCells);CHKERRQ(ierr);
1048f4e72b9SMatthew G. Knepley     ierr = PetscSFReduceBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);CHKERRQ(ierr);
1058f4e72b9SMatthew G. Knepley     ierr = PetscSFReduceEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);CHKERRQ(ierr);
1068f4e72b9SMatthew G. Knepley   }
1078f4e72b9SMatthew G. Knepley   /* Combine local and global adjacencies */
1088cfe4c1fSMichael Lange   for (*numVertices = 0, p = pStart; p < pEnd; p++) {
1098cfe4c1fSMichael Lange     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
1108cfe4c1fSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
1118f4e72b9SMatthew G. Knepley     /* Add remote cells */
1128f4e72b9SMatthew G. Knepley     if (remoteCells) {
1130134a67bSLisandro Dalcin       const PetscInt gp = DMPlex_GlobalID(cellNum[p]);
1140134a67bSLisandro Dalcin       PetscInt       coneSize, numChildren, c, i;
1150134a67bSLisandro Dalcin       const PetscInt *cone, *children;
1160134a67bSLisandro Dalcin 
1178f4e72b9SMatthew G. Knepley       ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1188f4e72b9SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1198f4e72b9SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
1200134a67bSLisandro Dalcin         const PetscInt point = cone[c];
1210134a67bSLisandro Dalcin         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
1228f4e72b9SMatthew G. Knepley           PetscInt *PETSC_RESTRICT pBuf;
1238f4e72b9SMatthew G. Knepley           ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
1248f4e72b9SMatthew G. Knepley           ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1250134a67bSLisandro Dalcin           *pBuf = remoteCells[point];
1260134a67bSLisandro Dalcin         }
1270134a67bSLisandro Dalcin         /* Handle non-conforming meshes */
1280134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, point, &numChildren, &children);CHKERRQ(ierr);
1290134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1300134a67bSLisandro Dalcin           const PetscInt child = children[i];
1310134a67bSLisandro Dalcin           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
1320134a67bSLisandro Dalcin             PetscInt *PETSC_RESTRICT pBuf;
1330134a67bSLisandro Dalcin             ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
1340134a67bSLisandro Dalcin             ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1350134a67bSLisandro Dalcin             *pBuf = remoteCells[child];
1360134a67bSLisandro Dalcin           }
1378f4e72b9SMatthew G. Knepley         }
1388f4e72b9SMatthew G. Knepley       }
1398f4e72b9SMatthew G. Knepley     }
1408f4e72b9SMatthew G. Knepley     /* Add local cells */
141532c4e7dSMichael Lange     adjSize = PETSC_DETERMINE;
142532c4e7dSMichael Lange     ierr = DMPlexGetAdjacency(dm, p, &adjSize, &adj);CHKERRQ(ierr);
143532c4e7dSMichael Lange     for (a = 0; a < adjSize; ++a) {
144532c4e7dSMichael Lange       const PetscInt point = adj[a];
145532c4e7dSMichael Lange       if (point != p && pStart <= point && point < pEnd) {
146532c4e7dSMichael Lange         PetscInt *PETSC_RESTRICT pBuf;
147532c4e7dSMichael Lange         ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
148532c4e7dSMichael Lange         ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1490134a67bSLisandro Dalcin         *pBuf = DMPlex_GlobalID(cellNum[point]);
150532c4e7dSMichael Lange       }
151532c4e7dSMichael Lange     }
1528cfe4c1fSMichael Lange     (*numVertices)++;
153532c4e7dSMichael Lange   }
1544e468a93SLisandro Dalcin   ierr = PetscFree(adj);CHKERRQ(ierr);
1558f4e72b9SMatthew G. Knepley   ierr = PetscFree2(adjCells, remoteCells);CHKERRQ(ierr);
156b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, useCone, useClosure);CHKERRQ(ierr);
1574e468a93SLisandro Dalcin 
158532c4e7dSMichael Lange   /* Derive CSR graph from section/segbuffer */
159532c4e7dSMichael Lange   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
160532c4e7dSMichael Lange   ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
161389e55d8SMichael Lange   ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
16243f7d02bSMichael Lange   for (idx = 0, p = pStart; p < pEnd; p++) {
16343f7d02bSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
16443f7d02bSMichael Lange     ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
16543f7d02bSMichael Lange   }
166532c4e7dSMichael Lange   vOffsets[*numVertices] = size;
167389e55d8SMichael Lange   ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
1684e468a93SLisandro Dalcin 
1694e468a93SLisandro Dalcin   if (nroots >= 0) {
1704e468a93SLisandro Dalcin     /* Filter out duplicate edges using section/segbuffer */
1714e468a93SLisandro Dalcin     ierr = PetscSectionReset(section);CHKERRQ(ierr);
1724e468a93SLisandro Dalcin     ierr = PetscSectionSetChart(section, 0, *numVertices);CHKERRQ(ierr);
1734e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
1744e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
1754e468a93SLisandro Dalcin       PetscInt numEdges = end-start, *PETSC_RESTRICT edges;
1764e468a93SLisandro Dalcin       ierr = PetscSortRemoveDupsInt(&numEdges, &graph[start]);CHKERRQ(ierr);
1774e468a93SLisandro Dalcin       ierr = PetscSectionSetDof(section, p, numEdges);CHKERRQ(ierr);
1784e468a93SLisandro Dalcin       ierr = PetscSegBufferGetInts(adjBuffer, numEdges, &edges);CHKERRQ(ierr);
179580bdb30SBarry Smith       ierr = PetscArraycpy(edges, &graph[start], numEdges);CHKERRQ(ierr);
1804e468a93SLisandro Dalcin     }
1814e468a93SLisandro Dalcin     ierr = PetscFree(vOffsets);CHKERRQ(ierr);
1824e468a93SLisandro Dalcin     ierr = PetscFree(graph);CHKERRQ(ierr);
1834e468a93SLisandro Dalcin     /* Derive CSR graph from section/segbuffer */
1844e468a93SLisandro Dalcin     ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
1854e468a93SLisandro Dalcin     ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
1864e468a93SLisandro Dalcin     ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
1874e468a93SLisandro Dalcin     for (idx = 0, p = 0; p < *numVertices; p++) {
1884e468a93SLisandro Dalcin       ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
1894e468a93SLisandro Dalcin     }
1904e468a93SLisandro Dalcin     vOffsets[*numVertices] = size;
1914e468a93SLisandro Dalcin     ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
1924e468a93SLisandro Dalcin   } else {
1934e468a93SLisandro Dalcin     /* Sort adjacencies (not strictly necessary) */
1944e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
1954e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
1964e468a93SLisandro Dalcin       ierr = PetscSortInt(end-start, &graph[start]);CHKERRQ(ierr);
1974e468a93SLisandro Dalcin     }
1984e468a93SLisandro Dalcin   }
1994e468a93SLisandro Dalcin 
2004e468a93SLisandro Dalcin   if (offsets) *offsets = vOffsets;
201389e55d8SMichael Lange   if (adjacency) *adjacency = graph;
2024e468a93SLisandro Dalcin 
203532c4e7dSMichael Lange   /* Cleanup */
204532c4e7dSMichael Lange   ierr = PetscSegBufferDestroy(&adjBuffer);CHKERRQ(ierr);
205532c4e7dSMichael Lange   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
2064e468a93SLisandro Dalcin   ierr = ISRestoreIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
2074e468a93SLisandro Dalcin   ierr = ISDestroy(&cellNumbering);CHKERRQ(ierr);
208532c4e7dSMichael Lange   PetscFunctionReturn(0);
209532c4e7dSMichael Lange }
210532c4e7dSMichael Lange 
211bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
212bbbc8e51SStefano Zampini {
213bbbc8e51SStefano Zampini   Mat            conn, CSR;
214bbbc8e51SStefano Zampini   IS             fis, cis, cis_own;
215bbbc8e51SStefano Zampini   PetscSF        sfPoint;
216bbbc8e51SStefano Zampini   const PetscInt *rows, *cols, *ii, *jj;
217bbbc8e51SStefano Zampini   PetscInt       *idxs,*idxs2;
21883c5d788SMatthew G. Knepley   PetscInt       dim, depth, floc, cloc, i, M, N, c, lm, m, cStart, cEnd, fStart, fEnd;
219bbbc8e51SStefano Zampini   PetscMPIInt    rank;
220bbbc8e51SStefano Zampini   PetscBool      flg;
221bbbc8e51SStefano Zampini   PetscErrorCode ierr;
222bbbc8e51SStefano Zampini 
223bbbc8e51SStefano Zampini   PetscFunctionBegin;
224bbbc8e51SStefano Zampini   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
225bbbc8e51SStefano Zampini   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
226bbbc8e51SStefano Zampini   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
227bbbc8e51SStefano Zampini   if (dim != depth) {
228bbbc8e51SStefano Zampini     /* We do not handle the uninterpolated case here */
229bbbc8e51SStefano Zampini     ierr = DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);CHKERRQ(ierr);
230bbbc8e51SStefano Zampini     /* DMPlexCreateNeighborCSR does not make a numbering */
231bbbc8e51SStefano Zampini     if (globalNumbering) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);CHKERRQ(ierr);}
232bbbc8e51SStefano Zampini     /* Different behavior for empty graphs */
233bbbc8e51SStefano Zampini     if (!*numVertices) {
234bbbc8e51SStefano Zampini       ierr = PetscMalloc1(1, offsets);CHKERRQ(ierr);
235bbbc8e51SStefano Zampini       (*offsets)[0] = 0;
236bbbc8e51SStefano Zampini     }
237bbbc8e51SStefano Zampini     /* Broken in parallel */
238bbbc8e51SStefano Zampini     if (rank && *numVertices) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
239bbbc8e51SStefano Zampini     PetscFunctionReturn(0);
240bbbc8e51SStefano Zampini   }
241bbbc8e51SStefano Zampini   /* Interpolated and parallel case */
242bbbc8e51SStefano Zampini 
243bbbc8e51SStefano Zampini   /* numbering */
244bbbc8e51SStefano Zampini   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
245bbbc8e51SStefano Zampini   ierr = DMPlexGetHeightStratum(dm, height, &cStart, &cEnd);CHKERRQ(ierr);
246bbbc8e51SStefano Zampini   ierr = DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);CHKERRQ(ierr);
2479886b8cfSStefano Zampini   ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, &N, sfPoint, &cis);CHKERRQ(ierr);
2489886b8cfSStefano Zampini   ierr = DMPlexCreateNumbering_Plex(dm, fStart, fEnd, 0, &M, sfPoint, &fis);CHKERRQ(ierr);
249bbbc8e51SStefano Zampini   if (globalNumbering) {
250bbbc8e51SStefano Zampini     ierr = ISDuplicate(cis, globalNumbering);CHKERRQ(ierr);
251bbbc8e51SStefano Zampini   }
252bbbc8e51SStefano Zampini 
253bbbc8e51SStefano Zampini   /* get positive global ids and local sizes for facets and cells */
254bbbc8e51SStefano Zampini   ierr = ISGetLocalSize(fis, &m);CHKERRQ(ierr);
255bbbc8e51SStefano Zampini   ierr = ISGetIndices(fis, &rows);CHKERRQ(ierr);
256bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs);CHKERRQ(ierr);
257bbbc8e51SStefano Zampini   for (i = 0, floc = 0; i < m; i++) {
258bbbc8e51SStefano Zampini     const PetscInt p = rows[i];
259bbbc8e51SStefano Zampini 
260bbbc8e51SStefano Zampini     if (p < 0) {
261bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
262bbbc8e51SStefano Zampini     } else {
263bbbc8e51SStefano Zampini       idxs[i] = p;
264bbbc8e51SStefano Zampini       floc   += 1;
265bbbc8e51SStefano Zampini     }
266bbbc8e51SStefano Zampini   }
267bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(fis, &rows);CHKERRQ(ierr);
268bbbc8e51SStefano Zampini   ierr = ISDestroy(&fis);CHKERRQ(ierr);
269bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr);
270bbbc8e51SStefano Zampini 
271bbbc8e51SStefano Zampini   ierr = ISGetLocalSize(cis, &m);CHKERRQ(ierr);
272bbbc8e51SStefano Zampini   ierr = ISGetIndices(cis, &cols);CHKERRQ(ierr);
273bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs);CHKERRQ(ierr);
274bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs2);CHKERRQ(ierr);
275bbbc8e51SStefano Zampini   for (i = 0, cloc = 0; i < m; i++) {
276bbbc8e51SStefano Zampini     const PetscInt p = cols[i];
277bbbc8e51SStefano Zampini 
278bbbc8e51SStefano Zampini     if (p < 0) {
279bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
280bbbc8e51SStefano Zampini     } else {
281bbbc8e51SStefano Zampini       idxs[i]       = p;
282bbbc8e51SStefano Zampini       idxs2[cloc++] = p;
283bbbc8e51SStefano Zampini     }
284bbbc8e51SStefano Zampini   }
285bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(cis, &cols);CHKERRQ(ierr);
286bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis);CHKERRQ(ierr);
287bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr);
288bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own);CHKERRQ(ierr);
289bbbc8e51SStefano Zampini 
290bbbc8e51SStefano Zampini   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
291bbbc8e51SStefano Zampini   ierr = MatCreate(PetscObjectComm((PetscObject)dm), &conn);CHKERRQ(ierr);
292bbbc8e51SStefano Zampini   ierr = MatSetSizes(conn, floc, cloc, M, N);CHKERRQ(ierr);
293bbbc8e51SStefano Zampini   ierr = MatSetType(conn, MATMPIAIJ);CHKERRQ(ierr);
29483c5d788SMatthew G. Knepley   ierr = DMPlexGetMaxSizes(dm, NULL, &lm);CHKERRQ(ierr);
29583c5d788SMatthew G. Knepley   ierr = MPI_Allreduce(&lm, &m, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
296bbbc8e51SStefano Zampini   ierr = MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL);CHKERRQ(ierr);
297bbbc8e51SStefano Zampini 
298bbbc8e51SStefano Zampini   /* Assemble matrix */
299bbbc8e51SStefano Zampini   ierr = ISGetIndices(fis, &rows);CHKERRQ(ierr);
300bbbc8e51SStefano Zampini   ierr = ISGetIndices(cis, &cols);CHKERRQ(ierr);
301bbbc8e51SStefano Zampini   for (c = cStart; c < cEnd; c++) {
302bbbc8e51SStefano Zampini     const PetscInt *cone;
303bbbc8e51SStefano Zampini     PetscInt        coneSize, row, col, f;
304bbbc8e51SStefano Zampini 
305bbbc8e51SStefano Zampini     col  = cols[c-cStart];
306bbbc8e51SStefano Zampini     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
307bbbc8e51SStefano Zampini     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
308bbbc8e51SStefano Zampini     for (f = 0; f < coneSize; f++) {
309bbbc8e51SStefano Zampini       const PetscScalar v = 1.0;
310bbbc8e51SStefano Zampini       const PetscInt *children;
311bbbc8e51SStefano Zampini       PetscInt        numChildren, ch;
312bbbc8e51SStefano Zampini 
313bbbc8e51SStefano Zampini       row  = rows[cone[f]-fStart];
314bbbc8e51SStefano Zampini       ierr = MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);CHKERRQ(ierr);
315bbbc8e51SStefano Zampini 
316bbbc8e51SStefano Zampini       /* non-conforming meshes */
317bbbc8e51SStefano Zampini       ierr = DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children);CHKERRQ(ierr);
318bbbc8e51SStefano Zampini       for (ch = 0; ch < numChildren; ch++) {
319bbbc8e51SStefano Zampini         const PetscInt child = children[ch];
320bbbc8e51SStefano Zampini 
321bbbc8e51SStefano Zampini         if (child < fStart || child >= fEnd) continue;
322bbbc8e51SStefano Zampini         row  = rows[child-fStart];
323bbbc8e51SStefano Zampini         ierr = MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);CHKERRQ(ierr);
324bbbc8e51SStefano Zampini       }
325bbbc8e51SStefano Zampini     }
326bbbc8e51SStefano Zampini   }
327bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(fis, &rows);CHKERRQ(ierr);
328bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(cis, &cols);CHKERRQ(ierr);
329bbbc8e51SStefano Zampini   ierr = ISDestroy(&fis);CHKERRQ(ierr);
330bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis);CHKERRQ(ierr);
331bbbc8e51SStefano Zampini   ierr = MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
332bbbc8e51SStefano Zampini   ierr = MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
333bbbc8e51SStefano Zampini 
334bbbc8e51SStefano Zampini   /* Get parallel CSR by doing conn^T * conn */
335bbbc8e51SStefano Zampini   ierr = MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR);CHKERRQ(ierr);
336bbbc8e51SStefano Zampini   ierr = MatDestroy(&conn);CHKERRQ(ierr);
337bbbc8e51SStefano Zampini 
338bbbc8e51SStefano Zampini   /* extract local part of the CSR */
339bbbc8e51SStefano Zampini   ierr = MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn);CHKERRQ(ierr);
340bbbc8e51SStefano Zampini   ierr = MatDestroy(&CSR);CHKERRQ(ierr);
341bbbc8e51SStefano Zampini   ierr = MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);CHKERRQ(ierr);
342bbbc8e51SStefano Zampini   if (!flg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
343bbbc8e51SStefano Zampini 
344bbbc8e51SStefano Zampini   /* get back requested output */
345bbbc8e51SStefano Zampini   if (numVertices) *numVertices = m;
346bbbc8e51SStefano Zampini   if (offsets) {
347bbbc8e51SStefano Zampini     ierr = PetscCalloc1(m+1, &idxs);CHKERRQ(ierr);
348bbbc8e51SStefano Zampini     for (i = 1; i < m+1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
349bbbc8e51SStefano Zampini     *offsets = idxs;
350bbbc8e51SStefano Zampini   }
351bbbc8e51SStefano Zampini   if (adjacency) {
352bbbc8e51SStefano Zampini     ierr = PetscMalloc1(ii[m] - m, &idxs);CHKERRQ(ierr);
353bbbc8e51SStefano Zampini     ierr = ISGetIndices(cis_own, &rows);CHKERRQ(ierr);
354bbbc8e51SStefano Zampini     for (i = 0, c = 0; i < m; i++) {
355bbbc8e51SStefano Zampini       PetscInt j, g = rows[i];
356bbbc8e51SStefano Zampini 
357bbbc8e51SStefano Zampini       for (j = ii[i]; j < ii[i+1]; j++) {
358bbbc8e51SStefano Zampini         if (jj[j] == g) continue; /* again, self-connectivity */
359bbbc8e51SStefano Zampini         idxs[c++] = jj[j];
360bbbc8e51SStefano Zampini       }
361bbbc8e51SStefano Zampini     }
362bbbc8e51SStefano Zampini     if (c != ii[m] - m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %D != %D",c,ii[m]-m);
363bbbc8e51SStefano Zampini     ierr = ISRestoreIndices(cis_own, &rows);CHKERRQ(ierr);
364bbbc8e51SStefano Zampini     *adjacency = idxs;
365bbbc8e51SStefano Zampini   }
366bbbc8e51SStefano Zampini 
367bbbc8e51SStefano Zampini   /* cleanup */
368bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis_own);CHKERRQ(ierr);
369bbbc8e51SStefano Zampini   ierr = MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);CHKERRQ(ierr);
370bbbc8e51SStefano Zampini   if (!flg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
371bbbc8e51SStefano Zampini   ierr = MatDestroy(&conn);CHKERRQ(ierr);
372bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
373bbbc8e51SStefano Zampini }
374bbbc8e51SStefano Zampini 
375bbbc8e51SStefano Zampini /*@C
376bbbc8e51SStefano Zampini   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
377bbbc8e51SStefano Zampini 
378bbbc8e51SStefano Zampini   Input Parameters:
379bbbc8e51SStefano Zampini + dm      - The mesh DM dm
380bbbc8e51SStefano Zampini - height  - Height of the strata from which to construct the graph
381bbbc8e51SStefano Zampini 
382bbbc8e51SStefano Zampini   Output Parameter:
383bbbc8e51SStefano Zampini + numVertices     - Number of vertices in the graph
384bbbc8e51SStefano Zampini . offsets         - Point offsets in the graph
385bbbc8e51SStefano Zampini . adjacency       - Point connectivity in the graph
386bbbc8e51SStefano 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.
387bbbc8e51SStefano Zampini 
388bbbc8e51SStefano Zampini   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
389bbbc8e51SStefano Zampini   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
390bbbc8e51SStefano Zampini 
391bbbc8e51SStefano Zampini   Level: developer
392bbbc8e51SStefano Zampini 
393bbbc8e51SStefano Zampini .seealso: PetscPartitionerGetType(), PetscPartitionerCreate(), DMSetAdjacency()
394bbbc8e51SStefano Zampini @*/
395bbbc8e51SStefano Zampini PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
396bbbc8e51SStefano Zampini {
397bbbc8e51SStefano Zampini   PetscErrorCode ierr;
398bbbc8e51SStefano Zampini   PetscBool      usemat = PETSC_FALSE;
399bbbc8e51SStefano Zampini 
400bbbc8e51SStefano Zampini   PetscFunctionBegin;
401bbbc8e51SStefano Zampini   ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_csr_via_mat", &usemat, NULL);CHKERRQ(ierr);
402bbbc8e51SStefano Zampini   if (usemat) {
403bbbc8e51SStefano Zampini     ierr = DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering);CHKERRQ(ierr);
404bbbc8e51SStefano Zampini   } else {
405bbbc8e51SStefano Zampini     ierr = DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering);CHKERRQ(ierr);
406bbbc8e51SStefano Zampini   }
407bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
408bbbc8e51SStefano Zampini }
409bbbc8e51SStefano Zampini 
410d5577e40SMatthew G. Knepley /*@C
411d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
412d5577e40SMatthew G. Knepley 
413fe2efc57SMark   Collective on DM
414d5577e40SMatthew G. Knepley 
415d5577e40SMatthew G. Knepley   Input Arguments:
416d5577e40SMatthew G. Knepley + dm - The DMPlex
417d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
418d5577e40SMatthew G. Knepley 
419d5577e40SMatthew G. Knepley   Output Arguments:
420d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
421d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
422d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
423d5577e40SMatthew G. Knepley 
424d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
425d5577e40SMatthew G. Knepley 
426d5577e40SMatthew G. Knepley   Level: advanced
427d5577e40SMatthew G. Knepley 
428d5577e40SMatthew G. Knepley .seealso: DMPlexCreate()
429d5577e40SMatthew G. Knepley @*/
43070034214SMatthew G. Knepley PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
43170034214SMatthew G. Knepley {
43270034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
43370034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
43470034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
43570034214SMatthew G. Knepley   PetscInt      *off, *adj;
43670034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
43770034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
43870034214SMatthew G. Knepley   PetscErrorCode ierr;
43970034214SMatthew G. Knepley 
44070034214SMatthew G. Knepley   PetscFunctionBegin;
44170034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
442c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
44370034214SMatthew G. Knepley   cellDim = dim - cellHeight;
44470034214SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
44570034214SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
44670034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
44770034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
44870034214SMatthew G. Knepley     if (offsets)   *offsets   = NULL;
44970034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
45070034214SMatthew G. Knepley     PetscFunctionReturn(0);
45170034214SMatthew G. Knepley   }
45270034214SMatthew G. Knepley   numCells  = cEnd - cStart;
45370034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
45470034214SMatthew G. Knepley   if (dim == depth) {
45570034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
45670034214SMatthew G. Knepley 
45770034214SMatthew G. Knepley     ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
45870034214SMatthew G. Knepley     /* Count neighboring cells */
45970034214SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr);
46070034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
46170034214SMatthew G. Knepley       const PetscInt *support;
46270034214SMatthew G. Knepley       PetscInt        supportSize;
46370034214SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
46470034214SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
46570034214SMatthew G. Knepley       if (supportSize == 2) {
4669ffc88e4SToby Isaac         PetscInt numChildren;
4679ffc88e4SToby Isaac 
4689ffc88e4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
4699ffc88e4SToby Isaac         if (!numChildren) {
47070034214SMatthew G. Knepley           ++off[support[0]-cStart+1];
47170034214SMatthew G. Knepley           ++off[support[1]-cStart+1];
47270034214SMatthew G. Knepley         }
47370034214SMatthew G. Knepley       }
4749ffc88e4SToby Isaac     }
47570034214SMatthew G. Knepley     /* Prefix sum */
47670034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
47770034214SMatthew G. Knepley     if (adjacency) {
47870034214SMatthew G. Knepley       PetscInt *tmp;
47970034214SMatthew G. Knepley 
48070034214SMatthew G. Knepley       ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
481854ce69bSBarry Smith       ierr = PetscMalloc1(numCells+1, &tmp);CHKERRQ(ierr);
482580bdb30SBarry Smith       ierr = PetscArraycpy(tmp, off, numCells+1);CHKERRQ(ierr);
48370034214SMatthew G. Knepley       /* Get neighboring cells */
48470034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
48570034214SMatthew G. Knepley         const PetscInt *support;
48670034214SMatthew G. Knepley         PetscInt        supportSize;
48770034214SMatthew G. Knepley         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
48870034214SMatthew G. Knepley         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
48970034214SMatthew G. Knepley         if (supportSize == 2) {
4909ffc88e4SToby Isaac           PetscInt numChildren;
4919ffc88e4SToby Isaac 
4929ffc88e4SToby Isaac           ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
4939ffc88e4SToby Isaac           if (!numChildren) {
49470034214SMatthew G. Knepley             adj[tmp[support[0]-cStart]++] = support[1];
49570034214SMatthew G. Knepley             adj[tmp[support[1]-cStart]++] = support[0];
49670034214SMatthew G. Knepley           }
49770034214SMatthew G. Knepley         }
4989ffc88e4SToby Isaac       }
49976bd3646SJed Brown       if (PetscDefined(USE_DEBUG)) {
50070034214SMatthew G. Knepley         for (c = 0; c < cEnd-cStart; ++c) if (tmp[c] != off[c+1]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Offset %d != %d for cell %d", tmp[c], off[c], c+cStart);
50176bd3646SJed Brown       }
50270034214SMatthew G. Knepley       ierr = PetscFree(tmp);CHKERRQ(ierr);
50370034214SMatthew G. Knepley     }
50470034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
50570034214SMatthew G. Knepley     if (offsets)   *offsets   = off;
50670034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
50770034214SMatthew G. Knepley     PetscFunctionReturn(0);
50870034214SMatthew G. Knepley   }
50970034214SMatthew G. Knepley   /* Setup face recognition */
51070034214SMatthew G. Knepley   if (faceDepth == 1) {
51170034214SMatthew 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 */
51270034214SMatthew G. Knepley 
51370034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
51470034214SMatthew G. Knepley       PetscInt corners;
51570034214SMatthew G. Knepley 
51670034214SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
51770034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
51870034214SMatthew G. Knepley         PetscInt nFV;
51970034214SMatthew G. Knepley 
52070034214SMatthew G. Knepley         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
52170034214SMatthew G. Knepley         cornersSeen[corners] = 1;
52270034214SMatthew G. Knepley 
52370034214SMatthew G. Knepley         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
52470034214SMatthew G. Knepley 
52570034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
52670034214SMatthew G. Knepley       }
52770034214SMatthew G. Knepley     }
52870034214SMatthew G. Knepley   }
52970034214SMatthew G. Knepley   ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
53070034214SMatthew G. Knepley   /* Count neighboring cells */
53170034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
53270034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
53370034214SMatthew G. Knepley 
5348b0b4c70SToby Isaac     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
53570034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
53670034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
53770034214SMatthew G. Knepley       PetscInt        cellPair[2];
53870034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
53970034214SMatthew G. Knepley       PetscInt        meetSize = 0;
54070034214SMatthew G. Knepley       const PetscInt *meet    = NULL;
54170034214SMatthew G. Knepley 
54270034214SMatthew G. Knepley       cellPair[0] = cell; cellPair[1] = neighborCells[n];
54370034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
54470034214SMatthew G. Knepley       if (!found) {
54570034214SMatthew G. Knepley         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
54670034214SMatthew G. Knepley         if (meetSize) {
54770034214SMatthew G. Knepley           PetscInt f;
54870034214SMatthew G. Knepley 
54970034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
55070034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
55170034214SMatthew G. Knepley               found = PETSC_TRUE;
55270034214SMatthew G. Knepley               break;
55370034214SMatthew G. Knepley             }
55470034214SMatthew G. Knepley           }
55570034214SMatthew G. Knepley         }
55670034214SMatthew G. Knepley         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
55770034214SMatthew G. Knepley       }
55870034214SMatthew G. Knepley       if (found) ++off[cell-cStart+1];
55970034214SMatthew G. Knepley     }
56070034214SMatthew G. Knepley   }
56170034214SMatthew G. Knepley   /* Prefix sum */
56270034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
56370034214SMatthew G. Knepley 
56470034214SMatthew G. Knepley   if (adjacency) {
56570034214SMatthew G. Knepley     ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
56670034214SMatthew G. Knepley     /* Get neighboring cells */
56770034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
56870034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
56970034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
57070034214SMatthew G. Knepley 
5718b0b4c70SToby Isaac       ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
57270034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
57370034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
57470034214SMatthew G. Knepley         PetscInt        cellPair[2];
57570034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
57670034214SMatthew G. Knepley         PetscInt        meetSize = 0;
57770034214SMatthew G. Knepley         const PetscInt *meet    = NULL;
57870034214SMatthew G. Knepley 
57970034214SMatthew G. Knepley         cellPair[0] = cell; cellPair[1] = neighborCells[n];
58070034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
58170034214SMatthew G. Knepley         if (!found) {
58270034214SMatthew G. Knepley           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
58370034214SMatthew G. Knepley           if (meetSize) {
58470034214SMatthew G. Knepley             PetscInt f;
58570034214SMatthew G. Knepley 
58670034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
58770034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
58870034214SMatthew G. Knepley                 found = PETSC_TRUE;
58970034214SMatthew G. Knepley                 break;
59070034214SMatthew G. Knepley               }
59170034214SMatthew G. Knepley             }
59270034214SMatthew G. Knepley           }
59370034214SMatthew G. Knepley           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
59470034214SMatthew G. Knepley         }
59570034214SMatthew G. Knepley         if (found) {
59670034214SMatthew G. Knepley           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
59770034214SMatthew G. Knepley           ++cellOffset;
59870034214SMatthew G. Knepley         }
59970034214SMatthew G. Knepley       }
60070034214SMatthew G. Knepley     }
60170034214SMatthew G. Knepley   }
60270034214SMatthew G. Knepley   ierr = PetscFree(neighborCells);CHKERRQ(ierr);
60370034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
60470034214SMatthew G. Knepley   if (offsets)   *offsets   = off;
60570034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
60670034214SMatthew G. Knepley   PetscFunctionReturn(0);
60770034214SMatthew G. Knepley }
60870034214SMatthew G. Knepley 
60977623264SMatthew G. Knepley /*@
6103c41b853SStefano Zampini   PetscPartitionerDMPlexPartition - Create a non-overlapping partition of the cells in the mesh
61177623264SMatthew G. Knepley 
612fe2efc57SMark   Collective on PetscPartitioner
61377623264SMatthew G. Knepley 
61477623264SMatthew G. Knepley   Input Parameters:
61577623264SMatthew G. Knepley + part    - The PetscPartitioner
6163c41b853SStefano Zampini . targetSection - The PetscSection describing the absolute weight of each partition (can be NULL)
617f8987ae8SMichael Lange - dm      - The mesh DM
61877623264SMatthew G. Knepley 
61977623264SMatthew G. Knepley   Output Parameters:
62077623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
621f8987ae8SMichael Lange - partition       - The list of points by partition
62277623264SMatthew G. Knepley 
6233c41b853SStefano Zampini   Notes:
6243c41b853SStefano Zampini     If the DM has a local section associated, each point to be partitioned will be weighted by the total number of dofs identified
6253c41b853SStefano Zampini     by the section in the transitive closure of the point.
62677623264SMatthew G. Knepley 
62777623264SMatthew G. Knepley   Level: developer
62877623264SMatthew G. Knepley 
6293c41b853SStefano Zampini .seealso DMPlexDistribute(), PetscPartitionerCreate(), PetscSectionCreate(), PetscSectionSetChart(), PetscPartitionerPartition()
6304b15ede2SMatthew G. Knepley @*/
6313c41b853SStefano Zampini PetscErrorCode PetscPartitionerDMPlexPartition(PetscPartitioner part, DM dm, PetscSection targetSection, PetscSection partSection, IS *partition)
63277623264SMatthew G. Knepley {
63377623264SMatthew G. Knepley   PetscMPIInt    size;
6343c41b853SStefano Zampini   PetscBool      isplex;
63577623264SMatthew G. Knepley   PetscErrorCode ierr;
6363c41b853SStefano Zampini   PetscSection   vertSection = NULL;
63777623264SMatthew G. Knepley 
63877623264SMatthew G. Knepley   PetscFunctionBegin;
63977623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
64077623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
6413c41b853SStefano Zampini   if (targetSection) PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 3);
64277623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
64377623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
6443c41b853SStefano Zampini   ierr = PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isplex);CHKERRQ(ierr);
6453c41b853SStefano Zampini   if (!isplex) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Not for type %s",((PetscObject)dm)->type_name);
64677623264SMatthew G. Knepley   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
64777623264SMatthew G. Knepley   if (size == 1) {
64877623264SMatthew G. Knepley     PetscInt *points;
64977623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
65077623264SMatthew G. Knepley 
65177623264SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
6523c41b853SStefano Zampini     ierr = PetscSectionReset(partSection);CHKERRQ(ierr);
65377623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr);
65477623264SMatthew G. Knepley     ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr);
65577623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
65677623264SMatthew G. Knepley     ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr);
65777623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
65877623264SMatthew G. Knepley     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
65977623264SMatthew G. Knepley     PetscFunctionReturn(0);
66077623264SMatthew G. Knepley   }
66177623264SMatthew G. Knepley   if (part->height == 0) {
662074d466cSStefano Zampini     PetscInt numVertices = 0;
66377623264SMatthew G. Knepley     PetscInt *start     = NULL;
66477623264SMatthew G. Knepley     PetscInt *adjacency = NULL;
6653fa7752dSToby Isaac     IS       globalNumbering;
66677623264SMatthew G. Knepley 
667074d466cSStefano Zampini     if (!part->noGraph || part->viewGraph) {
668074d466cSStefano Zampini       ierr = DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering);CHKERRQ(ierr);
66913911537SStefano Zampini     } else { /* only compute the number of owned local vertices */
670074d466cSStefano Zampini       const PetscInt *idxs;
671074d466cSStefano Zampini       PetscInt       p, pStart, pEnd;
672074d466cSStefano Zampini 
673074d466cSStefano Zampini       ierr = DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd);CHKERRQ(ierr);
6749886b8cfSStefano Zampini       ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering);CHKERRQ(ierr);
675074d466cSStefano Zampini       ierr = ISGetIndices(globalNumbering, &idxs);CHKERRQ(ierr);
676074d466cSStefano Zampini       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
677074d466cSStefano Zampini       ierr = ISRestoreIndices(globalNumbering, &idxs);CHKERRQ(ierr);
678074d466cSStefano Zampini     }
6793c41b853SStefano Zampini     if (part->usevwgt) {
6803c41b853SStefano Zampini       PetscSection   section = dm->localSection, clSection = NULL;
6813c41b853SStefano Zampini       IS             clPoints = NULL;
6823c41b853SStefano Zampini       const PetscInt *gid,*clIdx;
6833c41b853SStefano Zampini       PetscInt       v, p, pStart, pEnd;
6840358368aSMatthew G. Knepley 
6853c41b853SStefano 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) */
6863c41b853SStefano Zampini       /* We do this only if the local section has been set */
6873c41b853SStefano Zampini       if (section) {
6883c41b853SStefano Zampini         ierr = PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, NULL);CHKERRQ(ierr);
6893c41b853SStefano Zampini         if (!clSection) {
6903c41b853SStefano Zampini           ierr = DMPlexCreateClosureIndex(dm,NULL);CHKERRQ(ierr);
6913c41b853SStefano Zampini         }
6923c41b853SStefano Zampini         ierr = PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, &clPoints);CHKERRQ(ierr);
6933c41b853SStefano Zampini         ierr = ISGetIndices(clPoints,&clIdx);CHKERRQ(ierr);
6943c41b853SStefano Zampini       }
6953c41b853SStefano Zampini       ierr = DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd);CHKERRQ(ierr);
6963c41b853SStefano Zampini       ierr = PetscSectionCreate(PETSC_COMM_SELF, &vertSection);CHKERRQ(ierr);
6973c41b853SStefano Zampini       ierr = PetscSectionSetChart(vertSection, 0, numVertices);CHKERRQ(ierr);
6983c41b853SStefano Zampini       if (globalNumbering) {
6993c41b853SStefano Zampini         ierr = ISGetIndices(globalNumbering,&gid);CHKERRQ(ierr);
7003c41b853SStefano Zampini       } else gid = NULL;
7013c41b853SStefano Zampini       for (p = pStart, v = 0; p < pEnd; ++p) {
7023c41b853SStefano Zampini         PetscInt dof = 1;
7030358368aSMatthew G. Knepley 
7043c41b853SStefano Zampini         /* skip cells in the overlap */
7053c41b853SStefano Zampini         if (gid && gid[p-pStart] < 0) continue;
7063c41b853SStefano Zampini 
7073c41b853SStefano Zampini         if (section) {
7083c41b853SStefano Zampini           PetscInt cl, clSize, clOff;
7093c41b853SStefano Zampini 
7103c41b853SStefano Zampini           dof  = 0;
7113c41b853SStefano Zampini           ierr = PetscSectionGetDof(clSection, p, &clSize);CHKERRQ(ierr);
7123c41b853SStefano Zampini           ierr = PetscSectionGetOffset(clSection, p, &clOff);CHKERRQ(ierr);
7133c41b853SStefano Zampini           for (cl = 0; cl < clSize; cl+=2) {
7143c41b853SStefano Zampini             PetscInt clDof, clPoint = clIdx[clOff + cl]; /* odd indices are reserved for orientations */
7153c41b853SStefano Zampini 
7163c41b853SStefano Zampini             ierr = PetscSectionGetDof(section, clPoint, &clDof);CHKERRQ(ierr);
7173c41b853SStefano Zampini             dof += clDof;
7180358368aSMatthew G. Knepley           }
7190358368aSMatthew G. Knepley         }
7203c41b853SStefano Zampini         if (!dof) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of dofs for point %D in the local section should be positive",p);
7213c41b853SStefano Zampini         ierr = PetscSectionSetDof(vertSection, v, dof);CHKERRQ(ierr);
7223c41b853SStefano Zampini         v++;
7233c41b853SStefano Zampini       }
7243c41b853SStefano Zampini       if (globalNumbering) {
7253c41b853SStefano Zampini         ierr = ISRestoreIndices(globalNumbering,&gid);CHKERRQ(ierr);
7263c41b853SStefano Zampini       }
7273c41b853SStefano Zampini       if (clPoints) {
7283c41b853SStefano Zampini         ierr = ISRestoreIndices(clPoints,&clIdx);CHKERRQ(ierr);
7293c41b853SStefano Zampini       }
7303c41b853SStefano Zampini       ierr = PetscSectionSetUp(vertSection);CHKERRQ(ierr);
7313c41b853SStefano Zampini     }
7323c41b853SStefano Zampini     ierr = PetscPartitionerPartition(part, size, numVertices, start, adjacency, vertSection, targetSection, partSection, partition);CHKERRQ(ierr);
73377623264SMatthew G. Knepley     ierr = PetscFree(start);CHKERRQ(ierr);
73477623264SMatthew G. Knepley     ierr = PetscFree(adjacency);CHKERRQ(ierr);
7353fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
7363fa7752dSToby Isaac       const PetscInt *globalNum;
7373fa7752dSToby Isaac       const PetscInt *partIdx;
7383fa7752dSToby Isaac       PetscInt       *map, cStart, cEnd;
7393fa7752dSToby Isaac       PetscInt       *adjusted, i, localSize, offset;
7403fa7752dSToby Isaac       IS             newPartition;
7413fa7752dSToby Isaac 
7423fa7752dSToby Isaac       ierr = ISGetLocalSize(*partition,&localSize);CHKERRQ(ierr);
7433fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&adjusted);CHKERRQ(ierr);
7443fa7752dSToby Isaac       ierr = ISGetIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
7453fa7752dSToby Isaac       ierr = ISGetIndices(*partition,&partIdx);CHKERRQ(ierr);
7463fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&map);CHKERRQ(ierr);
7473fa7752dSToby Isaac       ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
7483fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
7493fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
7503fa7752dSToby Isaac       }
7513fa7752dSToby Isaac       for (i = 0; i < localSize; i++) {
7523fa7752dSToby Isaac         adjusted[i] = map[partIdx[i]];
7533fa7752dSToby Isaac       }
7543fa7752dSToby Isaac       ierr = PetscFree(map);CHKERRQ(ierr);
7553fa7752dSToby Isaac       ierr = ISRestoreIndices(*partition,&partIdx);CHKERRQ(ierr);
7563fa7752dSToby Isaac       ierr = ISRestoreIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
7573fa7752dSToby Isaac       ierr = ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition);CHKERRQ(ierr);
7583fa7752dSToby Isaac       ierr = ISDestroy(&globalNumbering);CHKERRQ(ierr);
7593fa7752dSToby Isaac       ierr = ISDestroy(partition);CHKERRQ(ierr);
7603fa7752dSToby Isaac       *partition = newPartition;
7613fa7752dSToby Isaac     }
76277623264SMatthew G. Knepley   } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height);
7633c41b853SStefano Zampini   ierr = PetscSectionDestroy(&vertSection);CHKERRQ(ierr);
76477623264SMatthew G. Knepley   PetscFunctionReturn(0);
76577623264SMatthew G. Knepley }
76677623264SMatthew G. Knepley 
7675680f57bSMatthew G. Knepley /*@
7685680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
7695680f57bSMatthew G. Knepley 
7705680f57bSMatthew G. Knepley   Not collective
7715680f57bSMatthew G. Knepley 
7725680f57bSMatthew G. Knepley   Input Parameter:
7735680f57bSMatthew G. Knepley . dm - The DM
7745680f57bSMatthew G. Knepley 
7755680f57bSMatthew G. Knepley   Output Parameter:
7765680f57bSMatthew G. Knepley . part - The PetscPartitioner
7775680f57bSMatthew G. Knepley 
7785680f57bSMatthew G. Knepley   Level: developer
7795680f57bSMatthew G. Knepley 
78098599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
78198599a47SLawrence Mitchell 
7823c41b853SStefano Zampini .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerDMPlexPartition(), PetscPartitionerCreate()
7835680f57bSMatthew G. Knepley @*/
7845680f57bSMatthew G. Knepley PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
7855680f57bSMatthew G. Knepley {
7865680f57bSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex *) dm->data;
7875680f57bSMatthew G. Knepley 
7885680f57bSMatthew G. Knepley   PetscFunctionBegin;
7895680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7905680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
7915680f57bSMatthew G. Knepley   *part = mesh->partitioner;
7925680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
7935680f57bSMatthew G. Knepley }
7945680f57bSMatthew G. Knepley 
79571bb2955SLawrence Mitchell /*@
79671bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
79771bb2955SLawrence Mitchell 
798fe2efc57SMark   logically collective on DM
79971bb2955SLawrence Mitchell 
80071bb2955SLawrence Mitchell   Input Parameters:
80171bb2955SLawrence Mitchell + dm - The DM
80271bb2955SLawrence Mitchell - part - The partitioner
80371bb2955SLawrence Mitchell 
80471bb2955SLawrence Mitchell   Level: developer
80571bb2955SLawrence Mitchell 
80671bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
80771bb2955SLawrence Mitchell 
80871bb2955SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate()
80971bb2955SLawrence Mitchell @*/
81071bb2955SLawrence Mitchell PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
81171bb2955SLawrence Mitchell {
81271bb2955SLawrence Mitchell   DM_Plex       *mesh = (DM_Plex *) dm->data;
81371bb2955SLawrence Mitchell   PetscErrorCode ierr;
81471bb2955SLawrence Mitchell 
81571bb2955SLawrence Mitchell   PetscFunctionBegin;
81671bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
81771bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
81871bb2955SLawrence Mitchell   ierr = PetscObjectReference((PetscObject)part);CHKERRQ(ierr);
81971bb2955SLawrence Mitchell   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
82071bb2955SLawrence Mitchell   mesh->partitioner = part;
82171bb2955SLawrence Mitchell   PetscFunctionReturn(0);
82271bb2955SLawrence Mitchell }
82371bb2955SLawrence Mitchell 
8248e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point)
8258e330a33SStefano Zampini {
8268e330a33SStefano Zampini   const PetscInt *cone;
8278e330a33SStefano Zampini   PetscInt       coneSize, c;
8288e330a33SStefano Zampini   PetscBool      missing;
8298e330a33SStefano Zampini   PetscErrorCode ierr;
8308e330a33SStefano Zampini 
8318e330a33SStefano Zampini   PetscFunctionBeginHot;
8328e330a33SStefano Zampini   ierr = PetscHSetIQueryAdd(ht, point, &missing);CHKERRQ(ierr);
8338e330a33SStefano Zampini   if (missing) {
8348e330a33SStefano Zampini     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
8358e330a33SStefano Zampini     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
8368e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
8378e330a33SStefano Zampini       ierr = DMPlexAddClosure_Private(dm, ht, cone[c]);CHKERRQ(ierr);
8388e330a33SStefano Zampini     }
8398e330a33SStefano Zampini   }
8408e330a33SStefano Zampini   PetscFunctionReturn(0);
8418e330a33SStefano Zampini }
8428e330a33SStefano Zampini 
8438e330a33SStefano Zampini PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
844270bba0cSToby Isaac {
845270bba0cSToby Isaac   PetscErrorCode ierr;
846270bba0cSToby Isaac 
847270bba0cSToby Isaac   PetscFunctionBegin;
8486a5a2ffdSToby Isaac   if (up) {
8496a5a2ffdSToby Isaac     PetscInt parent;
8506a5a2ffdSToby Isaac 
851270bba0cSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
8526a5a2ffdSToby Isaac     if (parent != point) {
8536a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
8546a5a2ffdSToby Isaac 
855270bba0cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
856270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
857270bba0cSToby Isaac         PetscInt cpoint = closure[2*i];
858270bba0cSToby Isaac 
859e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
8601b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
861270bba0cSToby Isaac       }
862270bba0cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
8636a5a2ffdSToby Isaac     }
8646a5a2ffdSToby Isaac   }
8656a5a2ffdSToby Isaac   if (down) {
8666a5a2ffdSToby Isaac     PetscInt numChildren;
8676a5a2ffdSToby Isaac     const PetscInt *children;
8686a5a2ffdSToby Isaac 
8696a5a2ffdSToby Isaac     ierr = DMPlexGetTreeChildren(dm,point,&numChildren,&children);CHKERRQ(ierr);
8706a5a2ffdSToby Isaac     if (numChildren) {
8716a5a2ffdSToby Isaac       PetscInt i;
8726a5a2ffdSToby Isaac 
8736a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
8746a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
8756a5a2ffdSToby Isaac 
876e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
8771b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
8786a5a2ffdSToby Isaac       }
8796a5a2ffdSToby Isaac     }
8806a5a2ffdSToby Isaac   }
881270bba0cSToby Isaac   PetscFunctionReturn(0);
882270bba0cSToby Isaac }
883270bba0cSToby Isaac 
8848e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point)
8858e330a33SStefano Zampini {
8868e330a33SStefano Zampini   PetscInt       parent;
8878e330a33SStefano Zampini   PetscErrorCode ierr;
888825f8a23SLisandro Dalcin 
8898e330a33SStefano Zampini   PetscFunctionBeginHot;
8908e330a33SStefano Zampini   ierr = DMPlexGetTreeParent(dm, point, &parent,NULL);CHKERRQ(ierr);
8918e330a33SStefano Zampini   if (point != parent) {
8928e330a33SStefano Zampini     const PetscInt *cone;
8938e330a33SStefano Zampini     PetscInt       coneSize, c;
8948e330a33SStefano Zampini 
8958e330a33SStefano Zampini     ierr = DMPlexAddClosureTree_Up_Private(dm, ht, parent);CHKERRQ(ierr);
8968e330a33SStefano Zampini     ierr = DMPlexAddClosure_Private(dm, ht, parent);CHKERRQ(ierr);
8978e330a33SStefano Zampini     ierr = DMPlexGetCone(dm, parent, &cone);CHKERRQ(ierr);
8988e330a33SStefano Zampini     ierr = DMPlexGetConeSize(dm, parent, &coneSize);CHKERRQ(ierr);
8998e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
9008e330a33SStefano Zampini       const PetscInt cp = cone[c];
9018e330a33SStefano Zampini 
9028e330a33SStefano Zampini       ierr = DMPlexAddClosureTree_Up_Private(dm, ht, cp);CHKERRQ(ierr);
9038e330a33SStefano Zampini     }
9048e330a33SStefano Zampini   }
9058e330a33SStefano Zampini   PetscFunctionReturn(0);
9068e330a33SStefano Zampini }
9078e330a33SStefano Zampini 
9088e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point)
9098e330a33SStefano Zampini {
9108e330a33SStefano Zampini   PetscInt       i, numChildren;
9118e330a33SStefano Zampini   const PetscInt *children;
9128e330a33SStefano Zampini   PetscErrorCode ierr;
9138e330a33SStefano Zampini 
9148e330a33SStefano Zampini   PetscFunctionBeginHot;
9158e330a33SStefano Zampini   ierr = DMPlexGetTreeChildren(dm, point, &numChildren, &children);CHKERRQ(ierr);
9168e330a33SStefano Zampini   for (i = 0; i < numChildren; i++) {
9178e330a33SStefano Zampini     ierr = PetscHSetIAdd(ht, children[i]);CHKERRQ(ierr);
9188e330a33SStefano Zampini   }
9198e330a33SStefano Zampini   PetscFunctionReturn(0);
9208e330a33SStefano Zampini }
9218e330a33SStefano Zampini 
9228e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point)
9238e330a33SStefano Zampini {
9248e330a33SStefano Zampini   const PetscInt *cone;
9258e330a33SStefano Zampini   PetscInt       coneSize, c;
9268e330a33SStefano Zampini   PetscErrorCode ierr;
9278e330a33SStefano Zampini 
9288e330a33SStefano Zampini   PetscFunctionBeginHot;
9298e330a33SStefano Zampini   ierr = PetscHSetIAdd(ht, point);CHKERRQ(ierr);
9308e330a33SStefano Zampini   ierr = DMPlexAddClosureTree_Up_Private(dm, ht, point);CHKERRQ(ierr);
9318e330a33SStefano Zampini   ierr = DMPlexAddClosureTree_Down_Private(dm, ht, point);CHKERRQ(ierr);
9328e330a33SStefano Zampini   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
9338e330a33SStefano Zampini   ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
9348e330a33SStefano Zampini   for (c = 0; c < coneSize; c++) {
9358e330a33SStefano Zampini     ierr = DMPlexAddClosureTree_Private(dm, ht, cone[c]);CHKERRQ(ierr);
9368e330a33SStefano Zampini   }
9378e330a33SStefano Zampini   PetscFunctionReturn(0);
9388e330a33SStefano Zampini }
9398e330a33SStefano Zampini 
9408e330a33SStefano Zampini PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS)
941825f8a23SLisandro Dalcin {
942825f8a23SLisandro Dalcin   DM_Plex         *mesh = (DM_Plex *)dm->data;
9438e330a33SStefano Zampini   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
9448e330a33SStefano Zampini   PetscInt        nelems, *elems, off = 0, p;
945825f8a23SLisandro Dalcin   PetscHSetI      ht;
946825f8a23SLisandro Dalcin   PetscErrorCode  ierr;
947825f8a23SLisandro Dalcin 
948825f8a23SLisandro Dalcin   PetscFunctionBegin;
949825f8a23SLisandro Dalcin   ierr = PetscHSetICreate(&ht);CHKERRQ(ierr);
950825f8a23SLisandro Dalcin   ierr = PetscHSetIResize(ht, numPoints*16);CHKERRQ(ierr);
9518e330a33SStefano Zampini   if (!hasTree) {
9528e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
9538e330a33SStefano Zampini       ierr = DMPlexAddClosure_Private(dm, ht, points[p]);CHKERRQ(ierr);
9548e330a33SStefano Zampini     }
9558e330a33SStefano Zampini   } else {
9568e330a33SStefano Zampini #if 1
9578e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
9588e330a33SStefano Zampini       ierr = DMPlexAddClosureTree_Private(dm, ht, points[p]);CHKERRQ(ierr);
9598e330a33SStefano Zampini     }
9608e330a33SStefano Zampini #else
9618e330a33SStefano Zampini     PetscInt  *closure = NULL, closureSize, c;
962825f8a23SLisandro Dalcin     for (p = 0; p < numPoints; ++p) {
963825f8a23SLisandro Dalcin       ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
964825f8a23SLisandro Dalcin       for (c = 0; c < closureSize*2; c += 2) {
965825f8a23SLisandro Dalcin         ierr = PetscHSetIAdd(ht, closure[c]);CHKERRQ(ierr);
966825f8a23SLisandro Dalcin         if (hasTree) {ierr = DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE);CHKERRQ(ierr);}
967825f8a23SLisandro Dalcin       }
968825f8a23SLisandro Dalcin     }
969825f8a23SLisandro Dalcin     if (closure) {ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure);CHKERRQ(ierr);}
9708e330a33SStefano Zampini #endif
9718e330a33SStefano Zampini   }
972825f8a23SLisandro Dalcin   ierr = PetscHSetIGetSize(ht, &nelems);CHKERRQ(ierr);
973825f8a23SLisandro Dalcin   ierr = PetscMalloc1(nelems, &elems);CHKERRQ(ierr);
974825f8a23SLisandro Dalcin   ierr = PetscHSetIGetElems(ht, &off, elems);CHKERRQ(ierr);
975825f8a23SLisandro Dalcin   ierr = PetscHSetIDestroy(&ht);CHKERRQ(ierr);
976825f8a23SLisandro Dalcin   ierr = PetscSortInt(nelems, elems);CHKERRQ(ierr);
977825f8a23SLisandro Dalcin   ierr = ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS);CHKERRQ(ierr);
978825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
979825f8a23SLisandro Dalcin }
980825f8a23SLisandro Dalcin 
9815abbe4feSMichael Lange /*@
9825abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
9835abbe4feSMichael Lange 
9845abbe4feSMichael Lange   Input Parameters:
9855abbe4feSMichael Lange + dm     - The DM
9865abbe4feSMichael Lange - label  - DMLabel assinging ranks to remote roots
9875abbe4feSMichael Lange 
9885abbe4feSMichael Lange   Level: developer
9895abbe4feSMichael Lange 
99030b0ce1bSStefano Zampini .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
9915abbe4feSMichael Lange @*/
9925abbe4feSMichael Lange PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
9939ffc88e4SToby Isaac {
994825f8a23SLisandro Dalcin   IS              rankIS,   pointIS, closureIS;
9955abbe4feSMichael Lange   const PetscInt *ranks,   *points;
996825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
9979ffc88e4SToby Isaac   PetscErrorCode  ierr;
9989ffc88e4SToby Isaac 
9999ffc88e4SToby Isaac   PetscFunctionBegin;
10005abbe4feSMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
10015abbe4feSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
10025abbe4feSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
10035abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
10045abbe4feSMichael Lange     const PetscInt rank = ranks[r];
10055abbe4feSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
10065abbe4feSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
10075abbe4feSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
10088e330a33SStefano Zampini     ierr = DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS);CHKERRQ(ierr);
10095abbe4feSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
10105abbe4feSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1011825f8a23SLisandro Dalcin     ierr = DMLabelSetStratumIS(label, rank, closureIS);CHKERRQ(ierr);
1012825f8a23SLisandro Dalcin     ierr = ISDestroy(&closureIS);CHKERRQ(ierr);
10139ffc88e4SToby Isaac   }
10145abbe4feSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
10155abbe4feSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
10169ffc88e4SToby Isaac   PetscFunctionReturn(0);
10179ffc88e4SToby Isaac }
10189ffc88e4SToby Isaac 
101924d039d7SMichael Lange /*@
102024d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
102124d039d7SMichael Lange 
102224d039d7SMichael Lange   Input Parameters:
102324d039d7SMichael Lange + dm     - The DM
102424d039d7SMichael Lange - label  - DMLabel assinging ranks to remote roots
102524d039d7SMichael Lange 
102624d039d7SMichael Lange   Level: developer
102724d039d7SMichael Lange 
10282d4ee042Sprj- .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
102924d039d7SMichael Lange @*/
103024d039d7SMichael Lange PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
103170034214SMatthew G. Knepley {
103224d039d7SMichael Lange   IS              rankIS,   pointIS;
103324d039d7SMichael Lange   const PetscInt *ranks,   *points;
103424d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
103524d039d7SMichael Lange   PetscInt       *adj = NULL;
103670034214SMatthew G. Knepley   PetscErrorCode  ierr;
103770034214SMatthew G. Knepley 
103870034214SMatthew G. Knepley   PetscFunctionBegin;
103924d039d7SMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
104024d039d7SMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
104124d039d7SMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
104224d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
104324d039d7SMichael Lange     const PetscInt rank = ranks[r];
104470034214SMatthew G. Knepley 
104524d039d7SMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
104624d039d7SMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
104724d039d7SMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
104870034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
104924d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
105024d039d7SMichael Lange       ierr = DMPlexGetAdjacency(dm, points[p], &adjSize, &adj);CHKERRQ(ierr);
105124d039d7SMichael Lange       for (a = 0; a < adjSize; ++a) {ierr = DMLabelSetValue(label, adj[a], rank);CHKERRQ(ierr);}
105270034214SMatthew G. Knepley     }
105324d039d7SMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
105424d039d7SMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
105570034214SMatthew G. Knepley   }
105624d039d7SMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
105724d039d7SMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
105824d039d7SMichael Lange   ierr = PetscFree(adj);CHKERRQ(ierr);
105924d039d7SMichael Lange   PetscFunctionReturn(0);
106070034214SMatthew G. Knepley }
106170034214SMatthew G. Knepley 
1062be200f8dSMichael Lange /*@
1063be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
1064be200f8dSMichael Lange 
1065be200f8dSMichael Lange   Input Parameters:
1066be200f8dSMichael Lange + dm     - The DM
1067be200f8dSMichael Lange - label  - DMLabel assinging ranks to remote roots
1068be200f8dSMichael Lange 
1069be200f8dSMichael Lange   Level: developer
1070be200f8dSMichael Lange 
1071be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
1072be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
1073be200f8dSMichael Lange 
10742d4ee042Sprj- .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
1075be200f8dSMichael Lange @*/
1076be200f8dSMichael Lange PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
1077be200f8dSMichael Lange {
1078be200f8dSMichael Lange   MPI_Comm        comm;
1079be200f8dSMichael Lange   PetscMPIInt     rank;
1080be200f8dSMichael Lange   PetscSF         sfPoint;
10815d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
1082be200f8dSMichael Lange   IS              rankIS, pointIS;
1083be200f8dSMichael Lange   const PetscInt *ranks;
1084be200f8dSMichael Lange   PetscInt        numRanks, r;
1085be200f8dSMichael Lange   PetscErrorCode  ierr;
1086be200f8dSMichael Lange 
1087be200f8dSMichael Lange   PetscFunctionBegin;
1088be200f8dSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
1089be200f8dSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1090be200f8dSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
10915d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
10925d04f6ebSMichael Lange   ierr = DMLabelGather(label, sfPoint, &lblLeaves);CHKERRQ(ierr);
10935d04f6ebSMichael Lange   ierr = DMLabelGetValueIS(lblLeaves, &rankIS);CHKERRQ(ierr);
10945d04f6ebSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
10955d04f6ebSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
10965d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
10975d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
10985d04f6ebSMichael Lange     if (remoteRank == rank) continue;
10995d04f6ebSMichael Lange     ierr = DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS);CHKERRQ(ierr);
11005d04f6ebSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
11015d04f6ebSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
11025d04f6ebSMichael Lange   }
11035d04f6ebSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
11045d04f6ebSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
11055d04f6ebSMichael Lange   ierr = DMLabelDestroy(&lblLeaves);CHKERRQ(ierr);
1106be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
1107be200f8dSMichael Lange   ierr = DMLabelDistribute(label, sfPoint, &lblRoots);CHKERRQ(ierr);
1108be200f8dSMichael Lange   ierr = DMLabelGetValueIS(lblRoots, &rankIS);CHKERRQ(ierr);
1109be200f8dSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
1110be200f8dSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
1111be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
1112be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
1113be200f8dSMichael Lange     if (remoteRank == rank) continue;
1114be200f8dSMichael Lange     ierr = DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS);CHKERRQ(ierr);
1115be200f8dSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
1116be200f8dSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1117be200f8dSMichael Lange   }
1118be200f8dSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
1119be200f8dSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
1120be200f8dSMichael Lange   ierr = DMLabelDestroy(&lblRoots);CHKERRQ(ierr);
1121be200f8dSMichael Lange   PetscFunctionReturn(0);
1122be200f8dSMichael Lange }
1123be200f8dSMichael Lange 
11241fd9873aSMichael Lange /*@
11251fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
11261fd9873aSMichael Lange 
11271fd9873aSMichael Lange   Input Parameters:
11281fd9873aSMichael Lange + dm        - The DM
11291fd9873aSMichael Lange . rootLabel - DMLabel assinging ranks to local roots
1130fe2efc57SMark - processSF - A star forest mapping into the local index on each remote rank
11311fd9873aSMichael Lange 
11321fd9873aSMichael Lange   Output Parameter:
1133fe2efc57SMark . leafLabel - DMLabel assinging ranks to remote roots
11341fd9873aSMichael Lange 
11351fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
11361fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
11371fd9873aSMichael Lange 
11381fd9873aSMichael Lange   Level: developer
11391fd9873aSMichael Lange 
11402d4ee042Sprj- .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
11411fd9873aSMichael Lange @*/
11421fd9873aSMichael Lange PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
11431fd9873aSMichael Lange {
11441fd9873aSMichael Lange   MPI_Comm           comm;
1145874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
1146874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
11471fd9873aSMichael Lange   PetscSF            sfPoint;
1148874ddda9SLisandro Dalcin   PetscSection       rootSection;
11491fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
11501fd9873aSMichael Lange   const PetscSFNode *remote;
11511fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
11521fd9873aSMichael Lange   IS                 valueIS;
1153874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
11541fd9873aSMichael Lange   PetscErrorCode     ierr;
11551fd9873aSMichael Lange 
11561fd9873aSMichael Lange   PetscFunctionBegin;
115730b0ce1bSStefano Zampini   ierr = PetscLogEventBegin(DMPLEX_PartLabelInvert,dm,0,0,0);CHKERRQ(ierr);
11581fd9873aSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
11591fd9873aSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
11609852e123SBarry Smith   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
11611fd9873aSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
11621fd9873aSMichael Lange 
11631fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
11641fd9873aSMichael Lange   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
11659852e123SBarry Smith   ierr = PetscSectionSetChart(rootSection, 0, size);CHKERRQ(ierr);
11661fd9873aSMichael Lange   ierr = DMLabelGetValueIS(rootLabel, &valueIS);CHKERRQ(ierr);
11671fd9873aSMichael Lange   ierr = ISGetLocalSize(valueIS, &numNeighbors);CHKERRQ(ierr);
11681fd9873aSMichael Lange   ierr = ISGetIndices(valueIS, &neighbors);CHKERRQ(ierr);
11691fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
11701fd9873aSMichael Lange     ierr = DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints);CHKERRQ(ierr);
11711fd9873aSMichael Lange     ierr = PetscSectionAddDof(rootSection, neighbors[n], numPoints);CHKERRQ(ierr);
11721fd9873aSMichael Lange   }
11731fd9873aSMichael Lange   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
1174874ddda9SLisandro Dalcin   ierr = PetscSectionGetStorageSize(rootSection, &rootSize);CHKERRQ(ierr);
1175874ddda9SLisandro Dalcin   ierr = PetscMalloc1(rootSize, &rootPoints);CHKERRQ(ierr);
11761fd9873aSMichael Lange   ierr = PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote);CHKERRQ(ierr);
11771fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
11781fd9873aSMichael Lange     IS              pointIS;
11791fd9873aSMichael Lange     const PetscInt *points;
11801fd9873aSMichael Lange 
11811fd9873aSMichael Lange     ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
11821fd9873aSMichael Lange     ierr = DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS);CHKERRQ(ierr);
11831fd9873aSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
11841fd9873aSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
11851fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
1186f8987ae8SMichael Lange       if (local) {ierr = PetscFindInt(points[p], nleaves, local, &l);CHKERRQ(ierr);}
1187f8987ae8SMichael Lange       else       {l = -1;}
11881fd9873aSMichael Lange       if (l >= 0) {rootPoints[off+p] = remote[l];}
11891fd9873aSMichael Lange       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
11901fd9873aSMichael Lange     }
11911fd9873aSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
11921fd9873aSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
11931fd9873aSMichael Lange   }
1194874ddda9SLisandro Dalcin 
1195874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
1196874ddda9SLisandro Dalcin   if (!processSF) {
1197874ddda9SLisandro Dalcin     PetscInt64  counter = 0;
1198874ddda9SLisandro Dalcin     PetscBool   locOverflow = PETSC_FALSE;
1199874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
1200874ddda9SLisandro Dalcin 
1201874ddda9SLisandro Dalcin     ierr = PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls);CHKERRQ(ierr);
1202874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
1203874ddda9SLisandro Dalcin       ierr = PetscSectionGetDof(rootSection, neighbors[n], &dof);CHKERRQ(ierr);
1204874ddda9SLisandro Dalcin       ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
1205874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
1206874ddda9SLisandro Dalcin       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
1207874ddda9SLisandro Dalcin       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
1208874ddda9SLisandro Dalcin #endif
1209874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt) dof;
1210874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt) off;
1211874ddda9SLisandro Dalcin     }
1212874ddda9SLisandro Dalcin     ierr = MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm);CHKERRQ(ierr);
1213874ddda9SLisandro Dalcin     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
1214874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
1215874ddda9SLisandro Dalcin     ierr = MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm);CHKERRQ(ierr);
1216874ddda9SLisandro Dalcin     if (!mpiOverflow) {
121794b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using Alltoallv for mesh distribution\n");CHKERRQ(ierr);
1218874ddda9SLisandro Dalcin       leafSize = (PetscInt) counter;
1219874ddda9SLisandro Dalcin       ierr = PetscMalloc1(leafSize, &leafPoints);CHKERRQ(ierr);
1220874ddda9SLisandro Dalcin       ierr = MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm);CHKERRQ(ierr);
1221874ddda9SLisandro Dalcin     }
1222874ddda9SLisandro Dalcin     ierr = PetscFree4(scounts, sdispls, rcounts, rdispls);CHKERRQ(ierr);
1223874ddda9SLisandro Dalcin   }
1224874ddda9SLisandro Dalcin 
1225874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
1226874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
1227874ddda9SLisandro Dalcin     PetscSF      procSF;
1228874ddda9SLisandro Dalcin     PetscSection leafSection;
1229874ddda9SLisandro Dalcin 
1230874ddda9SLisandro Dalcin     if (processSF) {
123194b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using processSF for mesh distribution\n");CHKERRQ(ierr);
1232874ddda9SLisandro Dalcin       ierr = PetscObjectReference((PetscObject)processSF);CHKERRQ(ierr);
1233874ddda9SLisandro Dalcin       procSF = processSF;
1234874ddda9SLisandro Dalcin     } else {
123594b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using processSF for mesh distribution (MPI overflow)\n");CHKERRQ(ierr);
1236874ddda9SLisandro Dalcin       ierr = PetscSFCreate(comm,&procSF);CHKERRQ(ierr);
1237900e0f05SJunchao Zhang       ierr = PetscSFSetGraphWithPattern(procSF,NULL,PETSCSF_PATTERN_ALLTOALL);CHKERRQ(ierr);
1238874ddda9SLisandro Dalcin     }
1239874ddda9SLisandro Dalcin 
1240874ddda9SLisandro Dalcin     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection);CHKERRQ(ierr);
1241900e0f05SJunchao Zhang     ierr = DMPlexDistributeData(dm, procSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints);CHKERRQ(ierr);
1242874ddda9SLisandro Dalcin     ierr = PetscSectionGetStorageSize(leafSection, &leafSize);CHKERRQ(ierr);
1243874ddda9SLisandro Dalcin     ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
1244874ddda9SLisandro Dalcin     ierr = PetscSFDestroy(&procSF);CHKERRQ(ierr);
1245874ddda9SLisandro Dalcin   }
1246874ddda9SLisandro Dalcin 
1247874ddda9SLisandro Dalcin   for (p = 0; p < leafSize; p++) {
12481fd9873aSMichael Lange     ierr = DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank);CHKERRQ(ierr);
12491fd9873aSMichael Lange   }
1250874ddda9SLisandro Dalcin 
1251874ddda9SLisandro Dalcin   ierr = ISRestoreIndices(valueIS, &neighbors);CHKERRQ(ierr);
1252874ddda9SLisandro Dalcin   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
12531fd9873aSMichael Lange   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
1254874ddda9SLisandro Dalcin   ierr = PetscFree(rootPoints);CHKERRQ(ierr);
12551fd9873aSMichael Lange   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
125630b0ce1bSStefano Zampini   ierr = PetscLogEventEnd(DMPLEX_PartLabelInvert,dm,0,0,0);CHKERRQ(ierr);
12571fd9873aSMichael Lange   PetscFunctionReturn(0);
12581fd9873aSMichael Lange }
12591fd9873aSMichael Lange 
1260aa3148a8SMichael Lange /*@
1261aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
1262aa3148a8SMichael Lange 
1263aa3148a8SMichael Lange   Input Parameters:
1264aa3148a8SMichael Lange + dm    - The DM
1265f0fc11ceSJed Brown - label - DMLabel assinging ranks to remote roots
1266aa3148a8SMichael Lange 
1267aa3148a8SMichael Lange   Output Parameter:
1268fe2efc57SMark . sf    - The star forest communication context encapsulating the defined mapping
1269aa3148a8SMichael Lange 
1270aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
1271aa3148a8SMichael Lange 
1272aa3148a8SMichael Lange   Level: developer
1273aa3148a8SMichael Lange 
127430b0ce1bSStefano Zampini .seealso: DMPlexDistribute(), DMPlexCreateOverlap()
1275aa3148a8SMichael Lange @*/
1276aa3148a8SMichael Lange PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
1277aa3148a8SMichael Lange {
12786e203dd9SStefano Zampini   PetscMPIInt     rank;
12796e203dd9SStefano Zampini   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
1280aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
12816e203dd9SStefano Zampini   IS              remoteRootIS, neighborsIS;
12826e203dd9SStefano Zampini   const PetscInt *remoteRoots, *neighbors;
1283aa3148a8SMichael Lange   PetscErrorCode ierr;
1284aa3148a8SMichael Lange 
1285aa3148a8SMichael Lange   PetscFunctionBegin;
128630b0ce1bSStefano Zampini   ierr = PetscLogEventBegin(DMPLEX_PartLabelCreateSF,dm,0,0,0);CHKERRQ(ierr);
128743f7d02bSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
1288aa3148a8SMichael Lange 
12896e203dd9SStefano Zampini   ierr = DMLabelGetValueIS(label, &neighborsIS);CHKERRQ(ierr);
12906e203dd9SStefano Zampini #if 0
12916e203dd9SStefano Zampini   {
12926e203dd9SStefano Zampini     IS is;
12936e203dd9SStefano Zampini     ierr = ISDuplicate(neighborsIS, &is);CHKERRQ(ierr);
12946e203dd9SStefano Zampini     ierr = ISSort(is);CHKERRQ(ierr);
12956e203dd9SStefano Zampini     ierr = ISDestroy(&neighborsIS);CHKERRQ(ierr);
12966e203dd9SStefano Zampini     neighborsIS = is;
12976e203dd9SStefano Zampini   }
12986e203dd9SStefano Zampini #endif
12996e203dd9SStefano Zampini   ierr = ISGetLocalSize(neighborsIS, &nNeighbors);CHKERRQ(ierr);
13006e203dd9SStefano Zampini   ierr = ISGetIndices(neighborsIS, &neighbors);CHKERRQ(ierr);
13016e203dd9SStefano Zampini   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
13026e203dd9SStefano Zampini     ierr = DMLabelGetStratumSize(label, neighbors[n], &numPoints);CHKERRQ(ierr);
1303aa3148a8SMichael Lange     numRemote += numPoints;
1304aa3148a8SMichael Lange   }
1305aa3148a8SMichael Lange   ierr = PetscMalloc1(numRemote, &remotePoints);CHKERRQ(ierr);
130643f7d02bSMichael Lange   /* Put owned points first */
130743f7d02bSMichael Lange   ierr = DMLabelGetStratumSize(label, rank, &numPoints);CHKERRQ(ierr);
130843f7d02bSMichael Lange   if (numPoints > 0) {
130943f7d02bSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &remoteRootIS);CHKERRQ(ierr);
131043f7d02bSMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
131143f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
131243f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
131343f7d02bSMichael Lange       remotePoints[idx].rank = rank;
131443f7d02bSMichael Lange       idx++;
131543f7d02bSMichael Lange     }
131643f7d02bSMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
131743f7d02bSMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
131843f7d02bSMichael Lange   }
131943f7d02bSMichael Lange   /* Now add remote points */
13206e203dd9SStefano Zampini   for (n = 0; n < nNeighbors; ++n) {
13216e203dd9SStefano Zampini     const PetscInt nn = neighbors[n];
13226e203dd9SStefano Zampini 
13236e203dd9SStefano Zampini     ierr = DMLabelGetStratumSize(label, nn, &numPoints);CHKERRQ(ierr);
13246e203dd9SStefano Zampini     if (nn == rank || numPoints <= 0) continue;
13256e203dd9SStefano Zampini     ierr = DMLabelGetStratumIS(label, nn, &remoteRootIS);CHKERRQ(ierr);
1326aa3148a8SMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
1327aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
1328aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
13296e203dd9SStefano Zampini       remotePoints[idx].rank = nn;
1330aa3148a8SMichael Lange       idx++;
1331aa3148a8SMichael Lange     }
1332aa3148a8SMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
1333aa3148a8SMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
1334aa3148a8SMichael Lange   }
1335aa3148a8SMichael Lange   ierr = PetscSFCreate(PetscObjectComm((PetscObject) dm), sf);CHKERRQ(ierr);
1336aa3148a8SMichael Lange   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1337aa3148a8SMichael Lange   ierr = PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
133830b0ce1bSStefano Zampini   ierr = PetscSFSetUp(*sf);CHKERRQ(ierr);
13396e203dd9SStefano Zampini   ierr = ISDestroy(&neighborsIS);CHKERRQ(ierr);
134030b0ce1bSStefano Zampini   ierr = PetscLogEventEnd(DMPLEX_PartLabelCreateSF,dm,0,0,0);CHKERRQ(ierr);
134170034214SMatthew G. Knepley   PetscFunctionReturn(0);
134270034214SMatthew G. Knepley }
1343cb87ef4cSFlorian Wechsung 
1344abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PARMETIS)
1345abe9303eSLisandro Dalcin #include <parmetis.h>
1346abe9303eSLisandro Dalcin #endif
1347abe9303eSLisandro Dalcin 
13486a3739e5SFlorian Wechsung /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
13496a3739e5SFlorian Wechsung  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
13506a3739e5SFlorian Wechsung  * them out in that case. */
13516a3739e5SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
13527a82c785SFlorian Wechsung /*@C
13537f57c1a4SFlorian Wechsung 
13547f57c1a4SFlorian Wechsung   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).
13557f57c1a4SFlorian Wechsung 
13567f57c1a4SFlorian Wechsung   Input parameters:
13577f57c1a4SFlorian Wechsung + dm                - The DMPlex object.
1358fe2efc57SMark . n                 - The number of points.
1359fe2efc57SMark . pointsToRewrite   - The points in the SF whose ownership will change.
1360fe2efc57SMark . targetOwners      - New owner for each element in pointsToRewrite.
1361fe2efc57SMark - degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.
13627f57c1a4SFlorian Wechsung 
13637f57c1a4SFlorian Wechsung   Level: developer
13647f57c1a4SFlorian Wechsung 
13657f57c1a4SFlorian Wechsung @*/
13667f57c1a4SFlorian Wechsung static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
13677f57c1a4SFlorian Wechsung {
13687f57c1a4SFlorian Wechsung   PetscInt      ierr, pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
13697f57c1a4SFlorian Wechsung   PetscInt     *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
13707f57c1a4SFlorian Wechsung   PetscSFNode  *leafLocationsNew;
13717f57c1a4SFlorian Wechsung   const         PetscSFNode *iremote;
13727f57c1a4SFlorian Wechsung   const         PetscInt *ilocal;
13737f57c1a4SFlorian Wechsung   PetscBool    *isLeaf;
13747f57c1a4SFlorian Wechsung   PetscSF       sf;
13757f57c1a4SFlorian Wechsung   MPI_Comm      comm;
13765a30b08bSFlorian Wechsung   PetscMPIInt   rank, size;
13777f57c1a4SFlorian Wechsung 
13787f57c1a4SFlorian Wechsung   PetscFunctionBegin;
13797f57c1a4SFlorian Wechsung   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
13807f57c1a4SFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
13817f57c1a4SFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
13827f57c1a4SFlorian Wechsung   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
13837f57c1a4SFlorian Wechsung 
13847f57c1a4SFlorian Wechsung   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
13857f57c1a4SFlorian Wechsung   ierr = PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote);CHKERRQ(ierr);
13867f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isLeaf);CHKERRQ(ierr);
13877f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
13887f57c1a4SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
13897f57c1a4SFlorian Wechsung   }
13907f57c1a4SFlorian Wechsung   for (i=0; i<nleafs; i++) {
13917f57c1a4SFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
13927f57c1a4SFlorian Wechsung   }
13937f57c1a4SFlorian Wechsung 
13947f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart+1, &cumSumDegrees);CHKERRQ(ierr);
13957f57c1a4SFlorian Wechsung   cumSumDegrees[0] = 0;
13967f57c1a4SFlorian Wechsung   for (i=1; i<=pEnd-pStart; i++) {
13977f57c1a4SFlorian Wechsung     cumSumDegrees[i] = cumSumDegrees[i-1] + degrees[i-1];
13987f57c1a4SFlorian Wechsung   }
13997f57c1a4SFlorian Wechsung   sumDegrees = cumSumDegrees[pEnd-pStart];
14007f57c1a4SFlorian Wechsung   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
14017f57c1a4SFlorian Wechsung 
14027f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(sumDegrees, &locationsOfLeafs);CHKERRQ(ierr);
14037f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &rankOnLeafs);CHKERRQ(ierr);
14047f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
14057f57c1a4SFlorian Wechsung     rankOnLeafs[i] = rank;
14067f57c1a4SFlorian Wechsung   }
14077f57c1a4SFlorian Wechsung   ierr = PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);CHKERRQ(ierr);
14087f57c1a4SFlorian Wechsung   ierr = PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);CHKERRQ(ierr);
14097f57c1a4SFlorian Wechsung   ierr = PetscFree(rankOnLeafs);CHKERRQ(ierr);
14107f57c1a4SFlorian Wechsung 
14117f57c1a4SFlorian Wechsung   /* get the remote local points of my leaves */
14127f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs);CHKERRQ(ierr);
14137f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &points);CHKERRQ(ierr);
14147f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
14157f57c1a4SFlorian Wechsung     points[i] = pStart+i;
14167f57c1a4SFlorian Wechsung   }
14177f57c1a4SFlorian Wechsung   ierr = PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs);CHKERRQ(ierr);
14187f57c1a4SFlorian Wechsung   ierr = PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs);CHKERRQ(ierr);
14197f57c1a4SFlorian Wechsung   ierr = PetscFree(points);CHKERRQ(ierr);
14207f57c1a4SFlorian Wechsung   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
14217f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &newOwners);CHKERRQ(ierr);
14227f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &newNumbers);CHKERRQ(ierr);
14237f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
14247f57c1a4SFlorian Wechsung     newOwners[i] = -1;
14257f57c1a4SFlorian Wechsung     newNumbers[i] = -1;
14267f57c1a4SFlorian Wechsung   }
14277f57c1a4SFlorian Wechsung   {
14287f57c1a4SFlorian Wechsung     PetscInt oldNumber, newNumber, oldOwner, newOwner;
14297f57c1a4SFlorian Wechsung     for (i=0; i<n; i++) {
14307f57c1a4SFlorian Wechsung       oldNumber = pointsToRewrite[i];
14317f57c1a4SFlorian Wechsung       newNumber = -1;
14327f57c1a4SFlorian Wechsung       oldOwner = rank;
14337f57c1a4SFlorian Wechsung       newOwner = targetOwners[i];
14347f57c1a4SFlorian Wechsung       if (oldOwner == newOwner) {
14357f57c1a4SFlorian Wechsung         newNumber = oldNumber;
14367f57c1a4SFlorian Wechsung       } else {
14377f57c1a4SFlorian Wechsung         for (j=0; j<degrees[oldNumber]; j++) {
14387f57c1a4SFlorian Wechsung           if (locationsOfLeafs[cumSumDegrees[oldNumber]+j] == newOwner) {
14397f57c1a4SFlorian Wechsung             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber]+j];
14407f57c1a4SFlorian Wechsung             break;
14417f57c1a4SFlorian Wechsung           }
14427f57c1a4SFlorian Wechsung         }
14437f57c1a4SFlorian Wechsung       }
14447f57c1a4SFlorian Wechsung       if (newNumber == -1) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
14457f57c1a4SFlorian Wechsung 
14467f57c1a4SFlorian Wechsung       newOwners[oldNumber] = newOwner;
14477f57c1a4SFlorian Wechsung       newNumbers[oldNumber] = newNumber;
14487f57c1a4SFlorian Wechsung     }
14497f57c1a4SFlorian Wechsung   }
14507f57c1a4SFlorian Wechsung   ierr = PetscFree(cumSumDegrees);CHKERRQ(ierr);
14517f57c1a4SFlorian Wechsung   ierr = PetscFree(locationsOfLeafs);CHKERRQ(ierr);
14527f57c1a4SFlorian Wechsung   ierr = PetscFree(remoteLocalPointOfLeafs);CHKERRQ(ierr);
14537f57c1a4SFlorian Wechsung 
14547f57c1a4SFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners);CHKERRQ(ierr);
14557f57c1a4SFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners);CHKERRQ(ierr);
14567f57c1a4SFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers);CHKERRQ(ierr);
14577f57c1a4SFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers);CHKERRQ(ierr);
14587f57c1a4SFlorian Wechsung 
14597f57c1a4SFlorian Wechsung   /* Now count how many leafs we have on each processor. */
14607f57c1a4SFlorian Wechsung   leafCounter=0;
14617f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
14627f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
14637f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
14647f57c1a4SFlorian Wechsung         leafCounter++;
14657f57c1a4SFlorian Wechsung       }
14667f57c1a4SFlorian Wechsung     } else {
14677f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
14687f57c1a4SFlorian Wechsung         leafCounter++;
14697f57c1a4SFlorian Wechsung       }
14707f57c1a4SFlorian Wechsung     }
14717f57c1a4SFlorian Wechsung   }
14727f57c1a4SFlorian Wechsung 
14737f57c1a4SFlorian Wechsung   /* Now set up the new sf by creating the leaf arrays */
14747f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(leafCounter, &leafsNew);CHKERRQ(ierr);
14757f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(leafCounter, &leafLocationsNew);CHKERRQ(ierr);
14767f57c1a4SFlorian Wechsung 
14777f57c1a4SFlorian Wechsung   leafCounter = 0;
14787f57c1a4SFlorian Wechsung   counter = 0;
14797f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
14807f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
14817f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
14827f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
14837f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = newOwners[i];
14847f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = newNumbers[i];
14857f57c1a4SFlorian Wechsung         leafCounter++;
14867f57c1a4SFlorian Wechsung       }
14877f57c1a4SFlorian Wechsung     } else {
14887f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
14897f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
14907f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = iremote[counter].rank;
14917f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = iremote[counter].index;
14927f57c1a4SFlorian Wechsung         leafCounter++;
14937f57c1a4SFlorian Wechsung       }
14947f57c1a4SFlorian Wechsung     }
14957f57c1a4SFlorian Wechsung     if (isLeaf[i]) {
14967f57c1a4SFlorian Wechsung       counter++;
14977f57c1a4SFlorian Wechsung     }
14987f57c1a4SFlorian Wechsung   }
14997f57c1a4SFlorian Wechsung 
15007f57c1a4SFlorian Wechsung   ierr = PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
15017f57c1a4SFlorian Wechsung   ierr = PetscFree(newOwners);CHKERRQ(ierr);
15027f57c1a4SFlorian Wechsung   ierr = PetscFree(newNumbers);CHKERRQ(ierr);
15037f57c1a4SFlorian Wechsung   ierr = PetscFree(isLeaf);CHKERRQ(ierr);
15047f57c1a4SFlorian Wechsung   PetscFunctionReturn(0);
15057f57c1a4SFlorian Wechsung }
15067f57c1a4SFlorian Wechsung 
1507125d2a8fSFlorian Wechsung static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
1508125d2a8fSFlorian Wechsung {
15095a30b08bSFlorian Wechsung   PetscInt *distribution, min, max, sum, i, ierr;
15105a30b08bSFlorian Wechsung   PetscMPIInt rank, size;
1511125d2a8fSFlorian Wechsung   PetscFunctionBegin;
1512125d2a8fSFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
1513125d2a8fSFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1514125d2a8fSFlorian Wechsung   ierr = PetscCalloc1(size, &distribution);CHKERRQ(ierr);
1515125d2a8fSFlorian Wechsung   for (i=0; i<n; i++) {
1516125d2a8fSFlorian Wechsung     if (part) distribution[part[i]] += vtxwgt[skip*i];
1517125d2a8fSFlorian Wechsung     else distribution[rank] += vtxwgt[skip*i];
1518125d2a8fSFlorian Wechsung   }
1519125d2a8fSFlorian Wechsung   ierr = MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
1520125d2a8fSFlorian Wechsung   min = distribution[0];
1521125d2a8fSFlorian Wechsung   max = distribution[0];
1522125d2a8fSFlorian Wechsung   sum = distribution[0];
1523125d2a8fSFlorian Wechsung   for (i=1; i<size; i++) {
1524125d2a8fSFlorian Wechsung     if (distribution[i]<min) min=distribution[i];
1525125d2a8fSFlorian Wechsung     if (distribution[i]>max) max=distribution[i];
1526125d2a8fSFlorian Wechsung     sum += distribution[i];
1527125d2a8fSFlorian Wechsung   }
1528125d2a8fSFlorian Wechsung   ierr = PetscViewerASCIIPrintf(viewer, "Min: %D, Avg: %D, Max: %D, Balance: %f\n", min, sum/size, max, (max*1.*size)/sum);CHKERRQ(ierr);
1529125d2a8fSFlorian Wechsung   ierr = PetscFree(distribution);CHKERRQ(ierr);
1530125d2a8fSFlorian Wechsung   PetscFunctionReturn(0);
1531125d2a8fSFlorian Wechsung }
1532125d2a8fSFlorian Wechsung 
15336a3739e5SFlorian Wechsung #endif
15346a3739e5SFlorian Wechsung 
1535cb87ef4cSFlorian Wechsung /*@
15365dc86ac1SFlorian 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.
1537cb87ef4cSFlorian Wechsung 
1538cb87ef4cSFlorian Wechsung   Input parameters:
1539ed44d270SFlorian Wechsung + dm               - The DMPlex object.
1540fe2efc57SMark . entityDepth      - depth of the entity to balance (0 -> balance vertices).
1541fe2efc57SMark . useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
1542fe2efc57SMark - parallel         - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.
1543cb87ef4cSFlorian Wechsung 
15448b879b41SFlorian Wechsung   Output parameters:
1545fe2efc57SMark . success          - whether the graph partitioning was successful or not. If not, try useInitialGuess=True and parallel=True.
15468b879b41SFlorian Wechsung 
154790ea27d8SSatish Balay   Level: intermediate
1548cb87ef4cSFlorian Wechsung 
1549cb87ef4cSFlorian Wechsung @*/
1550cb87ef4cSFlorian Wechsung 
15518b879b41SFlorian Wechsung PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
1552cb87ef4cSFlorian Wechsung {
155341525646SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
1554cb87ef4cSFlorian Wechsung   PetscSF     sf;
15550faf6628SFlorian Wechsung   PetscInt    ierr, i, j, idx, jdx;
15567f57c1a4SFlorian Wechsung   PetscInt    eBegin, eEnd, nroots, nleafs, pStart, pEnd;
15577f57c1a4SFlorian Wechsung   const       PetscInt *degrees, *ilocal;
15587f57c1a4SFlorian Wechsung   const       PetscSFNode *iremote;
1559cb87ef4cSFlorian Wechsung   PetscBool   *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
1560cf818975SFlorian Wechsung   PetscInt    numExclusivelyOwned, numNonExclusivelyOwned;
1561cb87ef4cSFlorian Wechsung   PetscMPIInt rank, size;
15627f57c1a4SFlorian Wechsung   PetscInt    *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
15635dc86ac1SFlorian Wechsung   const       PetscInt *cumSumVertices;
1564cb87ef4cSFlorian Wechsung   PetscInt    offset, counter;
15657f57c1a4SFlorian Wechsung   PetscInt    lenadjncy;
1566cb87ef4cSFlorian Wechsung   PetscInt    *xadj, *adjncy, *vtxwgt;
1567cb87ef4cSFlorian Wechsung   PetscInt    lenxadj;
1568cb87ef4cSFlorian Wechsung   PetscInt    *adjwgt = NULL;
1569cb87ef4cSFlorian Wechsung   PetscInt    *part, *options;
1570cf818975SFlorian Wechsung   PetscInt    nparts, wgtflag, numflag, ncon, edgecut;
1571cb87ef4cSFlorian Wechsung   real_t      *ubvec;
1572cb87ef4cSFlorian Wechsung   PetscInt    *firstVertices, *renumbering;
1573cb87ef4cSFlorian Wechsung   PetscInt    failed, failedGlobal;
1574cb87ef4cSFlorian Wechsung   MPI_Comm    comm;
15754baf1206SFlorian Wechsung   Mat         A, Apre;
157612617df9SFlorian Wechsung   const char *prefix = NULL;
15777d197802SFlorian Wechsung   PetscViewer       viewer;
15787d197802SFlorian Wechsung   PetscViewerFormat format;
15795a30b08bSFlorian Wechsung   PetscLayout layout;
158012617df9SFlorian Wechsung 
158112617df9SFlorian Wechsung   PetscFunctionBegin;
15828b879b41SFlorian Wechsung   if (success) *success = PETSC_FALSE;
15837f57c1a4SFlorian Wechsung   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
15847f57c1a4SFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
15857f57c1a4SFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
15867f57c1a4SFlorian Wechsung   if (size==1) PetscFunctionReturn(0);
15877f57c1a4SFlorian Wechsung 
158841525646SFlorian Wechsung   ierr = PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
158941525646SFlorian Wechsung 
15905a30b08bSFlorian Wechsung   ierr = PetscOptionsGetViewer(comm,((PetscObject)dm)->options, prefix,"-dm_rebalance_partition_view",&viewer,&format,NULL);CHKERRQ(ierr);
15915dc86ac1SFlorian Wechsung   if (viewer) {
15925a30b08bSFlorian Wechsung     ierr = PetscViewerPushFormat(viewer,format);CHKERRQ(ierr);
15937d197802SFlorian Wechsung   }
15947d197802SFlorian Wechsung 
1595ed44d270SFlorian Wechsung   /* Figure out all points in the plex that we are interested in balancing. */
1596d5528e35SFlorian Wechsung   ierr = DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd);CHKERRQ(ierr);
1597cb87ef4cSFlorian Wechsung   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1598cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &toBalance);CHKERRQ(ierr);
1599cf818975SFlorian Wechsung 
1600cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
16015a7e692eSFlorian Wechsung     toBalance[i] = (PetscBool)(i-pStart>=eBegin && i-pStart<eEnd);
1602cb87ef4cSFlorian Wechsung   }
1603cb87ef4cSFlorian Wechsung 
1604cf818975SFlorian Wechsung   /* There are three types of points:
1605cf818975SFlorian Wechsung    * exclusivelyOwned: points that are owned by this process and only seen by this process
1606cf818975SFlorian Wechsung    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
1607cf818975SFlorian Wechsung    * leaf: a point that is seen by this process but owned by a different process
1608cf818975SFlorian Wechsung    */
1609cb87ef4cSFlorian Wechsung   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
1610cb87ef4cSFlorian Wechsung   ierr = PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote);CHKERRQ(ierr);
1611cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isLeaf);CHKERRQ(ierr);
1612cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isNonExclusivelyOwned);CHKERRQ(ierr);
1613cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isExclusivelyOwned);CHKERRQ(ierr);
1614cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
1615cb87ef4cSFlorian Wechsung     isNonExclusivelyOwned[i] = PETSC_FALSE;
1616cb87ef4cSFlorian Wechsung     isExclusivelyOwned[i] = PETSC_FALSE;
1617cf818975SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
1618cb87ef4cSFlorian Wechsung   }
1619cf818975SFlorian Wechsung 
1620cf818975SFlorian Wechsung   /* start by marking all the leafs */
1621cb87ef4cSFlorian Wechsung   for (i=0; i<nleafs; i++) {
1622cb87ef4cSFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
1623cb87ef4cSFlorian Wechsung   }
1624cb87ef4cSFlorian Wechsung 
1625cf818975SFlorian Wechsung   /* for an owned point, we can figure out whether another processor sees it or
1626cf818975SFlorian Wechsung    * not by calculating its degree */
16277f57c1a4SFlorian Wechsung   ierr = PetscSFComputeDegreeBegin(sf, &degrees);CHKERRQ(ierr);
16287f57c1a4SFlorian Wechsung   ierr = PetscSFComputeDegreeEnd(sf, &degrees);CHKERRQ(ierr);
1629cf818975SFlorian Wechsung 
1630cb87ef4cSFlorian Wechsung   numExclusivelyOwned = 0;
1631cb87ef4cSFlorian Wechsung   numNonExclusivelyOwned = 0;
1632cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
1633cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
16347f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1635cb87ef4cSFlorian Wechsung         isNonExclusivelyOwned[i] = PETSC_TRUE;
1636cb87ef4cSFlorian Wechsung         numNonExclusivelyOwned += 1;
1637cb87ef4cSFlorian Wechsung       } else {
1638cb87ef4cSFlorian Wechsung         if (!isLeaf[i]) {
1639cb87ef4cSFlorian Wechsung           isExclusivelyOwned[i] = PETSC_TRUE;
1640cb87ef4cSFlorian Wechsung           numExclusivelyOwned += 1;
1641cb87ef4cSFlorian Wechsung         }
1642cb87ef4cSFlorian Wechsung       }
1643cb87ef4cSFlorian Wechsung     }
1644cb87ef4cSFlorian Wechsung   }
1645cb87ef4cSFlorian Wechsung 
1646cf818975SFlorian Wechsung   /* We are going to build a graph with one vertex per core representing the
1647cf818975SFlorian Wechsung    * exclusively owned points and then one vertex per nonExclusively owned
1648cf818975SFlorian Wechsung    * point. */
1649cb87ef4cSFlorian Wechsung 
16505dc86ac1SFlorian Wechsung   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
16515dc86ac1SFlorian Wechsung   ierr = PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned);CHKERRQ(ierr);
16525dc86ac1SFlorian Wechsung   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
16535dc86ac1SFlorian Wechsung   ierr = PetscLayoutGetRanges(layout, &cumSumVertices);CHKERRQ(ierr);
16545dc86ac1SFlorian Wechsung 
1655cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &globalNumbersOfLocalOwnedVertices);CHKERRQ(ierr);
16565a427404SJunchao Zhang   for (i=0; i<pEnd-pStart; i++) {globalNumbersOfLocalOwnedVertices[i] = pStart - 1;}
1657cb87ef4cSFlorian Wechsung   offset = cumSumVertices[rank];
1658cb87ef4cSFlorian Wechsung   counter = 0;
1659cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
1660cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
16617f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1662cb87ef4cSFlorian Wechsung         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
1663cb87ef4cSFlorian Wechsung         counter++;
1664cb87ef4cSFlorian Wechsung       }
1665cb87ef4cSFlorian Wechsung     }
1666cb87ef4cSFlorian Wechsung   }
1667cb87ef4cSFlorian Wechsung 
1668cb87ef4cSFlorian Wechsung   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
1669cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &leafGlobalNumbers);CHKERRQ(ierr);
1670cb87ef4cSFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers);CHKERRQ(ierr);
1671cb87ef4cSFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers);CHKERRQ(ierr);
1672cb87ef4cSFlorian Wechsung 
16730faf6628SFlorian Wechsung   /* Now start building the data structure for ParMETIS */
1674cb87ef4cSFlorian Wechsung 
16754baf1206SFlorian Wechsung   ierr = MatCreate(comm, &Apre);CHKERRQ(ierr);
16764baf1206SFlorian Wechsung   ierr = MatSetType(Apre, MATPREALLOCATOR);CHKERRQ(ierr);
16774baf1206SFlorian Wechsung   ierr = MatSetSizes(Apre, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);CHKERRQ(ierr);
16784baf1206SFlorian Wechsung   ierr = MatSetUp(Apre);CHKERRQ(ierr);
16798c9a1619SFlorian Wechsung 
16808c9a1619SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
16818c9a1619SFlorian Wechsung     if (toBalance[i]) {
16820faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
16830faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
16840faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
16850faf6628SFlorian Wechsung       else continue;
16860faf6628SFlorian Wechsung       ierr = MatSetValue(Apre, idx, jdx, 1, INSERT_VALUES);CHKERRQ(ierr);
16870faf6628SFlorian Wechsung       ierr = MatSetValue(Apre, jdx, idx, 1, INSERT_VALUES);CHKERRQ(ierr);
16884baf1206SFlorian Wechsung     }
16894baf1206SFlorian Wechsung   }
16904baf1206SFlorian Wechsung 
16914baf1206SFlorian Wechsung   ierr = MatAssemblyBegin(Apre, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
16924baf1206SFlorian Wechsung   ierr = MatAssemblyEnd(Apre, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
16934baf1206SFlorian Wechsung 
16944baf1206SFlorian Wechsung   ierr = MatCreate(comm, &A);CHKERRQ(ierr);
16954baf1206SFlorian Wechsung   ierr = MatSetType(A, MATMPIAIJ);CHKERRQ(ierr);
16964baf1206SFlorian Wechsung   ierr = MatSetSizes(A, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);CHKERRQ(ierr);
16974baf1206SFlorian Wechsung   ierr = MatPreallocatorPreallocate(Apre, PETSC_FALSE, A);CHKERRQ(ierr);
16984baf1206SFlorian Wechsung   ierr = MatDestroy(&Apre);CHKERRQ(ierr);
16994baf1206SFlorian Wechsung 
17004baf1206SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
17014baf1206SFlorian Wechsung     if (toBalance[i]) {
17020faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
17030faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
17040faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
17050faf6628SFlorian Wechsung       else continue;
17060faf6628SFlorian Wechsung       ierr = MatSetValue(A, idx, jdx, 1, INSERT_VALUES);CHKERRQ(ierr);
17070faf6628SFlorian Wechsung       ierr = MatSetValue(A, jdx, idx, 1, INSERT_VALUES);CHKERRQ(ierr);
17080941debbSFlorian Wechsung     }
17090941debbSFlorian Wechsung   }
17108c9a1619SFlorian Wechsung 
17118c9a1619SFlorian Wechsung   ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
17128c9a1619SFlorian Wechsung   ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
17134baf1206SFlorian Wechsung   ierr = PetscFree(leafGlobalNumbers);CHKERRQ(ierr);
17144baf1206SFlorian Wechsung   ierr = PetscFree(globalNumbersOfLocalOwnedVertices);CHKERRQ(ierr);
17154baf1206SFlorian Wechsung 
171641525646SFlorian Wechsung   nparts = size;
171741525646SFlorian Wechsung   wgtflag = 2;
171841525646SFlorian Wechsung   numflag = 0;
171941525646SFlorian Wechsung   ncon = 2;
172041525646SFlorian Wechsung   real_t *tpwgts;
172141525646SFlorian Wechsung   ierr = PetscMalloc1(ncon * nparts, &tpwgts);CHKERRQ(ierr);
172241525646SFlorian Wechsung   for (i=0; i<ncon*nparts; i++) {
172341525646SFlorian Wechsung     tpwgts[i] = 1./(nparts);
172441525646SFlorian Wechsung   }
172541525646SFlorian Wechsung 
172641525646SFlorian Wechsung   ierr = PetscMalloc1(ncon, &ubvec);CHKERRQ(ierr);
172741525646SFlorian Wechsung   ubvec[0] = 1.01;
17285a30b08bSFlorian Wechsung   ubvec[1] = 1.01;
17298c9a1619SFlorian Wechsung   lenadjncy = 0;
17308c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
17318c9a1619SFlorian Wechsung     PetscInt temp=0;
17328c9a1619SFlorian Wechsung     ierr = MatGetRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);CHKERRQ(ierr);
17338c9a1619SFlorian Wechsung     lenadjncy += temp;
17348c9a1619SFlorian Wechsung     ierr = MatRestoreRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);CHKERRQ(ierr);
17358c9a1619SFlorian Wechsung   }
17368c9a1619SFlorian Wechsung   ierr = PetscMalloc1(lenadjncy, &adjncy);CHKERRQ(ierr);
17377407ba93SFlorian Wechsung   lenxadj = 2 + numNonExclusivelyOwned;
17380941debbSFlorian Wechsung   ierr = PetscMalloc1(lenxadj, &xadj);CHKERRQ(ierr);
17390941debbSFlorian Wechsung   xadj[0] = 0;
17408c9a1619SFlorian Wechsung   counter = 0;
17418c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
17422953a68cSFlorian Wechsung     PetscInt        temp=0;
17432953a68cSFlorian Wechsung     const PetscInt *cols;
17448c9a1619SFlorian Wechsung     ierr = MatGetRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);CHKERRQ(ierr);
1745580bdb30SBarry Smith     ierr = PetscArraycpy(&adjncy[counter], cols, temp);CHKERRQ(ierr);
17468c9a1619SFlorian Wechsung     counter += temp;
17470941debbSFlorian Wechsung     xadj[i+1] = counter;
17488c9a1619SFlorian Wechsung     ierr = MatRestoreRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);CHKERRQ(ierr);
17498c9a1619SFlorian Wechsung   }
17508c9a1619SFlorian Wechsung 
1751cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(cumSumVertices[rank+1]-cumSumVertices[rank], &part);CHKERRQ(ierr);
175241525646SFlorian Wechsung   ierr = PetscMalloc1(ncon*(1 + numNonExclusivelyOwned), &vtxwgt);CHKERRQ(ierr);
175341525646SFlorian Wechsung   vtxwgt[0] = numExclusivelyOwned;
175441525646SFlorian Wechsung   if (ncon>1) vtxwgt[1] = 1;
175541525646SFlorian Wechsung   for (i=0; i<numNonExclusivelyOwned; i++) {
175641525646SFlorian Wechsung     vtxwgt[ncon*(i+1)] = 1;
175741525646SFlorian Wechsung     if (ncon>1) vtxwgt[ncon*(i+1)+1] = 0;
175841525646SFlorian Wechsung   }
17598c9a1619SFlorian Wechsung 
17605dc86ac1SFlorian Wechsung   if (viewer) {
17617d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %D on interface of mesh distribution.\n", entityDepth);CHKERRQ(ierr);
17627d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %D\n", cumSumVertices[size]);CHKERRQ(ierr);
176312617df9SFlorian Wechsung   }
176441525646SFlorian Wechsung   if (parallel) {
17655a30b08bSFlorian Wechsung     ierr = PetscMalloc1(4, &options);CHKERRQ(ierr);
17665a30b08bSFlorian Wechsung     options[0] = 1;
17675a30b08bSFlorian Wechsung     options[1] = 0; /* Verbosity */
17685a30b08bSFlorian Wechsung     options[2] = 0; /* Seed */
17695a30b08bSFlorian Wechsung     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
17705dc86ac1SFlorian Wechsung     if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n");CHKERRQ(ierr); }
17718c9a1619SFlorian Wechsung     if (useInitialGuess) {
17725dc86ac1SFlorian Wechsung       if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n");CHKERRQ(ierr); }
17738c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_RefineKway");
17745dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_RefineKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
177506b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
17768c9a1619SFlorian Wechsung       PetscStackPop;
17778c9a1619SFlorian Wechsung     } else {
17788c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_PartKway");
17795dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_PartKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
17808c9a1619SFlorian Wechsung       PetscStackPop;
178106b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
17828c9a1619SFlorian Wechsung     }
1783ef74bcceSFlorian Wechsung     ierr = PetscFree(options);CHKERRQ(ierr);
178441525646SFlorian Wechsung   } else {
17855dc86ac1SFlorian Wechsung     if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n");CHKERRQ(ierr); }
178641525646SFlorian Wechsung     Mat As;
178741525646SFlorian Wechsung     PetscInt numRows;
178841525646SFlorian Wechsung     PetscInt *partGlobal;
178941525646SFlorian Wechsung     ierr = MatCreateRedundantMatrix(A, size, MPI_COMM_NULL, MAT_INITIAL_MATRIX, &As);CHKERRQ(ierr);
1790cb87ef4cSFlorian Wechsung 
179141525646SFlorian Wechsung     PetscInt *numExclusivelyOwnedAll;
179241525646SFlorian Wechsung     ierr = PetscMalloc1(size, &numExclusivelyOwnedAll);CHKERRQ(ierr);
179341525646SFlorian Wechsung     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
17942953a68cSFlorian Wechsung     ierr = MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,numExclusivelyOwnedAll,1,MPIU_INT,comm);CHKERRQ(ierr);
1795cb87ef4cSFlorian Wechsung 
179641525646SFlorian Wechsung     ierr = MatGetSize(As, &numRows, NULL);CHKERRQ(ierr);
179741525646SFlorian Wechsung     ierr = PetscMalloc1(numRows, &partGlobal);CHKERRQ(ierr);
17985dc86ac1SFlorian Wechsung     if (!rank) {
179941525646SFlorian Wechsung       PetscInt *adjncy_g, *xadj_g, *vtxwgt_g;
180041525646SFlorian Wechsung       lenadjncy = 0;
180141525646SFlorian Wechsung 
180241525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
180341525646SFlorian Wechsung         PetscInt temp=0;
180441525646SFlorian Wechsung         ierr = MatGetRow(As, i, &temp, NULL, NULL);CHKERRQ(ierr);
180541525646SFlorian Wechsung         lenadjncy += temp;
180641525646SFlorian Wechsung         ierr = MatRestoreRow(As, i, &temp, NULL, NULL);CHKERRQ(ierr);
180741525646SFlorian Wechsung       }
180841525646SFlorian Wechsung       ierr = PetscMalloc1(lenadjncy, &adjncy_g);CHKERRQ(ierr);
180941525646SFlorian Wechsung       lenxadj = 1 + numRows;
181041525646SFlorian Wechsung       ierr = PetscMalloc1(lenxadj, &xadj_g);CHKERRQ(ierr);
181141525646SFlorian Wechsung       xadj_g[0] = 0;
181241525646SFlorian Wechsung       counter = 0;
181341525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
18142953a68cSFlorian Wechsung         PetscInt        temp=0;
18152953a68cSFlorian Wechsung         const PetscInt *cols;
181641525646SFlorian Wechsung         ierr = MatGetRow(As, i, &temp, &cols, NULL);CHKERRQ(ierr);
1817580bdb30SBarry Smith         ierr = PetscArraycpy(&adjncy_g[counter], cols, temp);CHKERRQ(ierr);
181841525646SFlorian Wechsung         counter += temp;
181941525646SFlorian Wechsung         xadj_g[i+1] = counter;
182041525646SFlorian Wechsung         ierr = MatRestoreRow(As, i, &temp, &cols, NULL);CHKERRQ(ierr);
182141525646SFlorian Wechsung       }
182241525646SFlorian Wechsung       ierr = PetscMalloc1(2*numRows, &vtxwgt_g);CHKERRQ(ierr);
182341525646SFlorian Wechsung       for (i=0; i<size; i++){
182441525646SFlorian Wechsung         vtxwgt_g[ncon*cumSumVertices[i]] = numExclusivelyOwnedAll[i];
182541525646SFlorian Wechsung         if (ncon>1) vtxwgt_g[ncon*cumSumVertices[i]+1] = 1;
182641525646SFlorian Wechsung         for (j=cumSumVertices[i]+1; j<cumSumVertices[i+1]; j++) {
182741525646SFlorian Wechsung           vtxwgt_g[ncon*j] = 1;
182841525646SFlorian Wechsung           if (ncon>1) vtxwgt_g[2*j+1] = 0;
182941525646SFlorian Wechsung         }
183041525646SFlorian Wechsung       }
183141525646SFlorian Wechsung       ierr = PetscMalloc1(64, &options);CHKERRQ(ierr);
183241525646SFlorian Wechsung       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
183306b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
183441525646SFlorian Wechsung       options[METIS_OPTION_CONTIG] = 1;
183541525646SFlorian Wechsung       PetscStackPush("METIS_PartGraphKway");
183606b3913eSFlorian Wechsung       ierr = METIS_PartGraphKway(&numRows, &ncon, xadj_g, adjncy_g, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
183741525646SFlorian Wechsung       PetscStackPop;
183806b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
1839ef74bcceSFlorian Wechsung       ierr = PetscFree(options);CHKERRQ(ierr);
184041525646SFlorian Wechsung       ierr = PetscFree(xadj_g);CHKERRQ(ierr);
184141525646SFlorian Wechsung       ierr = PetscFree(adjncy_g);CHKERRQ(ierr);
184241525646SFlorian Wechsung       ierr = PetscFree(vtxwgt_g);CHKERRQ(ierr);
184341525646SFlorian Wechsung     }
184441525646SFlorian Wechsung     ierr = PetscFree(numExclusivelyOwnedAll);CHKERRQ(ierr);
184541525646SFlorian Wechsung 
18465dc86ac1SFlorian Wechsung     /* Now scatter the parts array. */
18475dc86ac1SFlorian Wechsung     {
184881a13b52SFlorian Wechsung       PetscMPIInt *counts, *mpiCumSumVertices;
18495dc86ac1SFlorian Wechsung       ierr = PetscMalloc1(size, &counts);CHKERRQ(ierr);
185081a13b52SFlorian Wechsung       ierr = PetscMalloc1(size+1, &mpiCumSumVertices);CHKERRQ(ierr);
18515dc86ac1SFlorian Wechsung       for (i=0; i<size; i++) {
185281a13b52SFlorian Wechsung         ierr = PetscMPIIntCast(cumSumVertices[i+1] - cumSumVertices[i], &(counts[i]));CHKERRQ(ierr);
185341525646SFlorian Wechsung       }
185481a13b52SFlorian Wechsung       for (i=0; i<=size; i++) {
185581a13b52SFlorian Wechsung         ierr = PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i]));CHKERRQ(ierr);
185681a13b52SFlorian Wechsung       }
185781a13b52SFlorian Wechsung       ierr = MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm);CHKERRQ(ierr);
18585dc86ac1SFlorian Wechsung       ierr = PetscFree(counts);CHKERRQ(ierr);
185981a13b52SFlorian Wechsung       ierr = PetscFree(mpiCumSumVertices);CHKERRQ(ierr);
18605dc86ac1SFlorian Wechsung     }
18615dc86ac1SFlorian Wechsung 
186241525646SFlorian Wechsung     ierr = PetscFree(partGlobal);CHKERRQ(ierr);
18632953a68cSFlorian Wechsung     ierr = MatDestroy(&As);CHKERRQ(ierr);
186441525646SFlorian Wechsung   }
1865cb87ef4cSFlorian Wechsung 
18662953a68cSFlorian Wechsung   ierr = MatDestroy(&A);CHKERRQ(ierr);
1867cb87ef4cSFlorian Wechsung   ierr = PetscFree(ubvec);CHKERRQ(ierr);
1868cb87ef4cSFlorian Wechsung   ierr = PetscFree(tpwgts);CHKERRQ(ierr);
1869cb87ef4cSFlorian Wechsung 
1870cb87ef4cSFlorian Wechsung   /* Now rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
1871cb87ef4cSFlorian Wechsung 
1872cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(size, &firstVertices);CHKERRQ(ierr);
1873cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(size, &renumbering);CHKERRQ(ierr);
1874cb87ef4cSFlorian Wechsung   firstVertices[rank] = part[0];
18752953a68cSFlorian Wechsung   ierr = MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,firstVertices,1,MPIU_INT,comm);CHKERRQ(ierr);
1876cb87ef4cSFlorian Wechsung   for (i=0; i<size; i++) {
1877cb87ef4cSFlorian Wechsung     renumbering[firstVertices[i]] = i;
1878cb87ef4cSFlorian Wechsung   }
1879cb87ef4cSFlorian Wechsung   for (i=0; i<cumSumVertices[rank+1]-cumSumVertices[rank]; i++) {
1880cb87ef4cSFlorian Wechsung     part[i] = renumbering[part[i]];
1881cb87ef4cSFlorian Wechsung   }
1882cb87ef4cSFlorian Wechsung   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
1883cb87ef4cSFlorian Wechsung   failed = (PetscInt)(part[0] != rank);
18842953a68cSFlorian Wechsung   ierr = MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
1885cb87ef4cSFlorian Wechsung 
18867f57c1a4SFlorian Wechsung   ierr = PetscFree(firstVertices);CHKERRQ(ierr);
18877f57c1a4SFlorian Wechsung   ierr = PetscFree(renumbering);CHKERRQ(ierr);
18887f57c1a4SFlorian Wechsung 
1889cb87ef4cSFlorian Wechsung   if (failedGlobal > 0) {
18907f57c1a4SFlorian Wechsung     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
18917f57c1a4SFlorian Wechsung     ierr = PetscFree(xadj);CHKERRQ(ierr);
18927f57c1a4SFlorian Wechsung     ierr = PetscFree(adjncy);CHKERRQ(ierr);
18937f57c1a4SFlorian Wechsung     ierr = PetscFree(vtxwgt);CHKERRQ(ierr);
18947f57c1a4SFlorian Wechsung     ierr = PetscFree(toBalance);CHKERRQ(ierr);
18957f57c1a4SFlorian Wechsung     ierr = PetscFree(isLeaf);CHKERRQ(ierr);
18967f57c1a4SFlorian Wechsung     ierr = PetscFree(isNonExclusivelyOwned);CHKERRQ(ierr);
18977f57c1a4SFlorian Wechsung     ierr = PetscFree(isExclusivelyOwned);CHKERRQ(ierr);
18987f57c1a4SFlorian Wechsung     ierr = PetscFree(part);CHKERRQ(ierr);
18997f57c1a4SFlorian Wechsung     if (viewer) {
190006b3913eSFlorian Wechsung       ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
190106b3913eSFlorian Wechsung       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
19027f57c1a4SFlorian Wechsung     }
19037f57c1a4SFlorian Wechsung     ierr = PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
19048b879b41SFlorian Wechsung     PetscFunctionReturn(0);
1905cb87ef4cSFlorian Wechsung   }
1906cb87ef4cSFlorian Wechsung 
19077407ba93SFlorian Wechsung   /*Let's check how well we did distributing points*/
19085dc86ac1SFlorian Wechsung   if (viewer) {
19097d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Comparing number of owned entities of depth %D on each process before rebalancing, after rebalancing, and after consistency checks.\n", entityDepth);CHKERRQ(ierr);
1910125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Initial.     ");CHKERRQ(ierr);
1911125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, NULL, viewer);CHKERRQ(ierr);
1912125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Rebalanced.  ");CHKERRQ(ierr);
1913125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);CHKERRQ(ierr);
19147407ba93SFlorian Wechsung   }
19157407ba93SFlorian Wechsung 
1916cb87ef4cSFlorian Wechsung   /* Now check that every vertex is owned by a process that it is actually connected to. */
191741525646SFlorian Wechsung   for (i=1; i<=numNonExclusivelyOwned; i++) {
1918cb87ef4cSFlorian Wechsung     PetscInt loc = 0;
191941525646SFlorian Wechsung     ierr = PetscFindInt(cumSumVertices[part[i]], xadj[i+1]-xadj[i], &adjncy[xadj[i]], &loc);CHKERRQ(ierr);
19207407ba93SFlorian Wechsung     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
1921cb87ef4cSFlorian Wechsung     if (loc<0) {
192241525646SFlorian Wechsung       part[i] = rank;
1923cb87ef4cSFlorian Wechsung     }
1924cb87ef4cSFlorian Wechsung   }
1925cb87ef4cSFlorian Wechsung 
19267407ba93SFlorian Wechsung   /* Let's see how significant the influences of the previous fixing up step was.*/
19275dc86ac1SFlorian Wechsung   if (viewer) {
1928125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "After.       ");CHKERRQ(ierr);
1929125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);CHKERRQ(ierr);
19307407ba93SFlorian Wechsung   }
19317407ba93SFlorian Wechsung 
19325dc86ac1SFlorian Wechsung   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
1933cb87ef4cSFlorian Wechsung   ierr = PetscFree(xadj);CHKERRQ(ierr);
1934cb87ef4cSFlorian Wechsung   ierr = PetscFree(adjncy);CHKERRQ(ierr);
193541525646SFlorian Wechsung   ierr = PetscFree(vtxwgt);CHKERRQ(ierr);
1936cb87ef4cSFlorian Wechsung 
19377f57c1a4SFlorian Wechsung   /* Almost done, now rewrite the SF to reflect the new ownership. */
1938cf818975SFlorian Wechsung   {
19397f57c1a4SFlorian Wechsung     PetscInt *pointsToRewrite;
194006b3913eSFlorian Wechsung     ierr = PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite);CHKERRQ(ierr);
19417f57c1a4SFlorian Wechsung     counter = 0;
1942cb87ef4cSFlorian Wechsung     for (i=0; i<pEnd-pStart; i++) {
1943cb87ef4cSFlorian Wechsung       if (toBalance[i]) {
1944cb87ef4cSFlorian Wechsung         if (isNonExclusivelyOwned[i]) {
19457f57c1a4SFlorian Wechsung           pointsToRewrite[counter] = i + pStart;
1946cb87ef4cSFlorian Wechsung           counter++;
1947cb87ef4cSFlorian Wechsung         }
1948cb87ef4cSFlorian Wechsung       }
1949cb87ef4cSFlorian Wechsung     }
19507f57c1a4SFlorian Wechsung     ierr = DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part+1, degrees);CHKERRQ(ierr);
19517f57c1a4SFlorian Wechsung     ierr = PetscFree(pointsToRewrite);CHKERRQ(ierr);
1952cf818975SFlorian Wechsung   }
1953cb87ef4cSFlorian Wechsung 
1954cb87ef4cSFlorian Wechsung   ierr = PetscFree(toBalance);CHKERRQ(ierr);
1955cb87ef4cSFlorian Wechsung   ierr = PetscFree(isLeaf);CHKERRQ(ierr);
1956cf818975SFlorian Wechsung   ierr = PetscFree(isNonExclusivelyOwned);CHKERRQ(ierr);
1957cf818975SFlorian Wechsung   ierr = PetscFree(isExclusivelyOwned);CHKERRQ(ierr);
19587f57c1a4SFlorian Wechsung   ierr = PetscFree(part);CHKERRQ(ierr);
19595dc86ac1SFlorian Wechsung   if (viewer) {
196006b3913eSFlorian Wechsung     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
196106b3913eSFlorian Wechsung     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
19627d197802SFlorian Wechsung   }
19638b879b41SFlorian Wechsung   if (success) *success = PETSC_TRUE;
196441525646SFlorian Wechsung   ierr = PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
1965*b458e8f1SJose E. Roman   PetscFunctionReturn(0);
1966240408d3SFlorian Wechsung #else
19675f441e9bSFlorian Wechsung   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
196841525646SFlorian Wechsung #endif
1969cb87ef4cSFlorian Wechsung }
1970