xref: /petsc/src/dm/impls/plex/plexpartition.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2abe9303eSLisandro Dalcin #include <petsc/private/partitionerimpl.h>
3e8f14785SLisandro Dalcin #include <petsc/private/hashseti.h>
470034214SMatthew G. Knepley 
54b876568SBarry Smith const char *const DMPlexCSRAlgorithms[] = {"mat", "graph", "overlap", "DMPlexCSRAlgorithm", "DM_PLEX_CSR_", NULL};
65a107427SMatthew G. Knepley 
79371c9d4SSatish Balay static inline PetscInt DMPlex_GlobalID(PetscInt point) {
89371c9d4SSatish Balay   return point >= 0 ? point : -(point + 1);
99371c9d4SSatish Balay }
100134a67bSLisandro Dalcin 
119371c9d4SSatish Balay static PetscErrorCode DMPlexCreatePartitionerGraph_Overlap(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering) {
125a107427SMatthew G. Knepley   DM              ovdm;
135a107427SMatthew G. Knepley   PetscSF         sfPoint;
145a107427SMatthew G. Knepley   IS              cellNumbering;
155a107427SMatthew G. Knepley   const PetscInt *cellNum;
165a107427SMatthew G. Knepley   PetscInt       *adj = NULL, *vOffsets = NULL, *vAdj = NULL;
175a107427SMatthew G. Knepley   PetscBool       useCone, useClosure;
185a107427SMatthew G. Knepley   PetscInt        dim, depth, overlap, cStart, cEnd, c, v;
195a107427SMatthew G. Knepley   PetscMPIInt     rank, size;
205a107427SMatthew G. Knepley 
215a107427SMatthew G. Knepley   PetscFunctionBegin;
229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
239566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
249566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
265a107427SMatthew G. Knepley   if (dim != depth) {
275a107427SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
289566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
295a107427SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
309566063dSJacob Faibussowitsch     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
315a107427SMatthew G. Knepley     /* Different behavior for empty graphs */
325a107427SMatthew G. Knepley     if (!*numVertices) {
339566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, offsets));
345a107427SMatthew G. Knepley       (*offsets)[0] = 0;
355a107427SMatthew G. Knepley     }
365a107427SMatthew G. Knepley     /* Broken in parallel */
375f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
385a107427SMatthew G. Knepley     PetscFunctionReturn(0);
395a107427SMatthew G. Knepley   }
405a107427SMatthew G. Knepley   /* Always use FVM adjacency to create partitioner graph */
419566063dSJacob Faibussowitsch   PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
429566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
435a107427SMatthew G. Knepley   /* Need overlap >= 1 */
449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetOverlap(dm, &overlap));
455a107427SMatthew G. Knepley   if (size && overlap < 1) {
469566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeOverlap(dm, 1, NULL, &ovdm));
475a107427SMatthew G. Knepley   } else {
489566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
495a107427SMatthew G. Knepley     ovdm = dm;
505a107427SMatthew G. Knepley   }
519566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(ovdm, &sfPoint));
529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(ovdm, height, &cStart, &cEnd));
539566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(ovdm, cStart, cEnd, 0, NULL, sfPoint, &cellNumbering));
545a107427SMatthew G. Knepley   if (globalNumbering) {
559566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cellNumbering));
565a107427SMatthew G. Knepley     *globalNumbering = cellNumbering;
575a107427SMatthew G. Knepley   }
589566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cellNumbering, &cellNum));
595a107427SMatthew G. Knepley   /* Determine sizes */
605a107427SMatthew G. Knepley   for (*numVertices = 0, c = cStart; c < cEnd; ++c) {
615a107427SMatthew G. Knepley     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
62b68380d8SVaclav Hapla     if (cellNum[c - cStart] < 0) continue;
635a107427SMatthew G. Knepley     (*numVertices)++;
645a107427SMatthew G. Knepley   }
659566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(*numVertices + 1, &vOffsets));
665a107427SMatthew G. Knepley   for (c = cStart, v = 0; c < cEnd; ++c) {
675a107427SMatthew G. Knepley     PetscInt adjSize = PETSC_DETERMINE, a, vsize = 0;
685a107427SMatthew G. Knepley 
69b68380d8SVaclav Hapla     if (cellNum[c - cStart] < 0) continue;
709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(ovdm, c, &adjSize, &adj));
715a107427SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
725a107427SMatthew G. Knepley       const PetscInt point = adj[a];
735a107427SMatthew G. Knepley       if (point != c && cStart <= point && point < cEnd) ++vsize;
745a107427SMatthew G. Knepley     }
755a107427SMatthew G. Knepley     vOffsets[v + 1] = vOffsets[v] + vsize;
765a107427SMatthew G. Knepley     ++v;
775a107427SMatthew G. Knepley   }
785a107427SMatthew G. Knepley   /* Determine adjacency */
799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vOffsets[*numVertices], &vAdj));
805a107427SMatthew G. Knepley   for (c = cStart, v = 0; c < cEnd; ++c) {
815a107427SMatthew G. Knepley     PetscInt adjSize = PETSC_DETERMINE, a, off = vOffsets[v];
825a107427SMatthew G. Knepley 
835a107427SMatthew G. Knepley     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
84b68380d8SVaclav Hapla     if (cellNum[c - cStart] < 0) continue;
859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(ovdm, c, &adjSize, &adj));
865a107427SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
875a107427SMatthew G. Knepley       const PetscInt point = adj[a];
889371c9d4SSatish Balay       if (point != c && cStart <= point && point < cEnd) { vAdj[off++] = DMPlex_GlobalID(cellNum[point - cStart]); }
895a107427SMatthew G. Knepley     }
9063a3b9bcSJacob Faibussowitsch     PetscCheck(off == vOffsets[v + 1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Offsets %" PetscInt_FMT " should be %" PetscInt_FMT, off, vOffsets[v + 1]);
915a107427SMatthew G. Knepley     /* Sort adjacencies (not strictly necessary) */
929566063dSJacob Faibussowitsch     PetscCall(PetscSortInt(off - vOffsets[v], &vAdj[vOffsets[v]]));
935a107427SMatthew G. Knepley     ++v;
945a107427SMatthew G. Knepley   }
959566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
969566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cellNumbering, &cellNum));
979566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellNumbering));
989566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
999566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&ovdm));
1009371c9d4SSatish Balay   if (offsets) {
1019371c9d4SSatish Balay     *offsets = vOffsets;
1029371c9d4SSatish Balay   } else PetscCall(PetscFree(vOffsets));
1039371c9d4SSatish Balay   if (adjacency) {
1049371c9d4SSatish Balay     *adjacency = vAdj;
1059371c9d4SSatish Balay   } else PetscCall(PetscFree(vAdj));
1065a107427SMatthew G. Knepley   PetscFunctionReturn(0);
1075a107427SMatthew G. Knepley }
1085a107427SMatthew G. Knepley 
1099371c9d4SSatish Balay static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering) {
110ffbd6163SMatthew G. Knepley   PetscInt        dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
111389e55d8SMichael Lange   PetscInt       *adj = NULL, *vOffsets = NULL, *graph = NULL;
1128cfe4c1fSMichael Lange   IS              cellNumbering;
1138cfe4c1fSMichael Lange   const PetscInt *cellNum;
114532c4e7dSMichael Lange   PetscBool       useCone, useClosure;
115532c4e7dSMichael Lange   PetscSection    section;
116532c4e7dSMichael Lange   PetscSegBuffer  adjBuffer;
1178cfe4c1fSMichael Lange   PetscSF         sfPoint;
1188f4e72b9SMatthew G. Knepley   PetscInt       *adjCells = NULL, *remoteCells = NULL;
1198f4e72b9SMatthew G. Knepley   const PetscInt *local;
1208f4e72b9SMatthew G. Knepley   PetscInt        nroots, nleaves, l;
121532c4e7dSMichael Lange   PetscMPIInt     rank;
122532c4e7dSMichael Lange 
123532c4e7dSMichael Lange   PetscFunctionBegin;
1249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1259566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
1269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
127ffbd6163SMatthew G. Knepley   if (dim != depth) {
128ffbd6163SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
1299566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
130ffbd6163SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
1319566063dSJacob Faibussowitsch     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
132ffbd6163SMatthew G. Knepley     /* Different behavior for empty graphs */
133ffbd6163SMatthew G. Knepley     if (!*numVertices) {
1349566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, offsets));
135ffbd6163SMatthew G. Knepley       (*offsets)[0] = 0;
136ffbd6163SMatthew G. Knepley     }
137ffbd6163SMatthew G. Knepley     /* Broken in parallel */
1385f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
139ffbd6163SMatthew G. Knepley     PetscFunctionReturn(0);
140ffbd6163SMatthew G. Knepley   }
1419566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
1429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, height, &pStart, &pEnd));
143532c4e7dSMichael Lange   /* Build adjacency graph via a section/segbuffer */
1449566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
1459566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
1469566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 1000, &adjBuffer));
147532c4e7dSMichael Lange   /* Always use FVM adjacency to create partitioner graph */
1489566063dSJacob Faibussowitsch   PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
1499566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
1509566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, sfPoint, &cellNumbering));
1513fa7752dSToby Isaac   if (globalNumbering) {
1529566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cellNumbering));
1533fa7752dSToby Isaac     *globalNumbering = cellNumbering;
1543fa7752dSToby Isaac   }
1559566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cellNumbering, &cellNum));
1568f4e72b9SMatthew G. Knepley   /* For all boundary faces (including faces adjacent to a ghost cell), record the local cell in adjCells
1578f4e72b9SMatthew G. Knepley      Broadcast adjCells to remoteCells (to get cells from roots) and Reduce adjCells to remoteCells (to get cells from leaves)
1588f4e72b9SMatthew G. Knepley    */
1599566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfPoint, &nroots, &nleaves, &local, NULL));
1608f4e72b9SMatthew G. Knepley   if (nroots >= 0) {
1618f4e72b9SMatthew G. Knepley     PetscInt fStart, fEnd, f;
1628f4e72b9SMatthew G. Knepley 
1639566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nroots, &adjCells, nroots, &remoteCells));
1649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, height + 1, &fStart, &fEnd));
1658f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) adjCells[l] = -3;
1668f4e72b9SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
1678f4e72b9SMatthew G. Knepley       const PetscInt *support;
1688f4e72b9SMatthew G. Knepley       PetscInt        supportSize;
1698f4e72b9SMatthew G. Knepley 
1709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &support));
1719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
172b68380d8SVaclav Hapla       if (supportSize == 1) adjCells[f] = DMPlex_GlobalID(cellNum[support[0] - pStart]);
1738f4e72b9SMatthew G. Knepley       else if (supportSize == 2) {
1749566063dSJacob Faibussowitsch         PetscCall(PetscFindInt(support[0], nleaves, local, &p));
175b68380d8SVaclav Hapla         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1] - pStart]);
1769566063dSJacob Faibussowitsch         PetscCall(PetscFindInt(support[1], nleaves, local, &p));
177b68380d8SVaclav Hapla         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0] - pStart]);
1780134a67bSLisandro Dalcin       }
1790134a67bSLisandro Dalcin       /* Handle non-conforming meshes */
1800134a67bSLisandro Dalcin       if (supportSize > 2) {
1810134a67bSLisandro Dalcin         PetscInt        numChildren, i;
1820134a67bSLisandro Dalcin         const PetscInt *children;
1830134a67bSLisandro Dalcin 
1849566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, &children));
1850134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1860134a67bSLisandro Dalcin           const PetscInt child = children[i];
1870134a67bSLisandro Dalcin           if (fStart <= child && child < fEnd) {
1889566063dSJacob Faibussowitsch             PetscCall(DMPlexGetSupport(dm, child, &support));
1899566063dSJacob Faibussowitsch             PetscCall(DMPlexGetSupportSize(dm, child, &supportSize));
190b68380d8SVaclav Hapla             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0] - pStart]);
1910134a67bSLisandro Dalcin             else if (supportSize == 2) {
1929566063dSJacob Faibussowitsch               PetscCall(PetscFindInt(support[0], nleaves, local, &p));
193b68380d8SVaclav Hapla               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1] - pStart]);
1949566063dSJacob Faibussowitsch               PetscCall(PetscFindInt(support[1], nleaves, local, &p));
195b68380d8SVaclav Hapla               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0] - pStart]);
1960134a67bSLisandro Dalcin             }
1970134a67bSLisandro Dalcin           }
1980134a67bSLisandro Dalcin         }
1998f4e72b9SMatthew G. Knepley       }
2008f4e72b9SMatthew G. Knepley     }
2018f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) remoteCells[l] = -1;
2029566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_REPLACE));
2039566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_REPLACE));
2049566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX));
2059566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX));
2068f4e72b9SMatthew G. Knepley   }
2078f4e72b9SMatthew G. Knepley   /* Combine local and global adjacencies */
2088cfe4c1fSMichael Lange   for (*numVertices = 0, p = pStart; p < pEnd; p++) {
2098cfe4c1fSMichael Lange     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
2109371c9d4SSatish Balay     if (nroots > 0) {
2119371c9d4SSatish Balay       if (cellNum[p - pStart] < 0) continue;
2129371c9d4SSatish Balay     }
2138f4e72b9SMatthew G. Knepley     /* Add remote cells */
2148f4e72b9SMatthew G. Knepley     if (remoteCells) {
215b68380d8SVaclav Hapla       const PetscInt  gp = DMPlex_GlobalID(cellNum[p - pStart]);
2160134a67bSLisandro Dalcin       PetscInt        coneSize, numChildren, c, i;
2170134a67bSLisandro Dalcin       const PetscInt *cone, *children;
2180134a67bSLisandro Dalcin 
2199566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, p, &cone));
2209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
2218f4e72b9SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
2220134a67bSLisandro Dalcin         const PetscInt point = cone[c];
2230134a67bSLisandro Dalcin         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
2248f4e72b9SMatthew G. Knepley           PetscInt *PETSC_RESTRICT pBuf;
2259566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(section, p, 1));
2269566063dSJacob Faibussowitsch           PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2270134a67bSLisandro Dalcin           *pBuf = remoteCells[point];
2280134a67bSLisandro Dalcin         }
2290134a67bSLisandro Dalcin         /* Handle non-conforming meshes */
2309566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
2310134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
2320134a67bSLisandro Dalcin           const PetscInt child = children[i];
2330134a67bSLisandro Dalcin           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
2340134a67bSLisandro Dalcin             PetscInt *PETSC_RESTRICT pBuf;
2359566063dSJacob Faibussowitsch             PetscCall(PetscSectionAddDof(section, p, 1));
2369566063dSJacob Faibussowitsch             PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2370134a67bSLisandro Dalcin             *pBuf = remoteCells[child];
2380134a67bSLisandro Dalcin           }
2398f4e72b9SMatthew G. Knepley         }
2408f4e72b9SMatthew G. Knepley       }
2418f4e72b9SMatthew G. Knepley     }
2428f4e72b9SMatthew G. Knepley     /* Add local cells */
243532c4e7dSMichael Lange     adjSize = PETSC_DETERMINE;
2449566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
245532c4e7dSMichael Lange     for (a = 0; a < adjSize; ++a) {
246532c4e7dSMichael Lange       const PetscInt point = adj[a];
247532c4e7dSMichael Lange       if (point != p && pStart <= point && point < pEnd) {
248532c4e7dSMichael Lange         PetscInt *PETSC_RESTRICT pBuf;
2499566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(section, p, 1));
2509566063dSJacob Faibussowitsch         PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
251b68380d8SVaclav Hapla         *pBuf = DMPlex_GlobalID(cellNum[point - pStart]);
252532c4e7dSMichael Lange       }
253532c4e7dSMichael Lange     }
2548cfe4c1fSMichael Lange     (*numVertices)++;
255532c4e7dSMichael Lange   }
2569566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
2579566063dSJacob Faibussowitsch   PetscCall(PetscFree2(adjCells, remoteCells));
2589566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
2594e468a93SLisandro Dalcin 
260532c4e7dSMichael Lange   /* Derive CSR graph from section/segbuffer */
2619566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
2629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &size));
2639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(*numVertices + 1, &vOffsets));
26443f7d02bSMichael Lange   for (idx = 0, p = pStart; p < pEnd; p++) {
2659371c9d4SSatish Balay     if (nroots > 0) {
2669371c9d4SSatish Balay       if (cellNum[p - pStart] < 0) continue;
2679371c9d4SSatish Balay     }
2689566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &(vOffsets[idx++])));
26943f7d02bSMichael Lange   }
270532c4e7dSMichael Lange   vOffsets[*numVertices] = size;
2719566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &graph));
2724e468a93SLisandro Dalcin 
2734e468a93SLisandro Dalcin   if (nroots >= 0) {
2744e468a93SLisandro Dalcin     /* Filter out duplicate edges using section/segbuffer */
2759566063dSJacob Faibussowitsch     PetscCall(PetscSectionReset(section));
2769566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(section, 0, *numVertices));
2774e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2784e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p + 1];
2794e468a93SLisandro Dalcin       PetscInt numEdges = end - start, *PETSC_RESTRICT edges;
2809566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&numEdges, &graph[start]));
2819566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(section, p, numEdges));
2829566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGetInts(adjBuffer, numEdges, &edges));
2839566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(edges, &graph[start], numEdges));
2844e468a93SLisandro Dalcin     }
2859566063dSJacob Faibussowitsch     PetscCall(PetscFree(vOffsets));
2869566063dSJacob Faibussowitsch     PetscCall(PetscFree(graph));
2874e468a93SLisandro Dalcin     /* Derive CSR graph from section/segbuffer */
2889566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(section));
2899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(section, &size));
2909566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(*numVertices + 1, &vOffsets));
291*48a46eb9SPierre Jolivet     for (idx = 0, p = 0; p < *numVertices; p++) PetscCall(PetscSectionGetOffset(section, p, &(vOffsets[idx++])));
2924e468a93SLisandro Dalcin     vOffsets[*numVertices] = size;
2939566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &graph));
2944e468a93SLisandro Dalcin   } else {
2954e468a93SLisandro Dalcin     /* Sort adjacencies (not strictly necessary) */
2964e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2974e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p + 1];
2989566063dSJacob Faibussowitsch       PetscCall(PetscSortInt(end - start, &graph[start]));
2994e468a93SLisandro Dalcin     }
3004e468a93SLisandro Dalcin   }
3014e468a93SLisandro Dalcin 
3024e468a93SLisandro Dalcin   if (offsets) *offsets = vOffsets;
303389e55d8SMichael Lange   if (adjacency) *adjacency = graph;
3044e468a93SLisandro Dalcin 
305532c4e7dSMichael Lange   /* Cleanup */
3069566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferDestroy(&adjBuffer));
3079566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
3089566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cellNumbering, &cellNum));
3099566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellNumbering));
310532c4e7dSMichael Lange   PetscFunctionReturn(0);
311532c4e7dSMichael Lange }
312532c4e7dSMichael Lange 
3139371c9d4SSatish Balay static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering) {
314bbbc8e51SStefano Zampini   Mat             conn, CSR;
315bbbc8e51SStefano Zampini   IS              fis, cis, cis_own;
316bbbc8e51SStefano Zampini   PetscSF         sfPoint;
317bbbc8e51SStefano Zampini   const PetscInt *rows, *cols, *ii, *jj;
318bbbc8e51SStefano Zampini   PetscInt       *idxs, *idxs2;
31983c5d788SMatthew G. Knepley   PetscInt        dim, depth, floc, cloc, i, M, N, c, lm, m, cStart, cEnd, fStart, fEnd;
320bbbc8e51SStefano Zampini   PetscMPIInt     rank;
321bbbc8e51SStefano Zampini   PetscBool       flg;
322bbbc8e51SStefano Zampini 
323bbbc8e51SStefano Zampini   PetscFunctionBegin;
3249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3259566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
3269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
327bbbc8e51SStefano Zampini   if (dim != depth) {
328bbbc8e51SStefano Zampini     /* We do not handle the uninterpolated case here */
3299566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
330bbbc8e51SStefano Zampini     /* DMPlexCreateNeighborCSR does not make a numbering */
3319566063dSJacob Faibussowitsch     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
332bbbc8e51SStefano Zampini     /* Different behavior for empty graphs */
333bbbc8e51SStefano Zampini     if (!*numVertices) {
3349566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, offsets));
335bbbc8e51SStefano Zampini       (*offsets)[0] = 0;
336bbbc8e51SStefano Zampini     }
337bbbc8e51SStefano Zampini     /* Broken in parallel */
3385f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
339bbbc8e51SStefano Zampini     PetscFunctionReturn(0);
340bbbc8e51SStefano Zampini   }
341bbbc8e51SStefano Zampini   /* Interpolated and parallel case */
342bbbc8e51SStefano Zampini 
343bbbc8e51SStefano Zampini   /* numbering */
3449566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
3459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd));
3469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, height + 1, &fStart, &fEnd));
3479566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, &N, sfPoint, &cis));
3489566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, fStart, fEnd, 0, &M, sfPoint, &fis));
3491baa6e33SBarry Smith   if (globalNumbering) PetscCall(ISDuplicate(cis, globalNumbering));
350bbbc8e51SStefano Zampini 
351bbbc8e51SStefano Zampini   /* get positive global ids and local sizes for facets and cells */
3529566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(fis, &m));
3539566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(fis, &rows));
3549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &idxs));
355bbbc8e51SStefano Zampini   for (i = 0, floc = 0; i < m; i++) {
356bbbc8e51SStefano Zampini     const PetscInt p = rows[i];
357bbbc8e51SStefano Zampini 
358bbbc8e51SStefano Zampini     if (p < 0) {
359bbbc8e51SStefano Zampini       idxs[i] = -(p + 1);
360bbbc8e51SStefano Zampini     } else {
361bbbc8e51SStefano Zampini       idxs[i] = p;
362bbbc8e51SStefano Zampini       floc += 1;
363bbbc8e51SStefano Zampini     }
364bbbc8e51SStefano Zampini   }
3659566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(fis, &rows));
3669566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&fis));
3679566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis));
368bbbc8e51SStefano Zampini 
3699566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cis, &m));
3709566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cis, &cols));
3719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &idxs));
3729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &idxs2));
373bbbc8e51SStefano Zampini   for (i = 0, cloc = 0; i < m; i++) {
374bbbc8e51SStefano Zampini     const PetscInt p = cols[i];
375bbbc8e51SStefano Zampini 
376bbbc8e51SStefano Zampini     if (p < 0) {
377bbbc8e51SStefano Zampini       idxs[i] = -(p + 1);
378bbbc8e51SStefano Zampini     } else {
379bbbc8e51SStefano Zampini       idxs[i]       = p;
380bbbc8e51SStefano Zampini       idxs2[cloc++] = p;
381bbbc8e51SStefano Zampini     }
382bbbc8e51SStefano Zampini   }
3839566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cis, &cols));
3849566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis));
3859566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis));
3869566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own));
387bbbc8e51SStefano Zampini 
388bbbc8e51SStefano Zampini   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
3899566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), &conn));
3909566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(conn, floc, cloc, M, N));
3919566063dSJacob Faibussowitsch   PetscCall(MatSetType(conn, MATMPIAIJ));
3929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, NULL, &lm));
3939566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&lm, &m, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
3949566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL));
395bbbc8e51SStefano Zampini 
396bbbc8e51SStefano Zampini   /* Assemble matrix */
3979566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(fis, &rows));
3989566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cis, &cols));
399bbbc8e51SStefano Zampini   for (c = cStart; c < cEnd; c++) {
400bbbc8e51SStefano Zampini     const PetscInt *cone;
401bbbc8e51SStefano Zampini     PetscInt        coneSize, row, col, f;
402bbbc8e51SStefano Zampini 
403bbbc8e51SStefano Zampini     col = cols[c - cStart];
4049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
4059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
406bbbc8e51SStefano Zampini     for (f = 0; f < coneSize; f++) {
407bbbc8e51SStefano Zampini       const PetscScalar v = 1.0;
408bbbc8e51SStefano Zampini       const PetscInt   *children;
409bbbc8e51SStefano Zampini       PetscInt          numChildren, ch;
410bbbc8e51SStefano Zampini 
411bbbc8e51SStefano Zampini       row = rows[cone[f] - fStart];
4129566063dSJacob Faibussowitsch       PetscCall(MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES));
413bbbc8e51SStefano Zampini 
414bbbc8e51SStefano Zampini       /* non-conforming meshes */
4159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children));
416bbbc8e51SStefano Zampini       for (ch = 0; ch < numChildren; ch++) {
417bbbc8e51SStefano Zampini         const PetscInt child = children[ch];
418bbbc8e51SStefano Zampini 
419bbbc8e51SStefano Zampini         if (child < fStart || child >= fEnd) continue;
420bbbc8e51SStefano Zampini         row = rows[child - fStart];
4219566063dSJacob Faibussowitsch         PetscCall(MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES));
422bbbc8e51SStefano Zampini       }
423bbbc8e51SStefano Zampini     }
424bbbc8e51SStefano Zampini   }
4259566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(fis, &rows));
4269566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cis, &cols));
4279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&fis));
4289566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis));
4299566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY));
4309566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY));
431bbbc8e51SStefano Zampini 
432bbbc8e51SStefano Zampini   /* Get parallel CSR by doing conn^T * conn */
4339566063dSJacob Faibussowitsch   PetscCall(MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR));
4349566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&conn));
435bbbc8e51SStefano Zampini 
436bbbc8e51SStefano Zampini   /* extract local part of the CSR */
4379566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn));
4389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&CSR));
4399566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
4405f80ce2aSJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
441bbbc8e51SStefano Zampini 
442bbbc8e51SStefano Zampini   /* get back requested output */
443bbbc8e51SStefano Zampini   if (numVertices) *numVertices = m;
444bbbc8e51SStefano Zampini   if (offsets) {
4459566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(m + 1, &idxs));
446bbbc8e51SStefano Zampini     for (i = 1; i < m + 1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
447bbbc8e51SStefano Zampini     *offsets = idxs;
448bbbc8e51SStefano Zampini   }
449bbbc8e51SStefano Zampini   if (adjacency) {
4509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ii[m] - m, &idxs));
4519566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(cis_own, &rows));
452bbbc8e51SStefano Zampini     for (i = 0, c = 0; i < m; i++) {
453bbbc8e51SStefano Zampini       PetscInt j, g = rows[i];
454bbbc8e51SStefano Zampini 
455bbbc8e51SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
456bbbc8e51SStefano Zampini         if (jj[j] == g) continue; /* again, self-connectivity */
457bbbc8e51SStefano Zampini         idxs[c++] = jj[j];
458bbbc8e51SStefano Zampini       }
459bbbc8e51SStefano Zampini     }
46063a3b9bcSJacob Faibussowitsch     PetscCheck(c == ii[m] - m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, c, ii[m] - m);
4619566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(cis_own, &rows));
462bbbc8e51SStefano Zampini     *adjacency = idxs;
463bbbc8e51SStefano Zampini   }
464bbbc8e51SStefano Zampini 
465bbbc8e51SStefano Zampini   /* cleanup */
4669566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis_own));
4679566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
4685f80ce2aSJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
4699566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&conn));
470bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
471bbbc8e51SStefano Zampini }
472bbbc8e51SStefano Zampini 
473bbbc8e51SStefano Zampini /*@C
474bbbc8e51SStefano Zampini   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
475bbbc8e51SStefano Zampini 
476bbbc8e51SStefano Zampini   Input Parameters:
477bbbc8e51SStefano Zampini + dm      - The mesh DM dm
478bbbc8e51SStefano Zampini - height  - Height of the strata from which to construct the graph
479bbbc8e51SStefano Zampini 
480d8d19677SJose E. Roman   Output Parameters:
481bbbc8e51SStefano Zampini + numVertices     - Number of vertices in the graph
482bbbc8e51SStefano Zampini . offsets         - Point offsets in the graph
483bbbc8e51SStefano Zampini . adjacency       - Point connectivity in the graph
484bbbc8e51SStefano 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.
485bbbc8e51SStefano Zampini 
486bbbc8e51SStefano Zampini   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
487bbbc8e51SStefano Zampini   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
488bbbc8e51SStefano Zampini 
4895a107427SMatthew G. Knepley   Options Database Keys:
4905a107427SMatthew G. Knepley . -dm_plex_csr_alg <mat,graph,overlap> - Choose the algorithm for computing the CSR graph
4915a107427SMatthew G. Knepley 
492bbbc8e51SStefano Zampini   Level: developer
493bbbc8e51SStefano Zampini 
494db781477SPatrick Sanan .seealso: `PetscPartitionerGetType()`, `PetscPartitionerCreate()`, `DMSetAdjacency()`
495bbbc8e51SStefano Zampini @*/
4969371c9d4SSatish Balay PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering) {
4975a107427SMatthew G. Knepley   DMPlexCSRAlgorithm alg = DM_PLEX_CSR_GRAPH;
498bbbc8e51SStefano Zampini 
499bbbc8e51SStefano Zampini   PetscFunctionBegin;
5009566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetEnum(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_csr_alg", DMPlexCSRAlgorithms, (PetscEnum *)&alg, NULL));
5015a107427SMatthew G. Knepley   switch (alg) {
5029371c9d4SSatish Balay   case DM_PLEX_CSR_MAT: PetscCall(DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering)); break;
5039371c9d4SSatish Balay   case DM_PLEX_CSR_GRAPH: PetscCall(DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering)); break;
5049371c9d4SSatish Balay   case DM_PLEX_CSR_OVERLAP: PetscCall(DMPlexCreatePartitionerGraph_Overlap(dm, height, numVertices, offsets, adjacency, globalNumbering)); break;
505bbbc8e51SStefano Zampini   }
506bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
507bbbc8e51SStefano Zampini }
508bbbc8e51SStefano Zampini 
509d5577e40SMatthew G. Knepley /*@C
510d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
511d5577e40SMatthew G. Knepley 
512fe2efc57SMark   Collective on DM
513d5577e40SMatthew G. Knepley 
5144165533cSJose E. Roman   Input Parameters:
515d5577e40SMatthew G. Knepley + dm - The DMPlex
516d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
517d5577e40SMatthew G. Knepley 
5184165533cSJose E. Roman   Output Parameters:
519d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
520d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
521d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
522d5577e40SMatthew G. Knepley 
523d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
524d5577e40SMatthew G. Knepley 
525d5577e40SMatthew G. Knepley   Level: advanced
526d5577e40SMatthew G. Knepley 
527db781477SPatrick Sanan .seealso: `DMPlexCreate()`
528d5577e40SMatthew G. Knepley @*/
5299371c9d4SSatish Balay PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency) {
53070034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
53170034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
53270034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
53370034214SMatthew G. Knepley   PetscInt      *off, *adj;
53470034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
53570034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
53670034214SMatthew G. Knepley 
53770034214SMatthew G. Knepley   PetscFunctionBegin;
53870034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
5399566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
54070034214SMatthew G. Knepley   cellDim = dim - cellHeight;
5419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
5429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
54370034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
54470034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
54570034214SMatthew G. Knepley     if (offsets) *offsets = NULL;
54670034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
54770034214SMatthew G. Knepley     PetscFunctionReturn(0);
54870034214SMatthew G. Knepley   }
54970034214SMatthew G. Knepley   numCells  = cEnd - cStart;
55070034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
55170034214SMatthew G. Knepley   if (dim == depth) {
55270034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
55370034214SMatthew G. Knepley 
5549566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(numCells + 1, &off));
55570034214SMatthew G. Knepley     /* Count neighboring cells */
5569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight + 1, &fStart, &fEnd));
55770034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
55870034214SMatthew G. Knepley       const PetscInt *support;
55970034214SMatthew G. Knepley       PetscInt        supportSize;
5609566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
5619566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &support));
56270034214SMatthew G. Knepley       if (supportSize == 2) {
5639ffc88e4SToby Isaac         PetscInt numChildren;
5649ffc88e4SToby Isaac 
5659566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
5669ffc88e4SToby Isaac         if (!numChildren) {
56770034214SMatthew G. Knepley           ++off[support[0] - cStart + 1];
56870034214SMatthew G. Knepley           ++off[support[1] - cStart + 1];
56970034214SMatthew G. Knepley         }
57070034214SMatthew G. Knepley       }
5719ffc88e4SToby Isaac     }
57270034214SMatthew G. Knepley     /* Prefix sum */
57370034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c - 1];
57470034214SMatthew G. Knepley     if (adjacency) {
57570034214SMatthew G. Knepley       PetscInt *tmp;
57670034214SMatthew G. Knepley 
5779566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(off[numCells], &adj));
5789566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numCells + 1, &tmp));
5799566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(tmp, off, numCells + 1));
58070034214SMatthew G. Knepley       /* Get neighboring cells */
58170034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
58270034214SMatthew G. Knepley         const PetscInt *support;
58370034214SMatthew G. Knepley         PetscInt        supportSize;
5849566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
5859566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, f, &support));
58670034214SMatthew G. Knepley         if (supportSize == 2) {
5879ffc88e4SToby Isaac           PetscInt numChildren;
5889ffc88e4SToby Isaac 
5899566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
5909ffc88e4SToby Isaac           if (!numChildren) {
59170034214SMatthew G. Knepley             adj[tmp[support[0] - cStart]++] = support[1];
59270034214SMatthew G. Knepley             adj[tmp[support[1] - cStart]++] = support[0];
59370034214SMatthew G. Knepley           }
59470034214SMatthew G. Knepley         }
5959ffc88e4SToby Isaac       }
59663a3b9bcSJacob Faibussowitsch       for (c = 0; c < cEnd - cStart; ++c) PetscAssert(tmp[c] == off[c + 1], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Offset %" PetscInt_FMT " != %" PetscInt_FMT " for cell %" PetscInt_FMT, tmp[c], off[c], c + cStart);
5979566063dSJacob Faibussowitsch       PetscCall(PetscFree(tmp));
59870034214SMatthew G. Knepley     }
59970034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
60070034214SMatthew G. Knepley     if (offsets) *offsets = off;
60170034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
60270034214SMatthew G. Knepley     PetscFunctionReturn(0);
60370034214SMatthew G. Knepley   }
60470034214SMatthew G. Knepley   /* Setup face recognition */
60570034214SMatthew G. Knepley   if (faceDepth == 1) {
60670034214SMatthew 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 */
60770034214SMatthew G. Knepley 
60870034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
60970034214SMatthew G. Knepley       PetscInt corners;
61070034214SMatthew G. Knepley 
6119566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &corners));
61270034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
61370034214SMatthew G. Knepley         PetscInt nFV;
61470034214SMatthew G. Knepley 
6155f80ce2aSJacob Faibussowitsch         PetscCheck(numFaceCases < maxFaceCases, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
61670034214SMatthew G. Knepley         cornersSeen[corners] = 1;
61770034214SMatthew G. Knepley 
6189566063dSJacob Faibussowitsch         PetscCall(DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV));
61970034214SMatthew G. Knepley 
62070034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
62170034214SMatthew G. Knepley       }
62270034214SMatthew G. Knepley     }
62370034214SMatthew G. Knepley   }
6249566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numCells + 1, &off));
62570034214SMatthew G. Knepley   /* Count neighboring cells */
62670034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
62770034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
62870034214SMatthew G. Knepley 
6299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
63070034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
63170034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
63270034214SMatthew G. Knepley       PetscInt        cellPair[2];
63370034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
63470034214SMatthew G. Knepley       PetscInt        meetSize = 0;
63570034214SMatthew G. Knepley       const PetscInt *meet     = NULL;
63670034214SMatthew G. Knepley 
6379371c9d4SSatish Balay       cellPair[0] = cell;
6389371c9d4SSatish Balay       cellPair[1] = neighborCells[n];
63970034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
64070034214SMatthew G. Knepley       if (!found) {
6419566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
64270034214SMatthew G. Knepley         if (meetSize) {
64370034214SMatthew G. Knepley           PetscInt f;
64470034214SMatthew G. Knepley 
64570034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
64670034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
64770034214SMatthew G. Knepley               found = PETSC_TRUE;
64870034214SMatthew G. Knepley               break;
64970034214SMatthew G. Knepley             }
65070034214SMatthew G. Knepley           }
65170034214SMatthew G. Knepley         }
6529566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
65370034214SMatthew G. Knepley       }
65470034214SMatthew G. Knepley       if (found) ++off[cell - cStart + 1];
65570034214SMatthew G. Knepley     }
65670034214SMatthew G. Knepley   }
65770034214SMatthew G. Knepley   /* Prefix sum */
65870034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell - 1];
65970034214SMatthew G. Knepley 
66070034214SMatthew G. Knepley   if (adjacency) {
6619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(off[numCells], &adj));
66270034214SMatthew G. Knepley     /* Get neighboring cells */
66370034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
66470034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
66570034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
66670034214SMatthew G. Knepley 
6679566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
66870034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
66970034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
67070034214SMatthew G. Knepley         PetscInt        cellPair[2];
67170034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
67270034214SMatthew G. Knepley         PetscInt        meetSize = 0;
67370034214SMatthew G. Knepley         const PetscInt *meet     = NULL;
67470034214SMatthew G. Knepley 
6759371c9d4SSatish Balay         cellPair[0] = cell;
6769371c9d4SSatish Balay         cellPair[1] = neighborCells[n];
67770034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
67870034214SMatthew G. Knepley         if (!found) {
6799566063dSJacob Faibussowitsch           PetscCall(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
68070034214SMatthew G. Knepley           if (meetSize) {
68170034214SMatthew G. Knepley             PetscInt f;
68270034214SMatthew G. Knepley 
68370034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
68470034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
68570034214SMatthew G. Knepley                 found = PETSC_TRUE;
68670034214SMatthew G. Knepley                 break;
68770034214SMatthew G. Knepley               }
68870034214SMatthew G. Knepley             }
68970034214SMatthew G. Knepley           }
6909566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
69170034214SMatthew G. Knepley         }
69270034214SMatthew G. Knepley         if (found) {
69370034214SMatthew G. Knepley           adj[off[cell - cStart] + cellOffset] = neighborCells[n];
69470034214SMatthew G. Knepley           ++cellOffset;
69570034214SMatthew G. Knepley         }
69670034214SMatthew G. Knepley       }
69770034214SMatthew G. Knepley     }
69870034214SMatthew G. Knepley   }
6999566063dSJacob Faibussowitsch   PetscCall(PetscFree(neighborCells));
70070034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
70170034214SMatthew G. Knepley   if (offsets) *offsets = off;
70270034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
70370034214SMatthew G. Knepley   PetscFunctionReturn(0);
70470034214SMatthew G. Knepley }
70570034214SMatthew G. Knepley 
70677623264SMatthew G. Knepley /*@
7073c41b853SStefano Zampini   PetscPartitionerDMPlexPartition - Create a non-overlapping partition of the cells in the mesh
70877623264SMatthew G. Knepley 
709fe2efc57SMark   Collective on PetscPartitioner
71077623264SMatthew G. Knepley 
71177623264SMatthew G. Knepley   Input Parameters:
71277623264SMatthew G. Knepley + part    - The PetscPartitioner
7133c41b853SStefano Zampini . targetSection - The PetscSection describing the absolute weight of each partition (can be NULL)
714f8987ae8SMichael Lange - dm      - The mesh DM
71577623264SMatthew G. Knepley 
71677623264SMatthew G. Knepley   Output Parameters:
71777623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
718f8987ae8SMichael Lange - partition       - The list of points by partition
71977623264SMatthew G. Knepley 
7203c41b853SStefano Zampini   Notes:
7213c41b853SStefano Zampini     If the DM has a local section associated, each point to be partitioned will be weighted by the total number of dofs identified
7223c41b853SStefano Zampini     by the section in the transitive closure of the point.
72377623264SMatthew G. Knepley 
72477623264SMatthew G. Knepley   Level: developer
72577623264SMatthew G. Knepley 
726db781477SPatrick Sanan .seealso `DMPlexDistribute()`, `PetscPartitionerCreate()`, `PetscSectionCreate()`, `PetscSectionSetChart()`, `PetscPartitionerPartition()`
7274b15ede2SMatthew G. Knepley @*/
7289371c9d4SSatish Balay PetscErrorCode PetscPartitionerDMPlexPartition(PetscPartitioner part, DM dm, PetscSection targetSection, PetscSection partSection, IS *partition) {
72977623264SMatthew G. Knepley   PetscMPIInt  size;
7303c41b853SStefano Zampini   PetscBool    isplex;
7313c41b853SStefano Zampini   PetscSection vertSection = NULL;
73277623264SMatthew G. Knepley 
73377623264SMatthew G. Knepley   PetscFunctionBegin;
73477623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
73577623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
7363c41b853SStefano Zampini   if (targetSection) PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 3);
73777623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
73877623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
7399566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isplex));
7405f80ce2aSJacob Faibussowitsch   PetscCheck(isplex, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not for type %s", ((PetscObject)dm)->type_name);
7419566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)part), &size));
74277623264SMatthew G. Knepley   if (size == 1) {
74377623264SMatthew G. Knepley     PetscInt *points;
74477623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
74577623264SMatthew G. Knepley 
7469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
7479566063dSJacob Faibussowitsch     PetscCall(PetscSectionReset(partSection));
7489566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(partSection, 0, size));
7499566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(partSection, 0, cEnd - cStart));
7509566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(partSection));
7519566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cEnd - cStart, &points));
75277623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
7539566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)part), cEnd - cStart, points, PETSC_OWN_POINTER, partition));
75477623264SMatthew G. Knepley     PetscFunctionReturn(0);
75577623264SMatthew G. Knepley   }
75677623264SMatthew G. Knepley   if (part->height == 0) {
757074d466cSStefano Zampini     PetscInt  numVertices = 0;
75877623264SMatthew G. Knepley     PetscInt *start       = NULL;
75977623264SMatthew G. Knepley     PetscInt *adjacency   = NULL;
7603fa7752dSToby Isaac     IS        globalNumbering;
76177623264SMatthew G. Knepley 
762074d466cSStefano Zampini     if (!part->noGraph || part->viewGraph) {
7639566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering));
76413911537SStefano Zampini     } else { /* only compute the number of owned local vertices */
765074d466cSStefano Zampini       const PetscInt *idxs;
766074d466cSStefano Zampini       PetscInt        p, pStart, pEnd;
767074d466cSStefano Zampini 
7689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
7699566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering));
7709566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(globalNumbering, &idxs));
771074d466cSStefano Zampini       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
7729566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(globalNumbering, &idxs));
773074d466cSStefano Zampini     }
7743c41b853SStefano Zampini     if (part->usevwgt) {
7753c41b853SStefano Zampini       PetscSection    section = dm->localSection, clSection = NULL;
7763c41b853SStefano Zampini       IS              clPoints = NULL;
7773c41b853SStefano Zampini       const PetscInt *gid, *clIdx;
7783c41b853SStefano Zampini       PetscInt        v, p, pStart, pEnd;
7790358368aSMatthew G. Knepley 
7803c41b853SStefano 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) */
7813c41b853SStefano Zampini       /* We do this only if the local section has been set */
7823c41b853SStefano Zampini       if (section) {
7839566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, NULL));
784*48a46eb9SPierre Jolivet         if (!clSection) PetscCall(DMPlexCreateClosureIndex(dm, NULL));
7859566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, &clPoints));
7869566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(clPoints, &clIdx));
7873c41b853SStefano Zampini       }
7889566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
7899566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &vertSection));
7909566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(vertSection, 0, numVertices));
7913c41b853SStefano Zampini       if (globalNumbering) {
7929566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(globalNumbering, &gid));
7933c41b853SStefano Zampini       } else gid = NULL;
7943c41b853SStefano Zampini       for (p = pStart, v = 0; p < pEnd; ++p) {
7953c41b853SStefano Zampini         PetscInt dof = 1;
7960358368aSMatthew G. Knepley 
7973c41b853SStefano Zampini         /* skip cells in the overlap */
7983c41b853SStefano Zampini         if (gid && gid[p - pStart] < 0) continue;
7993c41b853SStefano Zampini 
8003c41b853SStefano Zampini         if (section) {
8013c41b853SStefano Zampini           PetscInt cl, clSize, clOff;
8023c41b853SStefano Zampini 
8033c41b853SStefano Zampini           dof = 0;
8049566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(clSection, p, &clSize));
8059566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(clSection, p, &clOff));
8063c41b853SStefano Zampini           for (cl = 0; cl < clSize; cl += 2) {
8073c41b853SStefano Zampini             PetscInt clDof, clPoint = clIdx[clOff + cl]; /* odd indices are reserved for orientations */
8083c41b853SStefano Zampini 
8099566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, clPoint, &clDof));
8103c41b853SStefano Zampini             dof += clDof;
8110358368aSMatthew G. Knepley           }
8120358368aSMatthew G. Knepley         }
81363a3b9bcSJacob Faibussowitsch         PetscCheck(dof, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of dofs for point %" PetscInt_FMT " in the local section should be positive", p);
8149566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(vertSection, v, dof));
8153c41b853SStefano Zampini         v++;
8163c41b853SStefano Zampini       }
817*48a46eb9SPierre Jolivet       if (globalNumbering) PetscCall(ISRestoreIndices(globalNumbering, &gid));
818*48a46eb9SPierre Jolivet       if (clPoints) PetscCall(ISRestoreIndices(clPoints, &clIdx));
8199566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(vertSection));
8203c41b853SStefano Zampini     }
8219566063dSJacob Faibussowitsch     PetscCall(PetscPartitionerPartition(part, size, numVertices, start, adjacency, vertSection, targetSection, partSection, partition));
8229566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
8239566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
8243fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
8253fa7752dSToby Isaac       const PetscInt *globalNum;
8263fa7752dSToby Isaac       const PetscInt *partIdx;
8273fa7752dSToby Isaac       PetscInt       *map, cStart, cEnd;
8283fa7752dSToby Isaac       PetscInt       *adjusted, i, localSize, offset;
8293fa7752dSToby Isaac       IS              newPartition;
8303fa7752dSToby Isaac 
8319566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(*partition, &localSize));
8329566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localSize, &adjusted));
8339566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(globalNumbering, &globalNum));
8349566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(*partition, &partIdx));
8359566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localSize, &map));
8369566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
8373fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
8383fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
8393fa7752dSToby Isaac       }
8409371c9d4SSatish Balay       for (i = 0; i < localSize; i++) { adjusted[i] = map[partIdx[i]]; }
8419566063dSJacob Faibussowitsch       PetscCall(PetscFree(map));
8429566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(*partition, &partIdx));
8439566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(globalNumbering, &globalNum));
8449566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, localSize, adjusted, PETSC_OWN_POINTER, &newPartition));
8459566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalNumbering));
8469566063dSJacob Faibussowitsch       PetscCall(ISDestroy(partition));
8473fa7752dSToby Isaac       *partition = newPartition;
8483fa7752dSToby Isaac     }
84963a3b9bcSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %" PetscInt_FMT " for points to partition", part->height);
8509566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&vertSection));
85177623264SMatthew G. Knepley   PetscFunctionReturn(0);
85277623264SMatthew G. Knepley }
85377623264SMatthew G. Knepley 
8545680f57bSMatthew G. Knepley /*@
8555680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
8565680f57bSMatthew G. Knepley 
8575680f57bSMatthew G. Knepley   Not collective
8585680f57bSMatthew G. Knepley 
8595680f57bSMatthew G. Knepley   Input Parameter:
8605680f57bSMatthew G. Knepley . dm - The DM
8615680f57bSMatthew G. Knepley 
8625680f57bSMatthew G. Knepley   Output Parameter:
8635680f57bSMatthew G. Knepley . part - The PetscPartitioner
8645680f57bSMatthew G. Knepley 
8655680f57bSMatthew G. Knepley   Level: developer
8665680f57bSMatthew G. Knepley 
86798599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
86898599a47SLawrence Mitchell 
869db781477SPatrick Sanan .seealso `DMPlexDistribute()`, `DMPlexSetPartitioner()`, `PetscPartitionerDMPlexPartition()`, `PetscPartitionerCreate()`
8705680f57bSMatthew G. Knepley @*/
8719371c9d4SSatish Balay PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part) {
8725680f57bSMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
8735680f57bSMatthew G. Knepley 
8745680f57bSMatthew G. Knepley   PetscFunctionBegin;
8755680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8765680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
8775680f57bSMatthew G. Knepley   *part = mesh->partitioner;
8785680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
8795680f57bSMatthew G. Knepley }
8805680f57bSMatthew G. Knepley 
88171bb2955SLawrence Mitchell /*@
88271bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
88371bb2955SLawrence Mitchell 
884fe2efc57SMark   logically collective on DM
88571bb2955SLawrence Mitchell 
88671bb2955SLawrence Mitchell   Input Parameters:
88771bb2955SLawrence Mitchell + dm - The DM
88871bb2955SLawrence Mitchell - part - The partitioner
88971bb2955SLawrence Mitchell 
89071bb2955SLawrence Mitchell   Level: developer
89171bb2955SLawrence Mitchell 
89271bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
89371bb2955SLawrence Mitchell 
894db781477SPatrick Sanan .seealso `DMPlexDistribute()`, `DMPlexGetPartitioner()`, `PetscPartitionerCreate()`
89571bb2955SLawrence Mitchell @*/
8969371c9d4SSatish Balay PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part) {
89771bb2955SLawrence Mitchell   DM_Plex *mesh = (DM_Plex *)dm->data;
89871bb2955SLawrence Mitchell 
89971bb2955SLawrence Mitchell   PetscFunctionBegin;
90071bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
90171bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
9029566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)part));
9039566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
90471bb2955SLawrence Mitchell   mesh->partitioner = part;
90571bb2955SLawrence Mitchell   PetscFunctionReturn(0);
90671bb2955SLawrence Mitchell }
90771bb2955SLawrence Mitchell 
9089371c9d4SSatish Balay static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point) {
9098e330a33SStefano Zampini   const PetscInt *cone;
9108e330a33SStefano Zampini   PetscInt        coneSize, c;
9118e330a33SStefano Zampini   PetscBool       missing;
9128e330a33SStefano Zampini 
9138e330a33SStefano Zampini   PetscFunctionBeginHot;
9149566063dSJacob Faibussowitsch   PetscCall(PetscHSetIQueryAdd(ht, point, &missing));
9158e330a33SStefano Zampini   if (missing) {
9169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
9179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
918*48a46eb9SPierre Jolivet     for (c = 0; c < coneSize; c++) PetscCall(DMPlexAddClosure_Private(dm, ht, cone[c]));
9198e330a33SStefano Zampini   }
9208e330a33SStefano Zampini   PetscFunctionReturn(0);
9218e330a33SStefano Zampini }
9228e330a33SStefano Zampini 
9239371c9d4SSatish Balay PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down) {
924270bba0cSToby Isaac   PetscFunctionBegin;
9256a5a2ffdSToby Isaac   if (up) {
9266a5a2ffdSToby Isaac     PetscInt parent;
9276a5a2ffdSToby Isaac 
9289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
9296a5a2ffdSToby Isaac     if (parent != point) {
9306a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
9316a5a2ffdSToby Isaac 
9329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
933270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
934270bba0cSToby Isaac         PetscInt cpoint = closure[2 * i];
935270bba0cSToby Isaac 
9369566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(ht, cpoint));
9379566063dSJacob Faibussowitsch         PetscCall(DMPlexAddClosure_Tree(dm, ht, cpoint, PETSC_TRUE, PETSC_FALSE));
938270bba0cSToby Isaac       }
9399566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
9406a5a2ffdSToby Isaac     }
9416a5a2ffdSToby Isaac   }
9426a5a2ffdSToby Isaac   if (down) {
9436a5a2ffdSToby Isaac     PetscInt        numChildren;
9446a5a2ffdSToby Isaac     const PetscInt *children;
9456a5a2ffdSToby Isaac 
9469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
9476a5a2ffdSToby Isaac     if (numChildren) {
9486a5a2ffdSToby Isaac       PetscInt i;
9496a5a2ffdSToby Isaac 
9506a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
9516a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
9526a5a2ffdSToby Isaac 
9539566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(ht, cpoint));
9549566063dSJacob Faibussowitsch         PetscCall(DMPlexAddClosure_Tree(dm, ht, cpoint, PETSC_FALSE, PETSC_TRUE));
9556a5a2ffdSToby Isaac       }
9566a5a2ffdSToby Isaac     }
9576a5a2ffdSToby Isaac   }
958270bba0cSToby Isaac   PetscFunctionReturn(0);
959270bba0cSToby Isaac }
960270bba0cSToby Isaac 
9619371c9d4SSatish Balay static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point) {
9628e330a33SStefano Zampini   PetscInt parent;
963825f8a23SLisandro Dalcin 
9648e330a33SStefano Zampini   PetscFunctionBeginHot;
9659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
9668e330a33SStefano Zampini   if (point != parent) {
9678e330a33SStefano Zampini     const PetscInt *cone;
9688e330a33SStefano Zampini     PetscInt        coneSize, c;
9698e330a33SStefano Zampini 
9709566063dSJacob Faibussowitsch     PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, parent));
9719566063dSJacob Faibussowitsch     PetscCall(DMPlexAddClosure_Private(dm, ht, parent));
9729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, parent, &cone));
9739566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
9748e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
9758e330a33SStefano Zampini       const PetscInt cp = cone[c];
9768e330a33SStefano Zampini 
9779566063dSJacob Faibussowitsch       PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, cp));
9788e330a33SStefano Zampini     }
9798e330a33SStefano Zampini   }
9808e330a33SStefano Zampini   PetscFunctionReturn(0);
9818e330a33SStefano Zampini }
9828e330a33SStefano Zampini 
9839371c9d4SSatish Balay static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point) {
9848e330a33SStefano Zampini   PetscInt        i, numChildren;
9858e330a33SStefano Zampini   const PetscInt *children;
9868e330a33SStefano Zampini 
9878e330a33SStefano Zampini   PetscFunctionBeginHot;
9889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
989*48a46eb9SPierre Jolivet   for (i = 0; i < numChildren; i++) PetscCall(PetscHSetIAdd(ht, children[i]));
9908e330a33SStefano Zampini   PetscFunctionReturn(0);
9918e330a33SStefano Zampini }
9928e330a33SStefano Zampini 
9939371c9d4SSatish Balay static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point) {
9948e330a33SStefano Zampini   const PetscInt *cone;
9958e330a33SStefano Zampini   PetscInt        coneSize, c;
9968e330a33SStefano Zampini 
9978e330a33SStefano Zampini   PetscFunctionBeginHot;
9989566063dSJacob Faibussowitsch   PetscCall(PetscHSetIAdd(ht, point));
9999566063dSJacob Faibussowitsch   PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, point));
10009566063dSJacob Faibussowitsch   PetscCall(DMPlexAddClosureTree_Down_Private(dm, ht, point));
10019566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
10029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
1003*48a46eb9SPierre Jolivet   for (c = 0; c < coneSize; c++) PetscCall(DMPlexAddClosureTree_Private(dm, ht, cone[c]));
10048e330a33SStefano Zampini   PetscFunctionReturn(0);
10058e330a33SStefano Zampini }
10068e330a33SStefano Zampini 
10079371c9d4SSatish Balay PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS) {
1008825f8a23SLisandro Dalcin   DM_Plex        *mesh    = (DM_Plex *)dm->data;
10098e330a33SStefano Zampini   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
10108e330a33SStefano Zampini   PetscInt        nelems, *elems, off = 0, p;
101127104ee2SJacob Faibussowitsch   PetscHSetI      ht = NULL;
1012825f8a23SLisandro Dalcin 
1013825f8a23SLisandro Dalcin   PetscFunctionBegin;
10149566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
10159566063dSJacob Faibussowitsch   PetscCall(PetscHSetIResize(ht, numPoints * 16));
10168e330a33SStefano Zampini   if (!hasTree) {
1017*48a46eb9SPierre Jolivet     for (p = 0; p < numPoints; ++p) PetscCall(DMPlexAddClosure_Private(dm, ht, points[p]));
10188e330a33SStefano Zampini   } else {
10198e330a33SStefano Zampini #if 1
1020*48a46eb9SPierre Jolivet     for (p = 0; p < numPoints; ++p) PetscCall(DMPlexAddClosureTree_Private(dm, ht, points[p]));
10218e330a33SStefano Zampini #else
10228e330a33SStefano Zampini     PetscInt *closure = NULL, closureSize, c;
1023825f8a23SLisandro Dalcin     for (p = 0; p < numPoints; ++p) {
10249566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure));
1025825f8a23SLisandro Dalcin       for (c = 0; c < closureSize * 2; c += 2) {
10269566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(ht, closure[c]));
10279566063dSJacob Faibussowitsch         if (hasTree) PetscCall(DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE));
1028825f8a23SLisandro Dalcin       }
1029825f8a23SLisandro Dalcin     }
10309566063dSJacob Faibussowitsch     if (closure) PetscCall(DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure));
10318e330a33SStefano Zampini #endif
10328e330a33SStefano Zampini   }
10339566063dSJacob Faibussowitsch   PetscCall(PetscHSetIGetSize(ht, &nelems));
10349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nelems, &elems));
10359566063dSJacob Faibussowitsch   PetscCall(PetscHSetIGetElems(ht, &off, elems));
10369566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
10379566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(nelems, elems));
10389566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS));
1039825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
1040825f8a23SLisandro Dalcin }
1041825f8a23SLisandro Dalcin 
10425abbe4feSMichael Lange /*@
10435abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
10445abbe4feSMichael Lange 
10455abbe4feSMichael Lange   Input Parameters:
10465abbe4feSMichael Lange + dm     - The DM
1047a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
10485abbe4feSMichael Lange 
10495abbe4feSMichael Lange   Level: developer
10505abbe4feSMichael Lange 
1051db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
10525abbe4feSMichael Lange @*/
10539371c9d4SSatish Balay PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label) {
1054825f8a23SLisandro Dalcin   IS              rankIS, pointIS, closureIS;
10555abbe4feSMichael Lange   const PetscInt *ranks, *points;
1056825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
10579ffc88e4SToby Isaac 
10589ffc88e4SToby Isaac   PetscFunctionBegin;
10599566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &rankIS));
10609566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
10619566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
10625abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
10635abbe4feSMichael Lange     const PetscInt rank = ranks[r];
10649566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &pointIS));
10659566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
10669566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
10679566063dSJacob Faibussowitsch     PetscCall(DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS));
10689566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
10699566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
10709566063dSJacob Faibussowitsch     PetscCall(DMLabelSetStratumIS(label, rank, closureIS));
10719566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&closureIS));
10729ffc88e4SToby Isaac   }
10739566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
10749566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
10759ffc88e4SToby Isaac   PetscFunctionReturn(0);
10769ffc88e4SToby Isaac }
10779ffc88e4SToby Isaac 
107824d039d7SMichael Lange /*@
107924d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
108024d039d7SMichael Lange 
108124d039d7SMichael Lange   Input Parameters:
108224d039d7SMichael Lange + dm     - The DM
1083a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
108424d039d7SMichael Lange 
108524d039d7SMichael Lange   Level: developer
108624d039d7SMichael Lange 
1087db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
108824d039d7SMichael Lange @*/
10899371c9d4SSatish Balay PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label) {
109024d039d7SMichael Lange   IS              rankIS, pointIS;
109124d039d7SMichael Lange   const PetscInt *ranks, *points;
109224d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
109324d039d7SMichael Lange   PetscInt       *adj = NULL;
109470034214SMatthew G. Knepley 
109570034214SMatthew G. Knepley   PetscFunctionBegin;
10969566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &rankIS));
10979566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
10989566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
109924d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
110024d039d7SMichael Lange     const PetscInt rank = ranks[r];
110170034214SMatthew G. Knepley 
11029566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &pointIS));
11039566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
11049566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
110570034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
110624d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
11079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency(dm, points[p], &adjSize, &adj));
11089566063dSJacob Faibussowitsch       for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(label, adj[a], rank));
110970034214SMatthew G. Knepley     }
11109566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
11119566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
111270034214SMatthew G. Knepley   }
11139566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11149566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11159566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
111624d039d7SMichael Lange   PetscFunctionReturn(0);
111770034214SMatthew G. Knepley }
111870034214SMatthew G. Knepley 
1119be200f8dSMichael Lange /*@
1120be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
1121be200f8dSMichael Lange 
1122be200f8dSMichael Lange   Input Parameters:
1123be200f8dSMichael Lange + dm     - The DM
1124a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
1125be200f8dSMichael Lange 
1126be200f8dSMichael Lange   Level: developer
1127be200f8dSMichael Lange 
1128be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
1129be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
1130be200f8dSMichael Lange 
1131db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1132be200f8dSMichael Lange @*/
11339371c9d4SSatish Balay PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label) {
1134be200f8dSMichael Lange   MPI_Comm        comm;
1135be200f8dSMichael Lange   PetscMPIInt     rank;
1136be200f8dSMichael Lange   PetscSF         sfPoint;
11375d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
1138be200f8dSMichael Lange   IS              rankIS, pointIS;
1139be200f8dSMichael Lange   const PetscInt *ranks;
1140be200f8dSMichael Lange   PetscInt        numRanks, r;
1141be200f8dSMichael Lange 
1142be200f8dSMichael Lange   PetscFunctionBegin;
11439566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
11449566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
11459566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
11465d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
11479566063dSJacob Faibussowitsch   PetscCall(DMLabelGather(label, sfPoint, &lblLeaves));
11489566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(lblLeaves, &rankIS));
11499566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
11509566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
11515d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
11525d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
11535d04f6ebSMichael Lange     if (remoteRank == rank) continue;
11549566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS));
11559566063dSJacob Faibussowitsch     PetscCall(DMLabelInsertIS(label, pointIS, remoteRank));
11569566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
11575d04f6ebSMichael Lange   }
11589566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11599566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11609566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lblLeaves));
1161be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
11629566063dSJacob Faibussowitsch   PetscCall(DMLabelDistribute(label, sfPoint, &lblRoots));
11639566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(lblRoots, &rankIS));
11649566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
11659566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
1166be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
1167be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
1168be200f8dSMichael Lange     if (remoteRank == rank) continue;
11699566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS));
11709566063dSJacob Faibussowitsch     PetscCall(DMLabelInsertIS(label, pointIS, remoteRank));
11719566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
1172be200f8dSMichael Lange   }
11739566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11749566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11759566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lblRoots));
1176be200f8dSMichael Lange   PetscFunctionReturn(0);
1177be200f8dSMichael Lange }
1178be200f8dSMichael Lange 
11791fd9873aSMichael Lange /*@
11801fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
11811fd9873aSMichael Lange 
11821fd9873aSMichael Lange   Input Parameters:
11831fd9873aSMichael Lange + dm        - The DM
1184a5b23f4aSJose E. Roman . rootLabel - DMLabel assigning ranks to local roots
1185fe2efc57SMark - processSF - A star forest mapping into the local index on each remote rank
11861fd9873aSMichael Lange 
11871fd9873aSMichael Lange   Output Parameter:
1188a5b23f4aSJose E. Roman . leafLabel - DMLabel assigning ranks to remote roots
11891fd9873aSMichael Lange 
11901fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
11911fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
11921fd9873aSMichael Lange 
11931fd9873aSMichael Lange   Level: developer
11941fd9873aSMichael Lange 
1195db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
11961fd9873aSMichael Lange @*/
11979371c9d4SSatish Balay PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel) {
11981fd9873aSMichael Lange   MPI_Comm           comm;
1199874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
1200874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
12011fd9873aSMichael Lange   PetscSF            sfPoint;
1202874ddda9SLisandro Dalcin   PetscSection       rootSection;
12031fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
12041fd9873aSMichael Lange   const PetscSFNode *remote;
12051fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
12061fd9873aSMichael Lange   IS                 valueIS;
1207874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
12081fd9873aSMichael Lange 
12091fd9873aSMichael Lange   PetscFunctionBegin;
12109566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_PartLabelInvert, dm, 0, 0, 0));
12119566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
12129566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
12139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
12149566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
12151fd9873aSMichael Lange 
12161fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
12179566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &rootSection));
12189566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootSection, 0, size));
12199566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(rootLabel, &valueIS));
12209566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(valueIS, &numNeighbors));
12219566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(valueIS, &neighbors));
12221fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
12239566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints));
12249566063dSJacob Faibussowitsch     PetscCall(PetscSectionAddDof(rootSection, neighbors[n], numPoints));
12251fd9873aSMichael Lange   }
12269566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootSection));
12279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(rootSection, &rootSize));
12289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rootSize, &rootPoints));
12299566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote));
12301fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
12311fd9873aSMichael Lange     IS              pointIS;
12321fd9873aSMichael Lange     const PetscInt *points;
12331fd9873aSMichael Lange 
12349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(rootSection, neighbors[n], &off));
12359566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS));
12369566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
12379566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
12381fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
12399566063dSJacob Faibussowitsch       if (local) PetscCall(PetscFindInt(points[p], nleaves, local, &l));
1240f8987ae8SMichael Lange       else { l = -1; }
12419371c9d4SSatish Balay       if (l >= 0) {
12429371c9d4SSatish Balay         rootPoints[off + p] = remote[l];
12439371c9d4SSatish Balay       } else {
12449371c9d4SSatish Balay         rootPoints[off + p].index = points[p];
12459371c9d4SSatish Balay         rootPoints[off + p].rank  = rank;
12469371c9d4SSatish Balay       }
12471fd9873aSMichael Lange     }
12489566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
12499566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
12501fd9873aSMichael Lange   }
1251874ddda9SLisandro Dalcin 
1252874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
1253874ddda9SLisandro Dalcin   if (!processSF) {
1254874ddda9SLisandro Dalcin     PetscInt64   counter     = 0;
1255874ddda9SLisandro Dalcin     PetscBool    locOverflow = PETSC_FALSE;
1256874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
1257874ddda9SLisandro Dalcin 
12589566063dSJacob Faibussowitsch     PetscCall(PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls));
1259874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
12609566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootSection, neighbors[n], &dof));
12619566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootSection, neighbors[n], &off));
1262874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
12639371c9d4SSatish Balay       if (dof > PETSC_MPI_INT_MAX) {
12649371c9d4SSatish Balay         locOverflow = PETSC_TRUE;
12659371c9d4SSatish Balay         break;
12669371c9d4SSatish Balay       }
12679371c9d4SSatish Balay       if (off > PETSC_MPI_INT_MAX) {
12689371c9d4SSatish Balay         locOverflow = PETSC_TRUE;
12699371c9d4SSatish Balay         break;
12709371c9d4SSatish Balay       }
1271874ddda9SLisandro Dalcin #endif
1272874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt)dof;
1273874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt)off;
1274874ddda9SLisandro Dalcin     }
12759566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm));
12769371c9d4SSatish Balay     for (r = 0; r < size; ++r) {
12779371c9d4SSatish Balay       rdispls[r] = (int)counter;
12789371c9d4SSatish Balay       counter += rcounts[r];
12799371c9d4SSatish Balay     }
1280874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
12819566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm));
1282874ddda9SLisandro Dalcin     if (!mpiOverflow) {
12839566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Using Alltoallv for mesh distribution\n"));
1284874ddda9SLisandro Dalcin       leafSize = (PetscInt)counter;
12859566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(leafSize, &leafPoints));
12869566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm));
1287874ddda9SLisandro Dalcin     }
12889566063dSJacob Faibussowitsch     PetscCall(PetscFree4(scounts, sdispls, rcounts, rdispls));
1289874ddda9SLisandro Dalcin   }
1290874ddda9SLisandro Dalcin 
1291874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
1292874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
1293874ddda9SLisandro Dalcin     PetscSF      procSF;
1294874ddda9SLisandro Dalcin     PetscSection leafSection;
1295874ddda9SLisandro Dalcin 
1296874ddda9SLisandro Dalcin     if (processSF) {
12979566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Using processSF for mesh distribution\n"));
12989566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)processSF));
1299874ddda9SLisandro Dalcin       procSF = processSF;
1300874ddda9SLisandro Dalcin     } else {
13019566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Using processSF for mesh distribution (MPI overflow)\n"));
13029566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, &procSF));
13039566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphWithPattern(procSF, NULL, PETSCSF_PATTERN_ALLTOALL));
1304874ddda9SLisandro Dalcin     }
1305874ddda9SLisandro Dalcin 
13069566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection));
13079566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeData(dm, procSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void **)&leafPoints));
13089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafSection, &leafSize));
13099566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
13109566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&procSF));
1311874ddda9SLisandro Dalcin   }
1312874ddda9SLisandro Dalcin 
1313*48a46eb9SPierre Jolivet   for (p = 0; p < leafSize; p++) PetscCall(DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank));
1314874ddda9SLisandro Dalcin 
13159566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(valueIS, &neighbors));
13169566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&valueIS));
13179566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootSection));
13189566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootPoints));
13199566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafPoints));
13209566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_PartLabelInvert, dm, 0, 0, 0));
13211fd9873aSMichael Lange   PetscFunctionReturn(0);
13221fd9873aSMichael Lange }
13231fd9873aSMichael Lange 
1324aa3148a8SMichael Lange /*@
1325aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
1326aa3148a8SMichael Lange 
1327aa3148a8SMichael Lange   Input Parameters:
1328aa3148a8SMichael Lange + dm    - The DM
1329a5b23f4aSJose E. Roman - label - DMLabel assigning ranks to remote roots
1330aa3148a8SMichael Lange 
1331aa3148a8SMichael Lange   Output Parameter:
1332fe2efc57SMark . sf    - The star forest communication context encapsulating the defined mapping
1333aa3148a8SMichael Lange 
1334aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
1335aa3148a8SMichael Lange 
1336aa3148a8SMichael Lange   Level: developer
1337aa3148a8SMichael Lange 
1338db781477SPatrick Sanan .seealso: `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1339aa3148a8SMichael Lange @*/
13409371c9d4SSatish Balay PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf) {
13416e203dd9SStefano Zampini   PetscMPIInt     rank;
13426e203dd9SStefano Zampini   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
1343aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
13446e203dd9SStefano Zampini   IS              remoteRootIS, neighborsIS;
13456e203dd9SStefano Zampini   const PetscInt *remoteRoots, *neighbors;
1346aa3148a8SMichael Lange 
1347aa3148a8SMichael Lange   PetscFunctionBegin;
13489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_PartLabelCreateSF, dm, 0, 0, 0));
13499566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1350aa3148a8SMichael Lange 
13519566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &neighborsIS));
13526e203dd9SStefano Zampini #if 0
13536e203dd9SStefano Zampini   {
13546e203dd9SStefano Zampini     IS is;
13559566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(neighborsIS, &is));
13569566063dSJacob Faibussowitsch     PetscCall(ISSort(is));
13579566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&neighborsIS));
13586e203dd9SStefano Zampini     neighborsIS = is;
13596e203dd9SStefano Zampini   }
13606e203dd9SStefano Zampini #endif
13619566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(neighborsIS, &nNeighbors));
13629566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(neighborsIS, &neighbors));
13636e203dd9SStefano Zampini   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
13649566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(label, neighbors[n], &numPoints));
1365aa3148a8SMichael Lange     numRemote += numPoints;
1366aa3148a8SMichael Lange   }
13679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRemote, &remotePoints));
136843f7d02bSMichael Lange   /* Put owned points first */
13699566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumSize(label, rank, &numPoints));
137043f7d02bSMichael Lange   if (numPoints > 0) {
13719566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &remoteRootIS));
13729566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(remoteRootIS, &remoteRoots));
137343f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
137443f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
137543f7d02bSMichael Lange       remotePoints[idx].rank  = rank;
137643f7d02bSMichael Lange       idx++;
137743f7d02bSMichael Lange     }
13789566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(remoteRootIS, &remoteRoots));
13799566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&remoteRootIS));
138043f7d02bSMichael Lange   }
138143f7d02bSMichael Lange   /* Now add remote points */
13826e203dd9SStefano Zampini   for (n = 0; n < nNeighbors; ++n) {
13836e203dd9SStefano Zampini     const PetscInt nn = neighbors[n];
13846e203dd9SStefano Zampini 
13859566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(label, nn, &numPoints));
13866e203dd9SStefano Zampini     if (nn == rank || numPoints <= 0) continue;
13879566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, nn, &remoteRootIS));
13889566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(remoteRootIS, &remoteRoots));
1389aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
1390aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
13916e203dd9SStefano Zampini       remotePoints[idx].rank  = nn;
1392aa3148a8SMichael Lange       idx++;
1393aa3148a8SMichael Lange     }
13949566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(remoteRootIS, &remoteRoots));
13959566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&remoteRootIS));
1396aa3148a8SMichael Lange   }
13979566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), sf));
13989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
13999566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, pEnd - pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER));
14009566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(*sf));
14019566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&neighborsIS));
14029566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_PartLabelCreateSF, dm, 0, 0, 0));
140370034214SMatthew G. Knepley   PetscFunctionReturn(0);
140470034214SMatthew G. Knepley }
1405cb87ef4cSFlorian Wechsung 
1406abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PARMETIS)
1407abe9303eSLisandro Dalcin #include <parmetis.h>
1408abe9303eSLisandro Dalcin #endif
1409abe9303eSLisandro Dalcin 
14106a3739e5SFlorian Wechsung /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
14116a3739e5SFlorian Wechsung  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
14126a3739e5SFlorian Wechsung  * them out in that case. */
14136a3739e5SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
14147a82c785SFlorian Wechsung /*@C
14157f57c1a4SFlorian Wechsung 
14167f57c1a4SFlorian Wechsung   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).
14177f57c1a4SFlorian Wechsung 
14187f57c1a4SFlorian Wechsung   Input parameters:
14197f57c1a4SFlorian Wechsung + dm                - The DMPlex object.
1420fe2efc57SMark . n                 - The number of points.
1421fe2efc57SMark . pointsToRewrite   - The points in the SF whose ownership will change.
1422fe2efc57SMark . targetOwners      - New owner for each element in pointsToRewrite.
1423fe2efc57SMark - degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.
14247f57c1a4SFlorian Wechsung 
14257f57c1a4SFlorian Wechsung   Level: developer
14267f57c1a4SFlorian Wechsung 
14277f57c1a4SFlorian Wechsung @*/
14289371c9d4SSatish Balay static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees) {
14295f80ce2aSJacob Faibussowitsch   PetscInt           pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
14307f57c1a4SFlorian Wechsung   PetscInt          *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
14317f57c1a4SFlorian Wechsung   PetscSFNode       *leafLocationsNew;
14327f57c1a4SFlorian Wechsung   const PetscSFNode *iremote;
14337f57c1a4SFlorian Wechsung   const PetscInt    *ilocal;
14347f57c1a4SFlorian Wechsung   PetscBool         *isLeaf;
14357f57c1a4SFlorian Wechsung   PetscSF            sf;
14367f57c1a4SFlorian Wechsung   MPI_Comm           comm;
14375a30b08bSFlorian Wechsung   PetscMPIInt        rank, size;
14387f57c1a4SFlorian Wechsung 
14397f57c1a4SFlorian Wechsung   PetscFunctionBegin;
14409566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
14419566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
14429566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
14439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
14447f57c1a4SFlorian Wechsung 
14459566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
14469566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
14479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isLeaf));
14489371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++) { isLeaf[i] = PETSC_FALSE; }
14499371c9d4SSatish Balay   for (i = 0; i < nleafs; i++) { isLeaf[ilocal[i] - pStart] = PETSC_TRUE; }
14507f57c1a4SFlorian Wechsung 
14519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart + 1, &cumSumDegrees));
14527f57c1a4SFlorian Wechsung   cumSumDegrees[0] = 0;
14539371c9d4SSatish Balay   for (i = 1; i <= pEnd - pStart; i++) { cumSumDegrees[i] = cumSumDegrees[i - 1] + degrees[i - 1]; }
14547f57c1a4SFlorian Wechsung   sumDegrees = cumSumDegrees[pEnd - pStart];
14557f57c1a4SFlorian Wechsung   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
14567f57c1a4SFlorian Wechsung 
14579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(sumDegrees, &locationsOfLeafs));
14589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &rankOnLeafs));
14599371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++) { rankOnLeafs[i] = rank; }
14609566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
14619566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
14629566063dSJacob Faibussowitsch   PetscCall(PetscFree(rankOnLeafs));
14637f57c1a4SFlorian Wechsung 
14647f57c1a4SFlorian Wechsung   /* get the remote local points of my leaves */
14659566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs));
14669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &points));
14679371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++) { points[i] = pStart + i; }
14689566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
14699566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
14709566063dSJacob Faibussowitsch   PetscCall(PetscFree(points));
14717f57c1a4SFlorian Wechsung   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
14729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &newOwners));
14739566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &newNumbers));
14747f57c1a4SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
14757f57c1a4SFlorian Wechsung     newOwners[i]  = -1;
14767f57c1a4SFlorian Wechsung     newNumbers[i] = -1;
14777f57c1a4SFlorian Wechsung   }
14787f57c1a4SFlorian Wechsung   {
14797f57c1a4SFlorian Wechsung     PetscInt oldNumber, newNumber, oldOwner, newOwner;
14807f57c1a4SFlorian Wechsung     for (i = 0; i < n; i++) {
14817f57c1a4SFlorian Wechsung       oldNumber = pointsToRewrite[i];
14827f57c1a4SFlorian Wechsung       newNumber = -1;
14837f57c1a4SFlorian Wechsung       oldOwner  = rank;
14847f57c1a4SFlorian Wechsung       newOwner  = targetOwners[i];
14857f57c1a4SFlorian Wechsung       if (oldOwner == newOwner) {
14867f57c1a4SFlorian Wechsung         newNumber = oldNumber;
14877f57c1a4SFlorian Wechsung       } else {
14887f57c1a4SFlorian Wechsung         for (j = 0; j < degrees[oldNumber]; j++) {
14897f57c1a4SFlorian Wechsung           if (locationsOfLeafs[cumSumDegrees[oldNumber] + j] == newOwner) {
14907f57c1a4SFlorian Wechsung             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber] + j];
14917f57c1a4SFlorian Wechsung             break;
14927f57c1a4SFlorian Wechsung           }
14937f57c1a4SFlorian Wechsung         }
14947f57c1a4SFlorian Wechsung       }
14955f80ce2aSJacob Faibussowitsch       PetscCheck(newNumber != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
14967f57c1a4SFlorian Wechsung 
14977f57c1a4SFlorian Wechsung       newOwners[oldNumber]  = newOwner;
14987f57c1a4SFlorian Wechsung       newNumbers[oldNumber] = newNumber;
14997f57c1a4SFlorian Wechsung     }
15007f57c1a4SFlorian Wechsung   }
15019566063dSJacob Faibussowitsch   PetscCall(PetscFree(cumSumDegrees));
15029566063dSJacob Faibussowitsch   PetscCall(PetscFree(locationsOfLeafs));
15039566063dSJacob Faibussowitsch   PetscCall(PetscFree(remoteLocalPointOfLeafs));
15047f57c1a4SFlorian Wechsung 
15059566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners, MPI_REPLACE));
15069566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners, MPI_REPLACE));
15079566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers, MPI_REPLACE));
15089566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers, MPI_REPLACE));
15097f57c1a4SFlorian Wechsung 
15107f57c1a4SFlorian Wechsung   /* Now count how many leafs we have on each processor. */
15117f57c1a4SFlorian Wechsung   leafCounter = 0;
15127f57c1a4SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
15137f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
15149371c9d4SSatish Balay       if (newOwners[i] != rank) { leafCounter++; }
15157f57c1a4SFlorian Wechsung     } else {
15169371c9d4SSatish Balay       if (isLeaf[i]) { leafCounter++; }
15177f57c1a4SFlorian Wechsung     }
15187f57c1a4SFlorian Wechsung   }
15197f57c1a4SFlorian Wechsung 
15207f57c1a4SFlorian Wechsung   /* Now set up the new sf by creating the leaf arrays */
15219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(leafCounter, &leafsNew));
15229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(leafCounter, &leafLocationsNew));
15237f57c1a4SFlorian Wechsung 
15247f57c1a4SFlorian Wechsung   leafCounter = 0;
15257f57c1a4SFlorian Wechsung   counter     = 0;
15267f57c1a4SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
15277f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
15287f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
15297f57c1a4SFlorian Wechsung         leafsNew[leafCounter]               = i;
15307f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank  = newOwners[i];
15317f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = newNumbers[i];
15327f57c1a4SFlorian Wechsung         leafCounter++;
15337f57c1a4SFlorian Wechsung       }
15347f57c1a4SFlorian Wechsung     } else {
15357f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
15367f57c1a4SFlorian Wechsung         leafsNew[leafCounter]               = i;
15377f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank  = iremote[counter].rank;
15387f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = iremote[counter].index;
15397f57c1a4SFlorian Wechsung         leafCounter++;
15407f57c1a4SFlorian Wechsung       }
15417f57c1a4SFlorian Wechsung     }
15429371c9d4SSatish Balay     if (isLeaf[i]) { counter++; }
15437f57c1a4SFlorian Wechsung   }
15447f57c1a4SFlorian Wechsung 
15459566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER));
15469566063dSJacob Faibussowitsch   PetscCall(PetscFree(newOwners));
15479566063dSJacob Faibussowitsch   PetscCall(PetscFree(newNumbers));
15489566063dSJacob Faibussowitsch   PetscCall(PetscFree(isLeaf));
15497f57c1a4SFlorian Wechsung   PetscFunctionReturn(0);
15507f57c1a4SFlorian Wechsung }
15517f57c1a4SFlorian Wechsung 
15529371c9d4SSatish Balay static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer) {
15535f80ce2aSJacob Faibussowitsch   PetscInt   *distribution, min, max, sum;
15545a30b08bSFlorian Wechsung   PetscMPIInt rank, size;
15555f80ce2aSJacob Faibussowitsch 
1556125d2a8fSFlorian Wechsung   PetscFunctionBegin;
15579566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
15589566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
15599566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &distribution));
15605f80ce2aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; i++) {
1561125d2a8fSFlorian Wechsung     if (part) distribution[part[i]] += vtxwgt[skip * i];
1562125d2a8fSFlorian Wechsung     else distribution[rank] += vtxwgt[skip * i];
1563125d2a8fSFlorian Wechsung   }
15649566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm));
1565125d2a8fSFlorian Wechsung   min = distribution[0];
1566125d2a8fSFlorian Wechsung   max = distribution[0];
1567125d2a8fSFlorian Wechsung   sum = distribution[0];
15685f80ce2aSJacob Faibussowitsch   for (PetscInt i = 1; i < size; i++) {
1569125d2a8fSFlorian Wechsung     if (distribution[i] < min) min = distribution[i];
1570125d2a8fSFlorian Wechsung     if (distribution[i] > max) max = distribution[i];
1571125d2a8fSFlorian Wechsung     sum += distribution[i];
1572125d2a8fSFlorian Wechsung   }
157363a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "Min: %" PetscInt_FMT ", Avg: %" PetscInt_FMT ", Max: %" PetscInt_FMT ", Balance: %f\n", min, sum / size, max, (max * 1. * size) / sum));
15749566063dSJacob Faibussowitsch   PetscCall(PetscFree(distribution));
1575125d2a8fSFlorian Wechsung   PetscFunctionReturn(0);
1576125d2a8fSFlorian Wechsung }
1577125d2a8fSFlorian Wechsung 
15786a3739e5SFlorian Wechsung #endif
15796a3739e5SFlorian Wechsung 
1580cb87ef4cSFlorian Wechsung /*@
15815dc86ac1SFlorian 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.
1582cb87ef4cSFlorian Wechsung 
1583cb87ef4cSFlorian Wechsung   Input parameters:
1584ed44d270SFlorian Wechsung + dm               - The DMPlex object.
1585fe2efc57SMark . entityDepth      - depth of the entity to balance (0 -> balance vertices).
1586fe2efc57SMark . useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
1587fe2efc57SMark - parallel         - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.
1588cb87ef4cSFlorian Wechsung 
15898b879b41SFlorian Wechsung   Output parameters:
1590252a1336SBarry Smith . success          - whether the graph partitioning was successful or not, optional. Unsuccessful simply means no change to the partitioning
1591252a1336SBarry Smith 
1592252a1336SBarry Smith   Options Database:
1593252a1336SBarry Smith +  -dm_plex_rebalance_shared_points_parmetis - Use ParMetis instead of Metis for the partitioner
1594252a1336SBarry Smith .  -dm_plex_rebalance_shared_points_use_initial_guess - Use current partition to bootstrap ParMetis partition
1595252a1336SBarry Smith .  -dm_plex_rebalance_shared_points_use_mat_partitioning - Use the MatPartitioning object to perform the partition, the prefix for those operations is -dm_plex_rebalance_shared_points_
1596252a1336SBarry Smith -  -dm_plex_rebalance_shared_points_monitor - Monitor the shared points rebalance process
1597252a1336SBarry Smith 
1598252a1336SBarry Smith   Developer Notes:
1599252a1336SBarry Smith   This should use MatPartitioning to allow the use of any partitioner and not be hardwired to use ParMetis
16008b879b41SFlorian Wechsung 
160190ea27d8SSatish Balay   Level: intermediate
1602cb87ef4cSFlorian Wechsung @*/
16039371c9d4SSatish Balay PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success) {
160441525646SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
1605cb87ef4cSFlorian Wechsung   PetscSF            sf;
16060faf6628SFlorian Wechsung   PetscInt           ierr, i, j, idx, jdx;
16077f57c1a4SFlorian Wechsung   PetscInt           eBegin, eEnd, nroots, nleafs, pStart, pEnd;
16087f57c1a4SFlorian Wechsung   const PetscInt    *degrees, *ilocal;
16097f57c1a4SFlorian Wechsung   const PetscSFNode *iremote;
1610cb87ef4cSFlorian Wechsung   PetscBool         *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
1611cf818975SFlorian Wechsung   PetscInt           numExclusivelyOwned, numNonExclusivelyOwned;
1612cb87ef4cSFlorian Wechsung   PetscMPIInt        rank, size;
16137f57c1a4SFlorian Wechsung   PetscInt          *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
16145dc86ac1SFlorian Wechsung   const PetscInt    *cumSumVertices;
1615cb87ef4cSFlorian Wechsung   PetscInt           offset, counter;
1616252a1336SBarry Smith   PetscInt          *vtxwgt;
1617252a1336SBarry Smith   const PetscInt    *xadj, *adjncy;
1618cb87ef4cSFlorian Wechsung   PetscInt          *part, *options;
1619cf818975SFlorian Wechsung   PetscInt           nparts, wgtflag, numflag, ncon, edgecut;
1620cb87ef4cSFlorian Wechsung   real_t            *ubvec;
1621cb87ef4cSFlorian Wechsung   PetscInt          *firstVertices, *renumbering;
1622cb87ef4cSFlorian Wechsung   PetscInt           failed, failedGlobal;
1623cb87ef4cSFlorian Wechsung   MPI_Comm           comm;
1624252a1336SBarry Smith   Mat                A;
16257d197802SFlorian Wechsung   PetscViewer        viewer;
16267d197802SFlorian Wechsung   PetscViewerFormat  format;
16275a30b08bSFlorian Wechsung   PetscLayout        layout;
1628252a1336SBarry Smith   real_t            *tpwgts;
1629252a1336SBarry Smith   PetscMPIInt       *counts, *mpiCumSumVertices;
1630252a1336SBarry Smith   PetscInt          *pointsToRewrite;
1631252a1336SBarry Smith   PetscInt           numRows;
1632252a1336SBarry Smith   PetscBool          done, usematpartitioning = PETSC_FALSE;
1633252a1336SBarry Smith   IS                 ispart = NULL;
1634252a1336SBarry Smith   MatPartitioning    mp;
1635252a1336SBarry Smith   const char        *prefix;
163612617df9SFlorian Wechsung 
163712617df9SFlorian Wechsung   PetscFunctionBegin;
16389566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
16399566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
1640252a1336SBarry Smith   if (size == 1) {
1641252a1336SBarry Smith     if (success) *success = PETSC_TRUE;
1642252a1336SBarry Smith     PetscFunctionReturn(0);
1643252a1336SBarry Smith   }
1644252a1336SBarry Smith   if (success) *success = PETSC_FALSE;
1645252a1336SBarry Smith   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1646252a1336SBarry Smith 
1647252a1336SBarry Smith   parallel        = PETSC_FALSE;
1648252a1336SBarry Smith   useInitialGuess = PETSC_FALSE;
1649252a1336SBarry Smith   PetscObjectOptionsBegin((PetscObject)dm);
1650252a1336SBarry Smith   PetscCall(PetscOptionsName("-dm_plex_rebalance_shared_points_parmetis", "Use ParMetis instead of Metis for the partitioner", "DMPlexRebalanceSharedPoints", &parallel));
1651252a1336SBarry Smith   PetscCall(PetscOptionsBool("-dm_plex_rebalance_shared_points_use_initial_guess", "Use current partition to bootstrap ParMetis partition", "DMPlexRebalanceSharedPoints", useInitialGuess, &useInitialGuess, NULL));
1652252a1336SBarry Smith   PetscCall(PetscOptionsBool("-dm_plex_rebalance_shared_points_use_mat_partitioning", "Use the MatPartitioning object to partition", "DMPlexRebalanceSharedPoints", usematpartitioning, &usematpartitioning, NULL));
1653252a1336SBarry Smith   PetscCall(PetscOptionsViewer("-dm_plex_rebalance_shared_points_monitor", "Monitor the shared points rebalance process", "DMPlexRebalanceSharedPoints", &viewer, &format, NULL));
1654252a1336SBarry Smith   PetscOptionsEnd();
1655252a1336SBarry Smith   if (viewer) PetscCall(PetscViewerPushFormat(viewer, format));
16567f57c1a4SFlorian Wechsung 
16579566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
165841525646SFlorian Wechsung 
1659252a1336SBarry Smith   PetscCall(DMGetOptionsPrefix(dm, &prefix));
16609566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, ((PetscObject)dm)->options, prefix, "-dm_rebalance_partition_view", &viewer, &format, NULL));
16611baa6e33SBarry Smith   if (viewer) PetscCall(PetscViewerPushFormat(viewer, format));
16627d197802SFlorian Wechsung 
1663ed44d270SFlorian Wechsung   /* Figure out all points in the plex that we are interested in balancing. */
16649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd));
16659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
16669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &toBalance));
16679371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++) { toBalance[i] = (PetscBool)(i >= eBegin && i < eEnd); }
1668cb87ef4cSFlorian Wechsung 
1669cf818975SFlorian Wechsung   /* There are three types of points:
1670cf818975SFlorian Wechsung    * exclusivelyOwned: points that are owned by this process and only seen by this process
1671cf818975SFlorian Wechsung    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
1672cf818975SFlorian Wechsung    * leaf: a point that is seen by this process but owned by a different process
1673cf818975SFlorian Wechsung    */
16749566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
16759566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
16769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isLeaf));
16779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isNonExclusivelyOwned));
16789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isExclusivelyOwned));
1679cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1680cb87ef4cSFlorian Wechsung     isNonExclusivelyOwned[i] = PETSC_FALSE;
1681cb87ef4cSFlorian Wechsung     isExclusivelyOwned[i]    = PETSC_FALSE;
1682cf818975SFlorian Wechsung     isLeaf[i]                = PETSC_FALSE;
1683cb87ef4cSFlorian Wechsung   }
1684cf818975SFlorian Wechsung 
1685252a1336SBarry Smith   /* mark all the leafs */
16869371c9d4SSatish Balay   for (i = 0; i < nleafs; i++) { isLeaf[ilocal[i] - pStart] = PETSC_TRUE; }
1687cb87ef4cSFlorian Wechsung 
1688cf818975SFlorian Wechsung   /* for an owned point, we can figure out whether another processor sees it or
1689cf818975SFlorian Wechsung    * not by calculating its degree */
16909566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(sf, &degrees));
16919566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(sf, &degrees));
1692cb87ef4cSFlorian Wechsung   numExclusivelyOwned    = 0;
1693cb87ef4cSFlorian Wechsung   numNonExclusivelyOwned = 0;
1694cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1695cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
16967f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1697cb87ef4cSFlorian Wechsung         isNonExclusivelyOwned[i] = PETSC_TRUE;
1698cb87ef4cSFlorian Wechsung         numNonExclusivelyOwned += 1;
1699cb87ef4cSFlorian Wechsung       } else {
1700cb87ef4cSFlorian Wechsung         if (!isLeaf[i]) {
1701cb87ef4cSFlorian Wechsung           isExclusivelyOwned[i] = PETSC_TRUE;
1702cb87ef4cSFlorian Wechsung           numExclusivelyOwned += 1;
1703cb87ef4cSFlorian Wechsung         }
1704cb87ef4cSFlorian Wechsung       }
1705cb87ef4cSFlorian Wechsung     }
1706cb87ef4cSFlorian Wechsung   }
1707cb87ef4cSFlorian Wechsung 
1708252a1336SBarry Smith   /* Build a graph with one vertex per core representing the
1709cf818975SFlorian Wechsung    * exclusively owned points and then one vertex per nonExclusively owned
1710cf818975SFlorian Wechsung    * point. */
17119566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &layout));
17129566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned));
17139566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
17149566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRanges(layout, &cumSumVertices));
17159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &globalNumbersOfLocalOwnedVertices));
17165a427404SJunchao Zhang   for (i = 0; i < pEnd - pStart; i++) { globalNumbersOfLocalOwnedVertices[i] = pStart - 1; }
1717cb87ef4cSFlorian Wechsung   offset  = cumSumVertices[rank];
1718cb87ef4cSFlorian Wechsung   counter = 0;
1719cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1720cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
17217f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1722cb87ef4cSFlorian Wechsung         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
1723cb87ef4cSFlorian Wechsung         counter++;
1724cb87ef4cSFlorian Wechsung       }
1725cb87ef4cSFlorian Wechsung     }
1726cb87ef4cSFlorian Wechsung   }
1727cb87ef4cSFlorian Wechsung 
1728cb87ef4cSFlorian Wechsung   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
17299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &leafGlobalNumbers));
17309566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers, MPI_REPLACE));
17319566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers, MPI_REPLACE));
1732cb87ef4cSFlorian Wechsung 
1733252a1336SBarry Smith   /* Build the graph for partitioning */
1734252a1336SBarry Smith   numRows = 1 + numNonExclusivelyOwned;
1735252a1336SBarry Smith   PetscCall(PetscLogEventBegin(DMPLEX_RebalBuildGraph, dm, 0, 0, 0));
17369566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
1737252a1336SBarry Smith   PetscCall(MatSetType(A, MATMPIADJ));
1738252a1336SBarry Smith   PetscCall(MatSetSizes(A, numRows, numRows, cumSumVertices[size], cumSumVertices[size]));
1739252a1336SBarry Smith   idx = cumSumVertices[rank];
17404baf1206SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
17414baf1206SFlorian Wechsung     if (toBalance[i]) {
17420faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
17430faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
17440faf6628SFlorian Wechsung       else continue;
17459566063dSJacob Faibussowitsch       PetscCall(MatSetValue(A, idx, jdx, 1, INSERT_VALUES));
17469566063dSJacob Faibussowitsch       PetscCall(MatSetValue(A, jdx, idx, 1, INSERT_VALUES));
17470941debbSFlorian Wechsung     }
17480941debbSFlorian Wechsung   }
1749252a1336SBarry Smith   PetscCall(PetscFree(globalNumbersOfLocalOwnedVertices));
1750252a1336SBarry Smith   PetscCall(PetscFree(leafGlobalNumbers));
17519566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
17529566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1753252a1336SBarry Smith   PetscCall(PetscLogEventEnd(DMPLEX_RebalBuildGraph, dm, 0, 0, 0));
17544baf1206SFlorian Wechsung 
175541525646SFlorian Wechsung   nparts = size;
1756252a1336SBarry Smith   ncon   = 1;
17579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon * nparts, &tpwgts));
17589371c9d4SSatish Balay   for (i = 0; i < ncon * nparts; i++) { tpwgts[i] = 1. / (nparts); }
17599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon, &ubvec));
1760252a1336SBarry Smith   ubvec[0] = 1.05;
1761252a1336SBarry Smith   ubvec[1] = 1.05;
17628c9a1619SFlorian Wechsung 
17639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon * (1 + numNonExclusivelyOwned), &vtxwgt));
1764252a1336SBarry Smith   if (ncon == 2) {
176541525646SFlorian Wechsung     vtxwgt[0] = numExclusivelyOwned;
1766252a1336SBarry Smith     vtxwgt[1] = 1;
176741525646SFlorian Wechsung     for (i = 0; i < numNonExclusivelyOwned; i++) {
176841525646SFlorian Wechsung       vtxwgt[ncon * (i + 1)]     = 1;
1769252a1336SBarry Smith       vtxwgt[ncon * (i + 1) + 1] = 0;
1770252a1336SBarry Smith     }
1771252a1336SBarry Smith   } else {
1772252a1336SBarry Smith     PetscInt base, ms;
1773252a1336SBarry Smith     PetscCallMPI(MPI_Allreduce(&numExclusivelyOwned, &base, 1, MPIU_INT, MPIU_MAX, PetscObjectComm((PetscObject)dm)));
1774252a1336SBarry Smith     PetscCall(MatGetSize(A, &ms, NULL));
1775252a1336SBarry Smith     ms -= size;
1776252a1336SBarry Smith     base      = PetscMax(base, ms);
1777252a1336SBarry Smith     vtxwgt[0] = base + numExclusivelyOwned;
17789371c9d4SSatish Balay     for (i = 0; i < numNonExclusivelyOwned; i++) { vtxwgt[i + 1] = 1; }
177941525646SFlorian Wechsung   }
17808c9a1619SFlorian Wechsung 
17815dc86ac1SFlorian Wechsung   if (viewer) {
178263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %" PetscInt_FMT " on interface of mesh distribution.\n", entityDepth));
178363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %" PetscInt_FMT "\n", cumSumVertices[size]));
178412617df9SFlorian Wechsung   }
1785252a1336SBarry Smith   /* TODO: Drop the parallel/sequential choice here and just use MatPartioner for much more flexibility */
1786252a1336SBarry Smith   if (usematpartitioning) {
1787252a1336SBarry Smith     const char *prefix;
1788252a1336SBarry Smith 
1789252a1336SBarry Smith     PetscCall(MatPartitioningCreate(PetscObjectComm((PetscObject)dm), &mp));
1790252a1336SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mp, "dm_plex_rebalance_shared_points_"));
1791252a1336SBarry Smith     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
1792252a1336SBarry Smith     PetscCall(PetscObjectPrependOptionsPrefix((PetscObject)mp, prefix));
1793252a1336SBarry Smith     PetscCall(MatPartitioningSetAdjacency(mp, A));
1794252a1336SBarry Smith     PetscCall(MatPartitioningSetNumberVertexWeights(mp, ncon));
1795252a1336SBarry Smith     PetscCall(MatPartitioningSetVertexWeights(mp, vtxwgt));
1796252a1336SBarry Smith     PetscCall(MatPartitioningSetFromOptions(mp));
1797252a1336SBarry Smith     PetscCall(MatPartitioningApply(mp, &ispart));
1798252a1336SBarry Smith     PetscCall(ISGetIndices(ispart, (const PetscInt **)&part));
1799252a1336SBarry Smith   } else if (parallel) {
1800252a1336SBarry Smith     if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n"));
1801252a1336SBarry Smith     PetscCall(PetscMalloc1(cumSumVertices[rank + 1] - cumSumVertices[rank], &part));
1802252a1336SBarry Smith     PetscCall(MatGetRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, &xadj, &adjncy, &done));
1803252a1336SBarry Smith     PetscCheck(done, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Could not get adjacency information");
18049566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(4, &options));
18055a30b08bSFlorian Wechsung     options[0] = 1;
18065a30b08bSFlorian Wechsung     options[1] = 0; /* Verbosity */
1807252a1336SBarry Smith     if (viewer) options[1] = 1;
18085a30b08bSFlorian Wechsung     options[2] = 0;                    /* Seed */
18095a30b08bSFlorian Wechsung     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
1810252a1336SBarry Smith     wgtflag    = 2;
1811252a1336SBarry Smith     numflag    = 0;
18128c9a1619SFlorian Wechsung     if (useInitialGuess) {
1813252a1336SBarry Smith       PetscCall(PetscViewerASCIIPrintf(viewer, "THIS DOES NOT WORK! I don't know why. Using current distribution of points as initial guess.\n"));
1814252a1336SBarry Smith       for (i = 0; i < numRows; i++) part[i] = rank;
18159566063dSJacob Faibussowitsch       if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n"));
1816792fecdfSBarry Smith       PetscStackPushExternal("ParMETIS_V3_RefineKway");
1817252a1336SBarry Smith       PetscCall(PetscLogEventBegin(DMPLEX_RebalPartition, 0, 0, 0, 0));
1818252a1336SBarry Smith       ierr = ParMETIS_V3_RefineKway((PetscInt *)cumSumVertices, (idx_t *)xadj, (idx_t *)adjncy, vtxwgt, NULL, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
1819252a1336SBarry Smith       PetscCall(PetscLogEventEnd(DMPLEX_RebalPartition, 0, 0, 0, 0));
18208c9a1619SFlorian Wechsung       PetscStackPop;
1821252a1336SBarry Smith       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
18228c9a1619SFlorian Wechsung     } else {
1823792fecdfSBarry Smith       PetscStackPushExternal("ParMETIS_V3_PartKway");
1824252a1336SBarry Smith       PetscCall(PetscLogEventBegin(DMPLEX_RebalPartition, 0, 0, 0, 0));
1825252a1336SBarry Smith       ierr = ParMETIS_V3_PartKway((PetscInt *)cumSumVertices, (idx_t *)xadj, (idx_t *)adjncy, vtxwgt, NULL, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
1826252a1336SBarry Smith       PetscCall(PetscLogEventEnd(DMPLEX_RebalPartition, 0, 0, 0, 0));
18278c9a1619SFlorian Wechsung       PetscStackPop;
18285f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
18298c9a1619SFlorian Wechsung     }
1830252a1336SBarry Smith     PetscCall(MatRestoreRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, &xadj, &adjncy, &done));
18319566063dSJacob Faibussowitsch     PetscCall(PetscFree(options));
183241525646SFlorian Wechsung   } else {
18339566063dSJacob Faibussowitsch     if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n"));
183441525646SFlorian Wechsung     Mat       As;
183541525646SFlorian Wechsung     PetscInt *partGlobal;
183641525646SFlorian Wechsung     PetscInt *numExclusivelyOwnedAll;
1837252a1336SBarry Smith 
1838252a1336SBarry Smith     PetscCall(PetscMalloc1(cumSumVertices[rank + 1] - cumSumVertices[rank], &part));
1839252a1336SBarry Smith     PetscCall(MatGetSize(A, &numRows, NULL));
1840252a1336SBarry Smith     PetscCall(PetscLogEventBegin(DMPLEX_RebalGatherGraph, dm, 0, 0, 0));
1841252a1336SBarry Smith     PetscCall(MatMPIAdjToSeqRankZero(A, &As));
1842252a1336SBarry Smith     PetscCall(PetscLogEventEnd(DMPLEX_RebalGatherGraph, dm, 0, 0, 0));
1843252a1336SBarry Smith 
18449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &numExclusivelyOwnedAll));
184541525646SFlorian Wechsung     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
18469566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, numExclusivelyOwnedAll, 1, MPIU_INT, comm));
1847cb87ef4cSFlorian Wechsung 
18489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRows, &partGlobal));
1849252a1336SBarry Smith     PetscCall(PetscLogEventBegin(DMPLEX_RebalPartition, 0, 0, 0, 0));
1850dd400576SPatrick Sanan     if (rank == 0) {
1851252a1336SBarry Smith       PetscInt *vtxwgt_g, numRows_g;
185241525646SFlorian Wechsung 
1853252a1336SBarry Smith       PetscCall(MatGetRowIJ(As, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows_g, &xadj, &adjncy, &done));
1854252a1336SBarry Smith       PetscCall(PetscMalloc1(2 * numRows_g, &vtxwgt_g));
185541525646SFlorian Wechsung       for (i = 0; i < size; i++) {
185641525646SFlorian Wechsung         vtxwgt_g[ncon * cumSumVertices[i]] = numExclusivelyOwnedAll[i];
185741525646SFlorian Wechsung         if (ncon > 1) vtxwgt_g[ncon * cumSumVertices[i] + 1] = 1;
185841525646SFlorian Wechsung         for (j = cumSumVertices[i] + 1; j < cumSumVertices[i + 1]; j++) {
185941525646SFlorian Wechsung           vtxwgt_g[ncon * j] = 1;
186041525646SFlorian Wechsung           if (ncon > 1) vtxwgt_g[2 * j + 1] = 0;
186141525646SFlorian Wechsung         }
186241525646SFlorian Wechsung       }
1863252a1336SBarry Smith 
18649566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(64, &options));
186541525646SFlorian Wechsung       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
18665f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
186741525646SFlorian Wechsung       options[METIS_OPTION_CONTIG] = 1;
1868792fecdfSBarry Smith       PetscStackPushExternal("METIS_PartGraphKway");
1869252a1336SBarry Smith       ierr = METIS_PartGraphKway(&numRows_g, &ncon, (idx_t *)xadj, (idx_t *)adjncy, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
187041525646SFlorian Wechsung       PetscStackPop;
18715f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
18729566063dSJacob Faibussowitsch       PetscCall(PetscFree(options));
18739566063dSJacob Faibussowitsch       PetscCall(PetscFree(vtxwgt_g));
1874252a1336SBarry Smith       PetscCall(MatRestoreRowIJ(As, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows_g, &xadj, &adjncy, &done));
1875252a1336SBarry Smith       PetscCall(MatDestroy(&As));
187641525646SFlorian Wechsung     }
1877252a1336SBarry Smith     PetscCall(PetscBarrier((PetscObject)dm));
1878252a1336SBarry Smith     PetscCall(PetscLogEventEnd(DMPLEX_RebalPartition, 0, 0, 0, 0));
18799566063dSJacob Faibussowitsch     PetscCall(PetscFree(numExclusivelyOwnedAll));
188041525646SFlorian Wechsung 
1881252a1336SBarry Smith     /* scatter the partitioning information to ranks */
1882252a1336SBarry Smith     PetscCall(PetscLogEventBegin(DMPLEX_RebalScatterPart, 0, 0, 0, 0));
18839566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &counts));
18849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size + 1, &mpiCumSumVertices));
1885*48a46eb9SPierre Jolivet     for (i = 0; i < size; i++) PetscCall(PetscMPIIntCast(cumSumVertices[i + 1] - cumSumVertices[i], &(counts[i])));
1886*48a46eb9SPierre Jolivet     for (i = 0; i <= size; i++) PetscCall(PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i])));
18879566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm));
18889566063dSJacob Faibussowitsch     PetscCall(PetscFree(counts));
18899566063dSJacob Faibussowitsch     PetscCall(PetscFree(mpiCumSumVertices));
18909566063dSJacob Faibussowitsch     PetscCall(PetscFree(partGlobal));
1891252a1336SBarry Smith     PetscCall(PetscLogEventEnd(DMPLEX_RebalScatterPart, 0, 0, 0, 0));
189241525646SFlorian Wechsung   }
18939566063dSJacob Faibussowitsch   PetscCall(PetscFree(ubvec));
18949566063dSJacob Faibussowitsch   PetscCall(PetscFree(tpwgts));
1895cb87ef4cSFlorian Wechsung 
1896252a1336SBarry Smith   /* Rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
1897252a1336SBarry Smith   PetscCall(PetscMalloc2(size, &firstVertices, size, &renumbering));
1898cb87ef4cSFlorian Wechsung   firstVertices[rank] = part[0];
18999566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, firstVertices, 1, MPIU_INT, comm));
19009371c9d4SSatish Balay   for (i = 0; i < size; i++) { renumbering[firstVertices[i]] = i; }
19019371c9d4SSatish Balay   for (i = 0; i < cumSumVertices[rank + 1] - cumSumVertices[rank]; i++) { part[i] = renumbering[part[i]]; }
1902252a1336SBarry Smith   PetscCall(PetscFree2(firstVertices, renumbering));
1903252a1336SBarry Smith 
1904cb87ef4cSFlorian Wechsung   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
1905cb87ef4cSFlorian Wechsung   failed = (PetscInt)(part[0] != rank);
19069566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm));
1907cb87ef4cSFlorian Wechsung   if (failedGlobal > 0) {
1908252a1336SBarry Smith     PetscCheck(failedGlobal <= 0, comm, PETSC_ERR_LIB, "Metis/Parmetis returned a bad partion");
19099566063dSJacob Faibussowitsch     PetscCall(PetscFree(vtxwgt));
19109566063dSJacob Faibussowitsch     PetscCall(PetscFree(toBalance));
19119566063dSJacob Faibussowitsch     PetscCall(PetscFree(isLeaf));
19129566063dSJacob Faibussowitsch     PetscCall(PetscFree(isNonExclusivelyOwned));
19139566063dSJacob Faibussowitsch     PetscCall(PetscFree(isExclusivelyOwned));
1914252a1336SBarry Smith     if (usematpartitioning) {
1915252a1336SBarry Smith       PetscCall(ISRestoreIndices(ispart, (const PetscInt **)&part));
1916252a1336SBarry Smith       PetscCall(ISDestroy(&ispart));
1917252a1336SBarry Smith     } else PetscCall(PetscFree(part));
19187f57c1a4SFlorian Wechsung     if (viewer) {
19199566063dSJacob Faibussowitsch       PetscCall(PetscViewerPopFormat(viewer));
19209566063dSJacob Faibussowitsch       PetscCall(PetscViewerDestroy(&viewer));
19217f57c1a4SFlorian Wechsung     }
19229566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
19238b879b41SFlorian Wechsung     PetscFunctionReturn(0);
1924cb87ef4cSFlorian Wechsung   }
1925cb87ef4cSFlorian Wechsung 
1926252a1336SBarry Smith   /* Check how well we did distributing points*/
19275dc86ac1SFlorian Wechsung   if (viewer) {
1928252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "Number of owned entities of depth %" PetscInt_FMT ".\n", entityDepth));
1929252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "Initial      "));
19309566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank + 1] - cumSumVertices[rank], ncon, vtxwgt, NULL, viewer));
1931252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "Rebalanced   "));
19329566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank + 1] - cumSumVertices[rank], ncon, vtxwgt, part, viewer));
19337407ba93SFlorian Wechsung   }
19347407ba93SFlorian Wechsung 
1935252a1336SBarry Smith   /* Check that every vertex is owned by a process that it is actually connected to. */
1936252a1336SBarry Smith   PetscCall(MatGetRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
193741525646SFlorian Wechsung   for (i = 1; i <= numNonExclusivelyOwned; i++) {
1938cb87ef4cSFlorian Wechsung     PetscInt loc = 0;
19399566063dSJacob Faibussowitsch     PetscCall(PetscFindInt(cumSumVertices[part[i]], xadj[i + 1] - xadj[i], &adjncy[xadj[i]], &loc));
19407407ba93SFlorian Wechsung     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
19419371c9d4SSatish Balay     if (loc < 0) { part[i] = rank; }
1942cb87ef4cSFlorian Wechsung   }
1943252a1336SBarry Smith   PetscCall(MatRestoreRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
1944252a1336SBarry Smith   PetscCall(MatDestroy(&A));
1945cb87ef4cSFlorian Wechsung 
1946252a1336SBarry Smith   /* See how significant the influences of the previous fixing up step was.*/
19475dc86ac1SFlorian Wechsung   if (viewer) {
1948252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "After fix    "));
19499566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank + 1] - cumSumVertices[rank], ncon, vtxwgt, part, viewer));
19507407ba93SFlorian Wechsung   }
1951252a1336SBarry Smith   if (!usematpartitioning) PetscCall(PetscFree(vtxwgt));
1952252a1336SBarry Smith   else PetscCall(MatPartitioningDestroy(&mp));
19537407ba93SFlorian Wechsung 
19549566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
1955cb87ef4cSFlorian Wechsung 
1956252a1336SBarry Smith   PetscCall(PetscLogEventBegin(DMPLEX_RebalRewriteSF, dm, 0, 0, 0));
1957252a1336SBarry Smith   /* Rewrite the SF to reflect the new ownership. */
19589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite));
19597f57c1a4SFlorian Wechsung   counter = 0;
1960cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1961cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
1962cb87ef4cSFlorian Wechsung       if (isNonExclusivelyOwned[i]) {
19637f57c1a4SFlorian Wechsung         pointsToRewrite[counter] = i + pStart;
1964cb87ef4cSFlorian Wechsung         counter++;
1965cb87ef4cSFlorian Wechsung       }
1966cb87ef4cSFlorian Wechsung     }
1967cb87ef4cSFlorian Wechsung   }
19689566063dSJacob Faibussowitsch   PetscCall(DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part + 1, degrees));
19699566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointsToRewrite));
1970252a1336SBarry Smith   PetscCall(PetscLogEventEnd(DMPLEX_RebalRewriteSF, dm, 0, 0, 0));
1971cb87ef4cSFlorian Wechsung 
19729566063dSJacob Faibussowitsch   PetscCall(PetscFree(toBalance));
19739566063dSJacob Faibussowitsch   PetscCall(PetscFree(isLeaf));
19749566063dSJacob Faibussowitsch   PetscCall(PetscFree(isNonExclusivelyOwned));
19759566063dSJacob Faibussowitsch   PetscCall(PetscFree(isExclusivelyOwned));
1976252a1336SBarry Smith   if (usematpartitioning) {
1977252a1336SBarry Smith     PetscCall(ISRestoreIndices(ispart, (const PetscInt **)&part));
1978252a1336SBarry Smith     PetscCall(ISDestroy(&ispart));
1979252a1336SBarry Smith   } else PetscCall(PetscFree(part));
19805dc86ac1SFlorian Wechsung   if (viewer) {
19819566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
19829566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
19837d197802SFlorian Wechsung   }
19848b879b41SFlorian Wechsung   if (success) *success = PETSC_TRUE;
19859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
1986b458e8f1SJose E. Roman   PetscFunctionReturn(0);
1987240408d3SFlorian Wechsung #else
19885f441e9bSFlorian Wechsung   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
198941525646SFlorian Wechsung #endif
1990cb87ef4cSFlorian Wechsung }
1991