xref: /petsc/src/dm/impls/plex/plexpartition.c (revision 1baa6e3354bfe224b33a0c158f482508792a8a6e)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2abe9303eSLisandro Dalcin #include <petsc/private/partitionerimpl.h>
3e8f14785SLisandro Dalcin #include <petsc/private/hashseti.h>
470034214SMatthew G. Knepley 
54b876568SBarry Smith const char * const DMPlexCSRAlgorithms[] = {"mat", "graph", "overlap", "DMPlexCSRAlgorithm", "DM_PLEX_CSR_",NULL};
65a107427SMatthew G. Knepley 
79fbee547SJacob Faibussowitsch static inline PetscInt DMPlex_GlobalID(PetscInt point) { return point >= 0 ? point : -(point+1); }
80134a67bSLisandro Dalcin 
95a107427SMatthew G. Knepley static PetscErrorCode DMPlexCreatePartitionerGraph_Overlap(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
105a107427SMatthew G. Knepley {
115a107427SMatthew G. Knepley   DM              ovdm;
125a107427SMatthew G. Knepley   PetscSF         sfPoint;
135a107427SMatthew G. Knepley   IS              cellNumbering;
145a107427SMatthew G. Knepley   const PetscInt *cellNum;
155a107427SMatthew G. Knepley   PetscInt       *adj = NULL, *vOffsets = NULL, *vAdj = NULL;
165a107427SMatthew G. Knepley   PetscBool       useCone, useClosure;
175a107427SMatthew G. Knepley   PetscInt        dim, depth, overlap, cStart, cEnd, c, v;
185a107427SMatthew G. Knepley   PetscMPIInt     rank, size;
195a107427SMatthew G. Knepley 
205a107427SMatthew G. Knepley   PetscFunctionBegin;
219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size));
239566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
255a107427SMatthew G. Knepley   if (dim != depth) {
265a107427SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
279566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
285a107427SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
299566063dSJacob Faibussowitsch     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
305a107427SMatthew G. Knepley     /* Different behavior for empty graphs */
315a107427SMatthew G. Knepley     if (!*numVertices) {
329566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, offsets));
335a107427SMatthew G. Knepley       (*offsets)[0] = 0;
345a107427SMatthew G. Knepley     }
355a107427SMatthew G. Knepley     /* Broken in parallel */
365f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices,PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
375a107427SMatthew G. Knepley     PetscFunctionReturn(0);
385a107427SMatthew G. Knepley   }
395a107427SMatthew G. Knepley   /* Always use FVM adjacency to create partitioner graph */
409566063dSJacob Faibussowitsch   PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
419566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
425a107427SMatthew G. Knepley   /* Need overlap >= 1 */
439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetOverlap(dm, &overlap));
445a107427SMatthew G. Knepley   if (size && overlap < 1) {
459566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeOverlap(dm, 1, NULL, &ovdm));
465a107427SMatthew G. Knepley   } else {
479566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject) dm));
485a107427SMatthew G. Knepley     ovdm = dm;
495a107427SMatthew G. Knepley   }
509566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(ovdm, &sfPoint));
519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(ovdm, height, &cStart, &cEnd));
529566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(ovdm, cStart, cEnd, 0, NULL, sfPoint, &cellNumbering));
535a107427SMatthew G. Knepley   if (globalNumbering) {
549566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject) cellNumbering));
555a107427SMatthew G. Knepley     *globalNumbering = cellNumbering;
565a107427SMatthew G. Knepley   }
579566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cellNumbering, &cellNum));
585a107427SMatthew G. Knepley   /* Determine sizes */
595a107427SMatthew G. Knepley   for (*numVertices = 0, c = cStart; c < cEnd; ++c) {
605a107427SMatthew G. Knepley     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
61b68380d8SVaclav Hapla     if (cellNum[c-cStart] < 0) continue;
625a107427SMatthew G. Knepley     (*numVertices)++;
635a107427SMatthew G. Knepley   }
649566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(*numVertices+1, &vOffsets));
655a107427SMatthew G. Knepley   for (c = cStart, v = 0; c < cEnd; ++c) {
665a107427SMatthew G. Knepley     PetscInt adjSize = PETSC_DETERMINE, a, vsize = 0;
675a107427SMatthew G. Knepley 
68b68380d8SVaclav Hapla     if (cellNum[c-cStart] < 0) continue;
699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(ovdm, c, &adjSize, &adj));
705a107427SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
715a107427SMatthew G. Knepley       const PetscInt point = adj[a];
725a107427SMatthew G. Knepley       if (point != c && cStart <= point && point < cEnd) ++vsize;
735a107427SMatthew G. Knepley     }
745a107427SMatthew G. Knepley     vOffsets[v+1] = vOffsets[v] + vsize;
755a107427SMatthew G. Knepley     ++v;
765a107427SMatthew G. Knepley   }
775a107427SMatthew G. Knepley   /* Determine adjacency */
789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vOffsets[*numVertices], &vAdj));
795a107427SMatthew G. Knepley   for (c = cStart, v = 0; c < cEnd; ++c) {
805a107427SMatthew G. Knepley     PetscInt adjSize = PETSC_DETERMINE, a, off = vOffsets[v];
815a107427SMatthew G. Knepley 
825a107427SMatthew G. Knepley     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
83b68380d8SVaclav Hapla     if (cellNum[c-cStart] < 0) continue;
849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(ovdm, c, &adjSize, &adj));
855a107427SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
865a107427SMatthew G. Knepley       const PetscInt point = adj[a];
875a107427SMatthew G. Knepley       if (point != c && cStart <= point && point < cEnd) {
88b68380d8SVaclav Hapla         vAdj[off++] = DMPlex_GlobalID(cellNum[point-cStart]);
895a107427SMatthew G. Knepley       }
905a107427SMatthew G. Knepley     }
9163a3b9bcSJacob Faibussowitsch     PetscCheck(off == vOffsets[v+1],PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Offsets %" PetscInt_FMT " should be %" PetscInt_FMT, off, vOffsets[v+1]);
925a107427SMatthew G. Knepley     /* Sort adjacencies (not strictly necessary) */
939566063dSJacob Faibussowitsch     PetscCall(PetscSortInt(off-vOffsets[v], &vAdj[vOffsets[v]]));
945a107427SMatthew G. Knepley     ++v;
955a107427SMatthew G. Knepley   }
969566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
979566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cellNumbering, &cellNum));
989566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellNumbering));
999566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
1009566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&ovdm));
1015a107427SMatthew G. Knepley   if (offsets)   {*offsets = vOffsets;}
1029566063dSJacob Faibussowitsch   else           PetscCall(PetscFree(vOffsets));
1035a107427SMatthew G. Knepley   if (adjacency) {*adjacency = vAdj;}
1049566063dSJacob Faibussowitsch   else           PetscCall(PetscFree(vAdj));
1055a107427SMatthew G. Knepley   PetscFunctionReturn(0);
1065a107427SMatthew G. Knepley }
1075a107427SMatthew G. Knepley 
108bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
109532c4e7dSMichael Lange {
110ffbd6163SMatthew G. Knepley   PetscInt       dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
111389e55d8SMichael Lange   PetscInt      *adj = NULL, *vOffsets = NULL, *graph = NULL;
1128cfe4c1fSMichael Lange   IS             cellNumbering;
1138cfe4c1fSMichael Lange   const PetscInt *cellNum;
114532c4e7dSMichael Lange   PetscBool      useCone, useClosure;
115532c4e7dSMichael Lange   PetscSection   section;
116532c4e7dSMichael Lange   PetscSegBuffer adjBuffer;
1178cfe4c1fSMichael Lange   PetscSF        sfPoint;
1188f4e72b9SMatthew G. Knepley   PetscInt       *adjCells = NULL, *remoteCells = NULL;
1198f4e72b9SMatthew G. Knepley   const PetscInt *local;
1208f4e72b9SMatthew G. Knepley   PetscInt       nroots, nleaves, l;
121532c4e7dSMichael Lange   PetscMPIInt    rank;
122532c4e7dSMichael Lange 
123532c4e7dSMichael Lange   PetscFunctionBegin;
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) */
210b68380d8SVaclav Hapla     if (nroots > 0) {if (cellNum[p-pStart] < 0) continue;}
2118f4e72b9SMatthew G. Knepley     /* Add remote cells */
2128f4e72b9SMatthew G. Knepley     if (remoteCells) {
213b68380d8SVaclav Hapla       const PetscInt gp = DMPlex_GlobalID(cellNum[p-pStart]);
2140134a67bSLisandro Dalcin       PetscInt       coneSize, numChildren, c, i;
2150134a67bSLisandro Dalcin       const PetscInt *cone, *children;
2160134a67bSLisandro Dalcin 
2179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, p, &cone));
2189566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
2198f4e72b9SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
2200134a67bSLisandro Dalcin         const PetscInt point = cone[c];
2210134a67bSLisandro Dalcin         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
2228f4e72b9SMatthew G. Knepley           PetscInt *PETSC_RESTRICT pBuf;
2239566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(section, p, 1));
2249566063dSJacob Faibussowitsch           PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2250134a67bSLisandro Dalcin           *pBuf = remoteCells[point];
2260134a67bSLisandro Dalcin         }
2270134a67bSLisandro Dalcin         /* Handle non-conforming meshes */
2289566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
2290134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
2300134a67bSLisandro Dalcin           const PetscInt child = children[i];
2310134a67bSLisandro Dalcin           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
2320134a67bSLisandro Dalcin             PetscInt *PETSC_RESTRICT pBuf;
2339566063dSJacob Faibussowitsch             PetscCall(PetscSectionAddDof(section, p, 1));
2349566063dSJacob Faibussowitsch             PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2350134a67bSLisandro Dalcin             *pBuf = remoteCells[child];
2360134a67bSLisandro Dalcin           }
2378f4e72b9SMatthew G. Knepley         }
2388f4e72b9SMatthew G. Knepley       }
2398f4e72b9SMatthew G. Knepley     }
2408f4e72b9SMatthew G. Knepley     /* Add local cells */
241532c4e7dSMichael Lange     adjSize = PETSC_DETERMINE;
2429566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
243532c4e7dSMichael Lange     for (a = 0; a < adjSize; ++a) {
244532c4e7dSMichael Lange       const PetscInt point = adj[a];
245532c4e7dSMichael Lange       if (point != p && pStart <= point && point < pEnd) {
246532c4e7dSMichael Lange         PetscInt *PETSC_RESTRICT pBuf;
2479566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(section, p, 1));
2489566063dSJacob Faibussowitsch         PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
249b68380d8SVaclav Hapla         *pBuf = DMPlex_GlobalID(cellNum[point-pStart]);
250532c4e7dSMichael Lange       }
251532c4e7dSMichael Lange     }
2528cfe4c1fSMichael Lange     (*numVertices)++;
253532c4e7dSMichael Lange   }
2549566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
2559566063dSJacob Faibussowitsch   PetscCall(PetscFree2(adjCells, remoteCells));
2569566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
2574e468a93SLisandro Dalcin 
258532c4e7dSMichael Lange   /* Derive CSR graph from section/segbuffer */
2599566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
2609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &size));
2619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(*numVertices+1, &vOffsets));
26243f7d02bSMichael Lange   for (idx = 0, p = pStart; p < pEnd; p++) {
263b68380d8SVaclav Hapla     if (nroots > 0) {if (cellNum[p-pStart] < 0) continue;}
2649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &(vOffsets[idx++])));
26543f7d02bSMichael Lange   }
266532c4e7dSMichael Lange   vOffsets[*numVertices] = size;
2679566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &graph));
2684e468a93SLisandro Dalcin 
2694e468a93SLisandro Dalcin   if (nroots >= 0) {
2704e468a93SLisandro Dalcin     /* Filter out duplicate edges using section/segbuffer */
2719566063dSJacob Faibussowitsch     PetscCall(PetscSectionReset(section));
2729566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(section, 0, *numVertices));
2734e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2744e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
2754e468a93SLisandro Dalcin       PetscInt numEdges = end-start, *PETSC_RESTRICT edges;
2769566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&numEdges, &graph[start]));
2779566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(section, p, numEdges));
2789566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGetInts(adjBuffer, numEdges, &edges));
2799566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(edges, &graph[start], numEdges));
2804e468a93SLisandro Dalcin     }
2819566063dSJacob Faibussowitsch     PetscCall(PetscFree(vOffsets));
2829566063dSJacob Faibussowitsch     PetscCall(PetscFree(graph));
2834e468a93SLisandro Dalcin     /* Derive CSR graph from section/segbuffer */
2849566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(section));
2859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(section, &size));
2869566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(*numVertices+1, &vOffsets));
2874e468a93SLisandro Dalcin     for (idx = 0, p = 0; p < *numVertices; p++) {
2889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(section, p, &(vOffsets[idx++])));
2894e468a93SLisandro Dalcin     }
2904e468a93SLisandro Dalcin     vOffsets[*numVertices] = size;
2919566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &graph));
2924e468a93SLisandro Dalcin   } else {
2934e468a93SLisandro Dalcin     /* Sort adjacencies (not strictly necessary) */
2944e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2954e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
2969566063dSJacob Faibussowitsch       PetscCall(PetscSortInt(end-start, &graph[start]));
2974e468a93SLisandro Dalcin     }
2984e468a93SLisandro Dalcin   }
2994e468a93SLisandro Dalcin 
3004e468a93SLisandro Dalcin   if (offsets) *offsets = vOffsets;
301389e55d8SMichael Lange   if (adjacency) *adjacency = graph;
3024e468a93SLisandro Dalcin 
303532c4e7dSMichael Lange   /* Cleanup */
3049566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferDestroy(&adjBuffer));
3059566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
3069566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cellNumbering, &cellNum));
3079566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellNumbering));
308532c4e7dSMichael Lange   PetscFunctionReturn(0);
309532c4e7dSMichael Lange }
310532c4e7dSMichael Lange 
311bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
312bbbc8e51SStefano Zampini {
313bbbc8e51SStefano Zampini   Mat            conn, CSR;
314bbbc8e51SStefano Zampini   IS             fis, cis, cis_own;
315bbbc8e51SStefano Zampini   PetscSF        sfPoint;
316bbbc8e51SStefano Zampini   const PetscInt *rows, *cols, *ii, *jj;
317bbbc8e51SStefano Zampini   PetscInt       *idxs,*idxs2;
31883c5d788SMatthew G. Knepley   PetscInt       dim, depth, floc, cloc, i, M, N, c, lm, m, cStart, cEnd, fStart, fEnd;
319bbbc8e51SStefano Zampini   PetscMPIInt    rank;
320bbbc8e51SStefano Zampini   PetscBool      flg;
321bbbc8e51SStefano Zampini 
322bbbc8e51SStefano Zampini   PetscFunctionBegin;
3239566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
3249566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
3259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
326bbbc8e51SStefano Zampini   if (dim != depth) {
327bbbc8e51SStefano Zampini     /* We do not handle the uninterpolated case here */
3289566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
329bbbc8e51SStefano Zampini     /* DMPlexCreateNeighborCSR does not make a numbering */
3309566063dSJacob Faibussowitsch     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
331bbbc8e51SStefano Zampini     /* Different behavior for empty graphs */
332bbbc8e51SStefano Zampini     if (!*numVertices) {
3339566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, offsets));
334bbbc8e51SStefano Zampini       (*offsets)[0] = 0;
335bbbc8e51SStefano Zampini     }
336bbbc8e51SStefano Zampini     /* Broken in parallel */
3375f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices,PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
338bbbc8e51SStefano Zampini     PetscFunctionReturn(0);
339bbbc8e51SStefano Zampini   }
340bbbc8e51SStefano Zampini   /* Interpolated and parallel case */
341bbbc8e51SStefano Zampini 
342bbbc8e51SStefano Zampini   /* numbering */
3439566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
3449566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd));
3459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd));
3469566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, &N, sfPoint, &cis));
3479566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, fStart, fEnd, 0, &M, sfPoint, &fis));
348*1baa6e33SBarry Smith   if (globalNumbering) PetscCall(ISDuplicate(cis, globalNumbering));
349bbbc8e51SStefano Zampini 
350bbbc8e51SStefano Zampini   /* get positive global ids and local sizes for facets and cells */
3519566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(fis, &m));
3529566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(fis, &rows));
3539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &idxs));
354bbbc8e51SStefano Zampini   for (i = 0, floc = 0; i < m; i++) {
355bbbc8e51SStefano Zampini     const PetscInt p = rows[i];
356bbbc8e51SStefano Zampini 
357bbbc8e51SStefano Zampini     if (p < 0) {
358bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
359bbbc8e51SStefano Zampini     } else {
360bbbc8e51SStefano Zampini       idxs[i] = p;
361bbbc8e51SStefano Zampini       floc   += 1;
362bbbc8e51SStefano Zampini     }
363bbbc8e51SStefano Zampini   }
3649566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(fis, &rows));
3659566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&fis));
3669566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis));
367bbbc8e51SStefano Zampini 
3689566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cis, &m));
3699566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cis, &cols));
3709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &idxs));
3719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &idxs2));
372bbbc8e51SStefano Zampini   for (i = 0, cloc = 0; i < m; i++) {
373bbbc8e51SStefano Zampini     const PetscInt p = cols[i];
374bbbc8e51SStefano Zampini 
375bbbc8e51SStefano Zampini     if (p < 0) {
376bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
377bbbc8e51SStefano Zampini     } else {
378bbbc8e51SStefano Zampini       idxs[i]       = p;
379bbbc8e51SStefano Zampini       idxs2[cloc++] = p;
380bbbc8e51SStefano Zampini     }
381bbbc8e51SStefano Zampini   }
3829566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cis, &cols));
3839566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis));
3849566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis));
3859566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own));
386bbbc8e51SStefano Zampini 
387bbbc8e51SStefano Zampini   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
3889566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), &conn));
3899566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(conn, floc, cloc, M, N));
3909566063dSJacob Faibussowitsch   PetscCall(MatSetType(conn, MATMPIAIJ));
3919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, NULL, &lm));
3929566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&lm, &m, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm)));
3939566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL));
394bbbc8e51SStefano Zampini 
395bbbc8e51SStefano Zampini   /* Assemble matrix */
3969566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(fis, &rows));
3979566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cis, &cols));
398bbbc8e51SStefano Zampini   for (c = cStart; c < cEnd; c++) {
399bbbc8e51SStefano Zampini     const PetscInt *cone;
400bbbc8e51SStefano Zampini     PetscInt        coneSize, row, col, f;
401bbbc8e51SStefano Zampini 
402bbbc8e51SStefano Zampini     col  = cols[c-cStart];
4039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
4049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
405bbbc8e51SStefano Zampini     for (f = 0; f < coneSize; f++) {
406bbbc8e51SStefano Zampini       const PetscScalar v = 1.0;
407bbbc8e51SStefano Zampini       const PetscInt *children;
408bbbc8e51SStefano Zampini       PetscInt        numChildren, ch;
409bbbc8e51SStefano Zampini 
410bbbc8e51SStefano Zampini       row  = rows[cone[f]-fStart];
4119566063dSJacob Faibussowitsch       PetscCall(MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES));
412bbbc8e51SStefano Zampini 
413bbbc8e51SStefano Zampini       /* non-conforming meshes */
4149566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children));
415bbbc8e51SStefano Zampini       for (ch = 0; ch < numChildren; ch++) {
416bbbc8e51SStefano Zampini         const PetscInt child = children[ch];
417bbbc8e51SStefano Zampini 
418bbbc8e51SStefano Zampini         if (child < fStart || child >= fEnd) continue;
419bbbc8e51SStefano Zampini         row  = rows[child-fStart];
4209566063dSJacob Faibussowitsch         PetscCall(MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES));
421bbbc8e51SStefano Zampini       }
422bbbc8e51SStefano Zampini     }
423bbbc8e51SStefano Zampini   }
4249566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(fis, &rows));
4259566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cis, &cols));
4269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&fis));
4279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis));
4289566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY));
4299566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY));
430bbbc8e51SStefano Zampini 
431bbbc8e51SStefano Zampini   /* Get parallel CSR by doing conn^T * conn */
4329566063dSJacob Faibussowitsch   PetscCall(MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR));
4339566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&conn));
434bbbc8e51SStefano Zampini 
435bbbc8e51SStefano Zampini   /* extract local part of the CSR */
4369566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn));
4379566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&CSR));
4389566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
4395f80ce2aSJacob Faibussowitsch   PetscCheck(flg,PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
440bbbc8e51SStefano Zampini 
441bbbc8e51SStefano Zampini   /* get back requested output */
442bbbc8e51SStefano Zampini   if (numVertices) *numVertices = m;
443bbbc8e51SStefano Zampini   if (offsets) {
4449566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(m+1, &idxs));
445bbbc8e51SStefano Zampini     for (i = 1; i < m+1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
446bbbc8e51SStefano Zampini     *offsets = idxs;
447bbbc8e51SStefano Zampini   }
448bbbc8e51SStefano Zampini   if (adjacency) {
4499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ii[m] - m, &idxs));
4509566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(cis_own, &rows));
451bbbc8e51SStefano Zampini     for (i = 0, c = 0; i < m; i++) {
452bbbc8e51SStefano Zampini       PetscInt j, g = rows[i];
453bbbc8e51SStefano Zampini 
454bbbc8e51SStefano Zampini       for (j = ii[i]; j < ii[i+1]; j++) {
455bbbc8e51SStefano Zampini         if (jj[j] == g) continue; /* again, self-connectivity */
456bbbc8e51SStefano Zampini         idxs[c++] = jj[j];
457bbbc8e51SStefano Zampini       }
458bbbc8e51SStefano Zampini     }
45963a3b9bcSJacob Faibussowitsch     PetscCheck(c == ii[m] - m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,c,ii[m]-m);
4609566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(cis_own, &rows));
461bbbc8e51SStefano Zampini     *adjacency = idxs;
462bbbc8e51SStefano Zampini   }
463bbbc8e51SStefano Zampini 
464bbbc8e51SStefano Zampini   /* cleanup */
4659566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis_own));
4669566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
4675f80ce2aSJacob Faibussowitsch   PetscCheck(flg,PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
4689566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&conn));
469bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
470bbbc8e51SStefano Zampini }
471bbbc8e51SStefano Zampini 
472bbbc8e51SStefano Zampini /*@C
473bbbc8e51SStefano Zampini   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
474bbbc8e51SStefano Zampini 
475bbbc8e51SStefano Zampini   Input Parameters:
476bbbc8e51SStefano Zampini + dm      - The mesh DM dm
477bbbc8e51SStefano Zampini - height  - Height of the strata from which to construct the graph
478bbbc8e51SStefano Zampini 
479d8d19677SJose E. Roman   Output Parameters:
480bbbc8e51SStefano Zampini + numVertices     - Number of vertices in the graph
481bbbc8e51SStefano Zampini . offsets         - Point offsets in the graph
482bbbc8e51SStefano Zampini . adjacency       - Point connectivity in the graph
483bbbc8e51SStefano 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.
484bbbc8e51SStefano Zampini 
485bbbc8e51SStefano Zampini   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
486bbbc8e51SStefano Zampini   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
487bbbc8e51SStefano Zampini 
4885a107427SMatthew G. Knepley   Options Database Keys:
4895a107427SMatthew G. Knepley . -dm_plex_csr_alg <mat,graph,overlap> - Choose the algorithm for computing the CSR graph
4905a107427SMatthew G. Knepley 
491bbbc8e51SStefano Zampini   Level: developer
492bbbc8e51SStefano Zampini 
493db781477SPatrick Sanan .seealso: `PetscPartitionerGetType()`, `PetscPartitionerCreate()`, `DMSetAdjacency()`
494bbbc8e51SStefano Zampini @*/
495bbbc8e51SStefano Zampini PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
496bbbc8e51SStefano Zampini {
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) {
5025a107427SMatthew G. Knepley     case DM_PLEX_CSR_MAT:
5039566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering));break;
5045a107427SMatthew G. Knepley     case DM_PLEX_CSR_GRAPH:
5059566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering));break;
5065a107427SMatthew G. Knepley     case DM_PLEX_CSR_OVERLAP:
5079566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePartitionerGraph_Overlap(dm, height, numVertices, offsets, adjacency, globalNumbering));break;
508bbbc8e51SStefano Zampini   }
509bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
510bbbc8e51SStefano Zampini }
511bbbc8e51SStefano Zampini 
512d5577e40SMatthew G. Knepley /*@C
513d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
514d5577e40SMatthew G. Knepley 
515fe2efc57SMark   Collective on DM
516d5577e40SMatthew G. Knepley 
5174165533cSJose E. Roman   Input Parameters:
518d5577e40SMatthew G. Knepley + dm - The DMPlex
519d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
520d5577e40SMatthew G. Knepley 
5214165533cSJose E. Roman   Output Parameters:
522d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
523d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
524d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
525d5577e40SMatthew G. Knepley 
526d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
527d5577e40SMatthew G. Knepley 
528d5577e40SMatthew G. Knepley   Level: advanced
529d5577e40SMatthew G. Knepley 
530db781477SPatrick Sanan .seealso: `DMPlexCreate()`
531d5577e40SMatthew G. Knepley @*/
53270034214SMatthew G. Knepley PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
53370034214SMatthew G. Knepley {
53470034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
53570034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
53670034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
53770034214SMatthew G. Knepley   PetscInt      *off, *adj;
53870034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
53970034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
54070034214SMatthew G. Knepley 
54170034214SMatthew G. Knepley   PetscFunctionBegin;
54270034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
5439566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
54470034214SMatthew G. Knepley   cellDim = dim - cellHeight;
5459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
5469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
54770034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
54870034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
54970034214SMatthew G. Knepley     if (offsets)   *offsets   = NULL;
55070034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
55170034214SMatthew G. Knepley     PetscFunctionReturn(0);
55270034214SMatthew G. Knepley   }
55370034214SMatthew G. Knepley   numCells  = cEnd - cStart;
55470034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
55570034214SMatthew G. Knepley   if (dim == depth) {
55670034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
55770034214SMatthew G. Knepley 
5589566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(numCells+1, &off));
55970034214SMatthew G. Knepley     /* Count neighboring cells */
5609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd));
56170034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
56270034214SMatthew G. Knepley       const PetscInt *support;
56370034214SMatthew G. Knepley       PetscInt        supportSize;
5649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
5659566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &support));
56670034214SMatthew G. Knepley       if (supportSize == 2) {
5679ffc88e4SToby Isaac         PetscInt numChildren;
5689ffc88e4SToby Isaac 
5699566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm,f,&numChildren,NULL));
5709ffc88e4SToby Isaac         if (!numChildren) {
57170034214SMatthew G. Knepley           ++off[support[0]-cStart+1];
57270034214SMatthew G. Knepley           ++off[support[1]-cStart+1];
57370034214SMatthew G. Knepley         }
57470034214SMatthew G. Knepley       }
5759ffc88e4SToby Isaac     }
57670034214SMatthew G. Knepley     /* Prefix sum */
57770034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
57870034214SMatthew G. Knepley     if (adjacency) {
57970034214SMatthew G. Knepley       PetscInt *tmp;
58070034214SMatthew G. Knepley 
5819566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(off[numCells], &adj));
5829566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numCells+1, &tmp));
5839566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(tmp, off, numCells+1));
58470034214SMatthew G. Knepley       /* Get neighboring cells */
58570034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
58670034214SMatthew G. Knepley         const PetscInt *support;
58770034214SMatthew G. Knepley         PetscInt        supportSize;
5889566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
5899566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, f, &support));
59070034214SMatthew G. Knepley         if (supportSize == 2) {
5919ffc88e4SToby Isaac           PetscInt numChildren;
5929ffc88e4SToby Isaac 
5939566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(dm,f,&numChildren,NULL));
5949ffc88e4SToby Isaac           if (!numChildren) {
59570034214SMatthew G. Knepley             adj[tmp[support[0]-cStart]++] = support[1];
59670034214SMatthew G. Knepley             adj[tmp[support[1]-cStart]++] = support[0];
59770034214SMatthew G. Knepley           }
59870034214SMatthew G. Knepley         }
5999ffc88e4SToby Isaac       }
60063a3b9bcSJacob 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);
6019566063dSJacob Faibussowitsch       PetscCall(PetscFree(tmp));
60270034214SMatthew G. Knepley     }
60370034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
60470034214SMatthew G. Knepley     if (offsets)   *offsets   = off;
60570034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
60670034214SMatthew G. Knepley     PetscFunctionReturn(0);
60770034214SMatthew G. Knepley   }
60870034214SMatthew G. Knepley   /* Setup face recognition */
60970034214SMatthew G. Knepley   if (faceDepth == 1) {
61070034214SMatthew 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 */
61170034214SMatthew G. Knepley 
61270034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
61370034214SMatthew G. Knepley       PetscInt corners;
61470034214SMatthew G. Knepley 
6159566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &corners));
61670034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
61770034214SMatthew G. Knepley         PetscInt nFV;
61870034214SMatthew G. Knepley 
6195f80ce2aSJacob Faibussowitsch         PetscCheck(numFaceCases < maxFaceCases,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
62070034214SMatthew G. Knepley         cornersSeen[corners] = 1;
62170034214SMatthew G. Knepley 
6229566063dSJacob Faibussowitsch         PetscCall(DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV));
62370034214SMatthew G. Knepley 
62470034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
62570034214SMatthew G. Knepley       }
62670034214SMatthew G. Knepley     }
62770034214SMatthew G. Knepley   }
6289566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numCells+1, &off));
62970034214SMatthew G. Knepley   /* Count neighboring cells */
63070034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
63170034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
63270034214SMatthew G. Knepley 
6339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
63470034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
63570034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
63670034214SMatthew G. Knepley       PetscInt        cellPair[2];
63770034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
63870034214SMatthew G. Knepley       PetscInt        meetSize = 0;
63970034214SMatthew G. Knepley       const PetscInt *meet    = NULL;
64070034214SMatthew G. Knepley 
64170034214SMatthew G. Knepley       cellPair[0] = cell; cellPair[1] = neighborCells[n];
64270034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
64370034214SMatthew G. Knepley       if (!found) {
6449566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
64570034214SMatthew G. Knepley         if (meetSize) {
64670034214SMatthew G. Knepley           PetscInt f;
64770034214SMatthew G. Knepley 
64870034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
64970034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
65070034214SMatthew G. Knepley               found = PETSC_TRUE;
65170034214SMatthew G. Knepley               break;
65270034214SMatthew G. Knepley             }
65370034214SMatthew G. Knepley           }
65470034214SMatthew G. Knepley         }
6559566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
65670034214SMatthew G. Knepley       }
65770034214SMatthew G. Knepley       if (found) ++off[cell-cStart+1];
65870034214SMatthew G. Knepley     }
65970034214SMatthew G. Knepley   }
66070034214SMatthew G. Knepley   /* Prefix sum */
66170034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
66270034214SMatthew G. Knepley 
66370034214SMatthew G. Knepley   if (adjacency) {
6649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(off[numCells], &adj));
66570034214SMatthew G. Knepley     /* Get neighboring cells */
66670034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
66770034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
66870034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
66970034214SMatthew G. Knepley 
6709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
67170034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
67270034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
67370034214SMatthew G. Knepley         PetscInt        cellPair[2];
67470034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
67570034214SMatthew G. Knepley         PetscInt        meetSize = 0;
67670034214SMatthew G. Knepley         const PetscInt *meet    = NULL;
67770034214SMatthew G. Knepley 
67870034214SMatthew G. Knepley         cellPair[0] = cell; cellPair[1] = neighborCells[n];
67970034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
68070034214SMatthew G. Knepley         if (!found) {
6819566063dSJacob Faibussowitsch           PetscCall(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
68270034214SMatthew G. Knepley           if (meetSize) {
68370034214SMatthew G. Knepley             PetscInt f;
68470034214SMatthew G. Knepley 
68570034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
68670034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
68770034214SMatthew G. Knepley                 found = PETSC_TRUE;
68870034214SMatthew G. Knepley                 break;
68970034214SMatthew G. Knepley               }
69070034214SMatthew G. Knepley             }
69170034214SMatthew G. Knepley           }
6929566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
69370034214SMatthew G. Knepley         }
69470034214SMatthew G. Knepley         if (found) {
69570034214SMatthew G. Knepley           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
69670034214SMatthew G. Knepley           ++cellOffset;
69770034214SMatthew G. Knepley         }
69870034214SMatthew G. Knepley       }
69970034214SMatthew G. Knepley     }
70070034214SMatthew G. Knepley   }
7019566063dSJacob Faibussowitsch   PetscCall(PetscFree(neighborCells));
70270034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
70370034214SMatthew G. Knepley   if (offsets)   *offsets   = off;
70470034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
70570034214SMatthew G. Knepley   PetscFunctionReturn(0);
70670034214SMatthew G. Knepley }
70770034214SMatthew G. Knepley 
70877623264SMatthew G. Knepley /*@
7093c41b853SStefano Zampini   PetscPartitionerDMPlexPartition - Create a non-overlapping partition of the cells in the mesh
71077623264SMatthew G. Knepley 
711fe2efc57SMark   Collective on PetscPartitioner
71277623264SMatthew G. Knepley 
71377623264SMatthew G. Knepley   Input Parameters:
71477623264SMatthew G. Knepley + part    - The PetscPartitioner
7153c41b853SStefano Zampini . targetSection - The PetscSection describing the absolute weight of each partition (can be NULL)
716f8987ae8SMichael Lange - dm      - The mesh DM
71777623264SMatthew G. Knepley 
71877623264SMatthew G. Knepley   Output Parameters:
71977623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
720f8987ae8SMichael Lange - partition       - The list of points by partition
72177623264SMatthew G. Knepley 
7223c41b853SStefano Zampini   Notes:
7233c41b853SStefano Zampini     If the DM has a local section associated, each point to be partitioned will be weighted by the total number of dofs identified
7243c41b853SStefano Zampini     by the section in the transitive closure of the point.
72577623264SMatthew G. Knepley 
72677623264SMatthew G. Knepley   Level: developer
72777623264SMatthew G. Knepley 
728db781477SPatrick Sanan .seealso `DMPlexDistribute()`, `PetscPartitionerCreate()`, `PetscSectionCreate()`, `PetscSectionSetChart()`, `PetscPartitionerPartition()`
7294b15ede2SMatthew G. Knepley @*/
7303c41b853SStefano Zampini PetscErrorCode PetscPartitionerDMPlexPartition(PetscPartitioner part, DM dm, PetscSection targetSection, PetscSection partSection, IS *partition)
73177623264SMatthew G. Knepley {
73277623264SMatthew G. Knepley   PetscMPIInt    size;
7333c41b853SStefano Zampini   PetscBool      isplex;
7343c41b853SStefano Zampini   PetscSection   vertSection = NULL;
73577623264SMatthew G. Knepley 
73677623264SMatthew G. Knepley   PetscFunctionBegin;
73777623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
73877623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
7393c41b853SStefano Zampini   if (targetSection) PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 3);
74077623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
74177623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
7429566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isplex));
7435f80ce2aSJacob Faibussowitsch   PetscCheck(isplex,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Not for type %s",((PetscObject)dm)->type_name);
7449566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject) part), &size));
74577623264SMatthew G. Knepley   if (size == 1) {
74677623264SMatthew G. Knepley     PetscInt *points;
74777623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
74877623264SMatthew G. Knepley 
7499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
7509566063dSJacob Faibussowitsch     PetscCall(PetscSectionReset(partSection));
7519566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(partSection, 0, size));
7529566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(partSection, 0, cEnd-cStart));
7539566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(partSection));
7549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cEnd-cStart, &points));
75577623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
7569566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition));
75777623264SMatthew G. Knepley     PetscFunctionReturn(0);
75877623264SMatthew G. Knepley   }
75977623264SMatthew G. Knepley   if (part->height == 0) {
760074d466cSStefano Zampini     PetscInt numVertices = 0;
76177623264SMatthew G. Knepley     PetscInt *start     = NULL;
76277623264SMatthew G. Knepley     PetscInt *adjacency = NULL;
7633fa7752dSToby Isaac     IS       globalNumbering;
76477623264SMatthew G. Knepley 
765074d466cSStefano Zampini     if (!part->noGraph || part->viewGraph) {
7669566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering));
76713911537SStefano Zampini     } else { /* only compute the number of owned local vertices */
768074d466cSStefano Zampini       const PetscInt *idxs;
769074d466cSStefano Zampini       PetscInt       p, pStart, pEnd;
770074d466cSStefano Zampini 
7719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
7729566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering));
7739566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(globalNumbering, &idxs));
774074d466cSStefano Zampini       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
7759566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(globalNumbering, &idxs));
776074d466cSStefano Zampini     }
7773c41b853SStefano Zampini     if (part->usevwgt) {
7783c41b853SStefano Zampini       PetscSection   section = dm->localSection, clSection = NULL;
7793c41b853SStefano Zampini       IS             clPoints = NULL;
7803c41b853SStefano Zampini       const PetscInt *gid,*clIdx;
7813c41b853SStefano Zampini       PetscInt       v, p, pStart, pEnd;
7820358368aSMatthew G. Knepley 
7833c41b853SStefano 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) */
7843c41b853SStefano Zampini       /* We do this only if the local section has been set */
7853c41b853SStefano Zampini       if (section) {
7869566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, NULL));
7873c41b853SStefano Zampini         if (!clSection) {
7889566063dSJacob Faibussowitsch           PetscCall(DMPlexCreateClosureIndex(dm,NULL));
7893c41b853SStefano Zampini         }
7909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, &clPoints));
7919566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(clPoints,&clIdx));
7923c41b853SStefano Zampini       }
7939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
7949566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &vertSection));
7959566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(vertSection, 0, numVertices));
7963c41b853SStefano Zampini       if (globalNumbering) {
7979566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(globalNumbering,&gid));
7983c41b853SStefano Zampini       } else gid = NULL;
7993c41b853SStefano Zampini       for (p = pStart, v = 0; p < pEnd; ++p) {
8003c41b853SStefano Zampini         PetscInt dof = 1;
8010358368aSMatthew G. Knepley 
8023c41b853SStefano Zampini         /* skip cells in the overlap */
8033c41b853SStefano Zampini         if (gid && gid[p-pStart] < 0) continue;
8043c41b853SStefano Zampini 
8053c41b853SStefano Zampini         if (section) {
8063c41b853SStefano Zampini           PetscInt cl, clSize, clOff;
8073c41b853SStefano Zampini 
8083c41b853SStefano Zampini           dof  = 0;
8099566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(clSection, p, &clSize));
8109566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(clSection, p, &clOff));
8113c41b853SStefano Zampini           for (cl = 0; cl < clSize; cl+=2) {
8123c41b853SStefano Zampini             PetscInt clDof, clPoint = clIdx[clOff + cl]; /* odd indices are reserved for orientations */
8133c41b853SStefano Zampini 
8149566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, clPoint, &clDof));
8153c41b853SStefano Zampini             dof += clDof;
8160358368aSMatthew G. Knepley           }
8170358368aSMatthew G. Knepley         }
81863a3b9bcSJacob Faibussowitsch         PetscCheck(dof,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of dofs for point %" PetscInt_FMT " in the local section should be positive",p);
8199566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(vertSection, v, dof));
8203c41b853SStefano Zampini         v++;
8213c41b853SStefano Zampini       }
8223c41b853SStefano Zampini       if (globalNumbering) {
8239566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(globalNumbering,&gid));
8243c41b853SStefano Zampini       }
8253c41b853SStefano Zampini       if (clPoints) {
8269566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(clPoints,&clIdx));
8273c41b853SStefano Zampini       }
8289566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(vertSection));
8293c41b853SStefano Zampini     }
8309566063dSJacob Faibussowitsch     PetscCall(PetscPartitionerPartition(part, size, numVertices, start, adjacency, vertSection, targetSection, partSection, partition));
8319566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
8329566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
8333fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
8343fa7752dSToby Isaac       const PetscInt *globalNum;
8353fa7752dSToby Isaac       const PetscInt *partIdx;
8363fa7752dSToby Isaac       PetscInt       *map, cStart, cEnd;
8373fa7752dSToby Isaac       PetscInt       *adjusted, i, localSize, offset;
8383fa7752dSToby Isaac       IS             newPartition;
8393fa7752dSToby Isaac 
8409566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(*partition,&localSize));
8419566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localSize,&adjusted));
8429566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(globalNumbering,&globalNum));
8439566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(*partition,&partIdx));
8449566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localSize,&map));
8459566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
8463fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
8473fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
8483fa7752dSToby Isaac       }
8493fa7752dSToby Isaac       for (i = 0; i < localSize; i++) {
8503fa7752dSToby Isaac         adjusted[i] = map[partIdx[i]];
8513fa7752dSToby Isaac       }
8529566063dSJacob Faibussowitsch       PetscCall(PetscFree(map));
8539566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(*partition,&partIdx));
8549566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(globalNumbering,&globalNum));
8559566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition));
8569566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalNumbering));
8579566063dSJacob Faibussowitsch       PetscCall(ISDestroy(partition));
8583fa7752dSToby Isaac       *partition = newPartition;
8593fa7752dSToby Isaac     }
86063a3b9bcSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %" PetscInt_FMT " for points to partition", part->height);
8619566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&vertSection));
86277623264SMatthew G. Knepley   PetscFunctionReturn(0);
86377623264SMatthew G. Knepley }
86477623264SMatthew G. Knepley 
8655680f57bSMatthew G. Knepley /*@
8665680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
8675680f57bSMatthew G. Knepley 
8685680f57bSMatthew G. Knepley   Not collective
8695680f57bSMatthew G. Knepley 
8705680f57bSMatthew G. Knepley   Input Parameter:
8715680f57bSMatthew G. Knepley . dm - The DM
8725680f57bSMatthew G. Knepley 
8735680f57bSMatthew G. Knepley   Output Parameter:
8745680f57bSMatthew G. Knepley . part - The PetscPartitioner
8755680f57bSMatthew G. Knepley 
8765680f57bSMatthew G. Knepley   Level: developer
8775680f57bSMatthew G. Knepley 
87898599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
87998599a47SLawrence Mitchell 
880db781477SPatrick Sanan .seealso `DMPlexDistribute()`, `DMPlexSetPartitioner()`, `PetscPartitionerDMPlexPartition()`, `PetscPartitionerCreate()`
8815680f57bSMatthew G. Knepley @*/
8825680f57bSMatthew G. Knepley PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
8835680f57bSMatthew G. Knepley {
8845680f57bSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex *) dm->data;
8855680f57bSMatthew G. Knepley 
8865680f57bSMatthew G. Knepley   PetscFunctionBegin;
8875680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8885680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
8895680f57bSMatthew G. Knepley   *part = mesh->partitioner;
8905680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
8915680f57bSMatthew G. Knepley }
8925680f57bSMatthew G. Knepley 
89371bb2955SLawrence Mitchell /*@
89471bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
89571bb2955SLawrence Mitchell 
896fe2efc57SMark   logically collective on DM
89771bb2955SLawrence Mitchell 
89871bb2955SLawrence Mitchell   Input Parameters:
89971bb2955SLawrence Mitchell + dm - The DM
90071bb2955SLawrence Mitchell - part - The partitioner
90171bb2955SLawrence Mitchell 
90271bb2955SLawrence Mitchell   Level: developer
90371bb2955SLawrence Mitchell 
90471bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
90571bb2955SLawrence Mitchell 
906db781477SPatrick Sanan .seealso `DMPlexDistribute()`, `DMPlexGetPartitioner()`, `PetscPartitionerCreate()`
90771bb2955SLawrence Mitchell @*/
90871bb2955SLawrence Mitchell PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
90971bb2955SLawrence Mitchell {
91071bb2955SLawrence Mitchell   DM_Plex       *mesh = (DM_Plex *) dm->data;
91171bb2955SLawrence Mitchell 
91271bb2955SLawrence Mitchell   PetscFunctionBegin;
91371bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
91471bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
9159566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)part));
9169566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
91771bb2955SLawrence Mitchell   mesh->partitioner = part;
91871bb2955SLawrence Mitchell   PetscFunctionReturn(0);
91971bb2955SLawrence Mitchell }
92071bb2955SLawrence Mitchell 
9218e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point)
9228e330a33SStefano Zampini {
9238e330a33SStefano Zampini   const PetscInt *cone;
9248e330a33SStefano Zampini   PetscInt       coneSize, c;
9258e330a33SStefano Zampini   PetscBool      missing;
9268e330a33SStefano Zampini 
9278e330a33SStefano Zampini   PetscFunctionBeginHot;
9289566063dSJacob Faibussowitsch   PetscCall(PetscHSetIQueryAdd(ht, point, &missing));
9298e330a33SStefano Zampini   if (missing) {
9309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
9319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
9328e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
9339566063dSJacob Faibussowitsch       PetscCall(DMPlexAddClosure_Private(dm, ht, cone[c]));
9348e330a33SStefano Zampini     }
9358e330a33SStefano Zampini   }
9368e330a33SStefano Zampini   PetscFunctionReturn(0);
9378e330a33SStefano Zampini }
9388e330a33SStefano Zampini 
9398e330a33SStefano Zampini PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
940270bba0cSToby Isaac {
941270bba0cSToby Isaac   PetscFunctionBegin;
9426a5a2ffdSToby Isaac   if (up) {
9436a5a2ffdSToby Isaac     PetscInt parent;
9446a5a2ffdSToby Isaac 
9459566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm,point,&parent,NULL));
9466a5a2ffdSToby Isaac     if (parent != point) {
9476a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
9486a5a2ffdSToby Isaac 
9499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
950270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
951270bba0cSToby Isaac         PetscInt cpoint = closure[2*i];
952270bba0cSToby Isaac 
9539566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(ht, cpoint));
9549566063dSJacob Faibussowitsch         PetscCall(DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE));
955270bba0cSToby Isaac       }
9569566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
9576a5a2ffdSToby Isaac     }
9586a5a2ffdSToby Isaac   }
9596a5a2ffdSToby Isaac   if (down) {
9606a5a2ffdSToby Isaac     PetscInt numChildren;
9616a5a2ffdSToby Isaac     const PetscInt *children;
9626a5a2ffdSToby Isaac 
9639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm,point,&numChildren,&children));
9646a5a2ffdSToby Isaac     if (numChildren) {
9656a5a2ffdSToby Isaac       PetscInt i;
9666a5a2ffdSToby Isaac 
9676a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
9686a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
9696a5a2ffdSToby Isaac 
9709566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(ht, cpoint));
9719566063dSJacob Faibussowitsch         PetscCall(DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE));
9726a5a2ffdSToby Isaac       }
9736a5a2ffdSToby Isaac     }
9746a5a2ffdSToby Isaac   }
975270bba0cSToby Isaac   PetscFunctionReturn(0);
976270bba0cSToby Isaac }
977270bba0cSToby Isaac 
9788e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point)
9798e330a33SStefano Zampini {
9808e330a33SStefano Zampini   PetscInt       parent;
981825f8a23SLisandro Dalcin 
9828e330a33SStefano Zampini   PetscFunctionBeginHot;
9839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTreeParent(dm, point, &parent,NULL));
9848e330a33SStefano Zampini   if (point != parent) {
9858e330a33SStefano Zampini     const PetscInt *cone;
9868e330a33SStefano Zampini     PetscInt       coneSize, c;
9878e330a33SStefano Zampini 
9889566063dSJacob Faibussowitsch     PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, parent));
9899566063dSJacob Faibussowitsch     PetscCall(DMPlexAddClosure_Private(dm, ht, parent));
9909566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, parent, &cone));
9919566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
9928e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
9938e330a33SStefano Zampini       const PetscInt cp = cone[c];
9948e330a33SStefano Zampini 
9959566063dSJacob Faibussowitsch       PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, cp));
9968e330a33SStefano Zampini     }
9978e330a33SStefano Zampini   }
9988e330a33SStefano Zampini   PetscFunctionReturn(0);
9998e330a33SStefano Zampini }
10008e330a33SStefano Zampini 
10018e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point)
10028e330a33SStefano Zampini {
10038e330a33SStefano Zampini   PetscInt       i, numChildren;
10048e330a33SStefano Zampini   const PetscInt *children;
10058e330a33SStefano Zampini 
10068e330a33SStefano Zampini   PetscFunctionBeginHot;
10079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
10088e330a33SStefano Zampini   for (i = 0; i < numChildren; i++) {
10099566063dSJacob Faibussowitsch     PetscCall(PetscHSetIAdd(ht, children[i]));
10108e330a33SStefano Zampini   }
10118e330a33SStefano Zampini   PetscFunctionReturn(0);
10128e330a33SStefano Zampini }
10138e330a33SStefano Zampini 
10148e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point)
10158e330a33SStefano Zampini {
10168e330a33SStefano Zampini   const PetscInt *cone;
10178e330a33SStefano Zampini   PetscInt       coneSize, c;
10188e330a33SStefano Zampini 
10198e330a33SStefano Zampini   PetscFunctionBeginHot;
10209566063dSJacob Faibussowitsch   PetscCall(PetscHSetIAdd(ht, point));
10219566063dSJacob Faibussowitsch   PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, point));
10229566063dSJacob Faibussowitsch   PetscCall(DMPlexAddClosureTree_Down_Private(dm, ht, point));
10239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
10249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
10258e330a33SStefano Zampini   for (c = 0; c < coneSize; c++) {
10269566063dSJacob Faibussowitsch     PetscCall(DMPlexAddClosureTree_Private(dm, ht, cone[c]));
10278e330a33SStefano Zampini   }
10288e330a33SStefano Zampini   PetscFunctionReturn(0);
10298e330a33SStefano Zampini }
10308e330a33SStefano Zampini 
10318e330a33SStefano Zampini PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS)
1032825f8a23SLisandro Dalcin {
1033825f8a23SLisandro Dalcin   DM_Plex         *mesh = (DM_Plex *)dm->data;
10348e330a33SStefano Zampini   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
10358e330a33SStefano Zampini   PetscInt        nelems, *elems, off = 0, p;
103627104ee2SJacob Faibussowitsch   PetscHSetI      ht = NULL;
1037825f8a23SLisandro Dalcin 
1038825f8a23SLisandro Dalcin   PetscFunctionBegin;
10399566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
10409566063dSJacob Faibussowitsch   PetscCall(PetscHSetIResize(ht, numPoints*16));
10418e330a33SStefano Zampini   if (!hasTree) {
10428e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
10439566063dSJacob Faibussowitsch       PetscCall(DMPlexAddClosure_Private(dm, ht, points[p]));
10448e330a33SStefano Zampini     }
10458e330a33SStefano Zampini   } else {
10468e330a33SStefano Zampini #if 1
10478e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
10489566063dSJacob Faibussowitsch       PetscCall(DMPlexAddClosureTree_Private(dm, ht, points[p]));
10498e330a33SStefano Zampini     }
10508e330a33SStefano Zampini #else
10518e330a33SStefano Zampini     PetscInt  *closure = NULL, closureSize, c;
1052825f8a23SLisandro Dalcin     for (p = 0; p < numPoints; ++p) {
10539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure));
1054825f8a23SLisandro Dalcin       for (c = 0; c < closureSize*2; c += 2) {
10559566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(ht, closure[c]));
10569566063dSJacob Faibussowitsch         if (hasTree) PetscCall(DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE));
1057825f8a23SLisandro Dalcin       }
1058825f8a23SLisandro Dalcin     }
10599566063dSJacob Faibussowitsch     if (closure) PetscCall(DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure));
10608e330a33SStefano Zampini #endif
10618e330a33SStefano Zampini   }
10629566063dSJacob Faibussowitsch   PetscCall(PetscHSetIGetSize(ht, &nelems));
10639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nelems, &elems));
10649566063dSJacob Faibussowitsch   PetscCall(PetscHSetIGetElems(ht, &off, elems));
10659566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
10669566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(nelems, elems));
10679566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS));
1068825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
1069825f8a23SLisandro Dalcin }
1070825f8a23SLisandro Dalcin 
10715abbe4feSMichael Lange /*@
10725abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
10735abbe4feSMichael Lange 
10745abbe4feSMichael Lange   Input Parameters:
10755abbe4feSMichael Lange + dm     - The DM
1076a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
10775abbe4feSMichael Lange 
10785abbe4feSMichael Lange   Level: developer
10795abbe4feSMichael Lange 
1080db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
10815abbe4feSMichael Lange @*/
10825abbe4feSMichael Lange PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
10839ffc88e4SToby Isaac {
1084825f8a23SLisandro Dalcin   IS              rankIS,   pointIS, closureIS;
10855abbe4feSMichael Lange   const PetscInt *ranks,   *points;
1086825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
10879ffc88e4SToby Isaac 
10889ffc88e4SToby Isaac   PetscFunctionBegin;
10899566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &rankIS));
10909566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
10919566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
10925abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
10935abbe4feSMichael Lange     const PetscInt rank = ranks[r];
10949566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &pointIS));
10959566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
10969566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
10979566063dSJacob Faibussowitsch     PetscCall(DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS));
10989566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
10999566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
11009566063dSJacob Faibussowitsch     PetscCall(DMLabelSetStratumIS(label, rank, closureIS));
11019566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&closureIS));
11029ffc88e4SToby Isaac   }
11039566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11049566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11059ffc88e4SToby Isaac   PetscFunctionReturn(0);
11069ffc88e4SToby Isaac }
11079ffc88e4SToby Isaac 
110824d039d7SMichael Lange /*@
110924d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
111024d039d7SMichael Lange 
111124d039d7SMichael Lange   Input Parameters:
111224d039d7SMichael Lange + dm     - The DM
1113a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
111424d039d7SMichael Lange 
111524d039d7SMichael Lange   Level: developer
111624d039d7SMichael Lange 
1117db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
111824d039d7SMichael Lange @*/
111924d039d7SMichael Lange PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
112070034214SMatthew G. Knepley {
112124d039d7SMichael Lange   IS              rankIS,   pointIS;
112224d039d7SMichael Lange   const PetscInt *ranks,   *points;
112324d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
112424d039d7SMichael Lange   PetscInt       *adj = NULL;
112570034214SMatthew G. Knepley 
112670034214SMatthew G. Knepley   PetscFunctionBegin;
11279566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &rankIS));
11289566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
11299566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
113024d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
113124d039d7SMichael Lange     const PetscInt rank = ranks[r];
113270034214SMatthew G. Knepley 
11339566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &pointIS));
11349566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
11359566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
113670034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
113724d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
11389566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency(dm, points[p], &adjSize, &adj));
11399566063dSJacob Faibussowitsch       for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(label, adj[a], rank));
114070034214SMatthew G. Knepley     }
11419566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
11429566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
114370034214SMatthew G. Knepley   }
11449566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11459566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11469566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
114724d039d7SMichael Lange   PetscFunctionReturn(0);
114870034214SMatthew G. Knepley }
114970034214SMatthew G. Knepley 
1150be200f8dSMichael Lange /*@
1151be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
1152be200f8dSMichael Lange 
1153be200f8dSMichael Lange   Input Parameters:
1154be200f8dSMichael Lange + dm     - The DM
1155a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
1156be200f8dSMichael Lange 
1157be200f8dSMichael Lange   Level: developer
1158be200f8dSMichael Lange 
1159be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
1160be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
1161be200f8dSMichael Lange 
1162db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1163be200f8dSMichael Lange @*/
1164be200f8dSMichael Lange PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
1165be200f8dSMichael Lange {
1166be200f8dSMichael Lange   MPI_Comm        comm;
1167be200f8dSMichael Lange   PetscMPIInt     rank;
1168be200f8dSMichael Lange   PetscSF         sfPoint;
11695d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
1170be200f8dSMichael Lange   IS              rankIS, pointIS;
1171be200f8dSMichael Lange   const PetscInt *ranks;
1172be200f8dSMichael Lange   PetscInt        numRanks, r;
1173be200f8dSMichael Lange 
1174be200f8dSMichael Lange   PetscFunctionBegin;
11759566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
11769566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
11779566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
11785d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
11799566063dSJacob Faibussowitsch   PetscCall(DMLabelGather(label, sfPoint, &lblLeaves));
11809566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(lblLeaves, &rankIS));
11819566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
11829566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
11835d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
11845d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
11855d04f6ebSMichael Lange     if (remoteRank == rank) continue;
11869566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS));
11879566063dSJacob Faibussowitsch     PetscCall(DMLabelInsertIS(label, pointIS, remoteRank));
11889566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
11895d04f6ebSMichael Lange   }
11909566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11919566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11929566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lblLeaves));
1193be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
11949566063dSJacob Faibussowitsch   PetscCall(DMLabelDistribute(label, sfPoint, &lblRoots));
11959566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(lblRoots, &rankIS));
11969566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
11979566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
1198be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
1199be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
1200be200f8dSMichael Lange     if (remoteRank == rank) continue;
12019566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS));
12029566063dSJacob Faibussowitsch     PetscCall(DMLabelInsertIS(label, pointIS, remoteRank));
12039566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
1204be200f8dSMichael Lange   }
12059566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
12069566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
12079566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lblRoots));
1208be200f8dSMichael Lange   PetscFunctionReturn(0);
1209be200f8dSMichael Lange }
1210be200f8dSMichael Lange 
12111fd9873aSMichael Lange /*@
12121fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
12131fd9873aSMichael Lange 
12141fd9873aSMichael Lange   Input Parameters:
12151fd9873aSMichael Lange + dm        - The DM
1216a5b23f4aSJose E. Roman . rootLabel - DMLabel assigning ranks to local roots
1217fe2efc57SMark - processSF - A star forest mapping into the local index on each remote rank
12181fd9873aSMichael Lange 
12191fd9873aSMichael Lange   Output Parameter:
1220a5b23f4aSJose E. Roman . leafLabel - DMLabel assigning ranks to remote roots
12211fd9873aSMichael Lange 
12221fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
12231fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
12241fd9873aSMichael Lange 
12251fd9873aSMichael Lange   Level: developer
12261fd9873aSMichael Lange 
1227db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
12281fd9873aSMichael Lange @*/
12291fd9873aSMichael Lange PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
12301fd9873aSMichael Lange {
12311fd9873aSMichael Lange   MPI_Comm           comm;
1232874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
1233874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
12341fd9873aSMichael Lange   PetscSF            sfPoint;
1235874ddda9SLisandro Dalcin   PetscSection       rootSection;
12361fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
12371fd9873aSMichael Lange   const PetscSFNode *remote;
12381fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
12391fd9873aSMichael Lange   IS                 valueIS;
1240874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
12411fd9873aSMichael Lange 
12421fd9873aSMichael Lange   PetscFunctionBegin;
12439566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_PartLabelInvert,dm,0,0,0));
12449566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
12459566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
12469566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
12479566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
12481fd9873aSMichael Lange 
12491fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
12509566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &rootSection));
12519566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootSection, 0, size));
12529566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(rootLabel, &valueIS));
12539566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(valueIS, &numNeighbors));
12549566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(valueIS, &neighbors));
12551fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
12569566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints));
12579566063dSJacob Faibussowitsch     PetscCall(PetscSectionAddDof(rootSection, neighbors[n], numPoints));
12581fd9873aSMichael Lange   }
12599566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootSection));
12609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(rootSection, &rootSize));
12619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rootSize, &rootPoints));
12629566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote));
12631fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
12641fd9873aSMichael Lange     IS              pointIS;
12651fd9873aSMichael Lange     const PetscInt *points;
12661fd9873aSMichael Lange 
12679566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(rootSection, neighbors[n], &off));
12689566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS));
12699566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
12709566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
12711fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
12729566063dSJacob Faibussowitsch       if (local) PetscCall(PetscFindInt(points[p], nleaves, local, &l));
1273f8987ae8SMichael Lange       else       {l = -1;}
12741fd9873aSMichael Lange       if (l >= 0) {rootPoints[off+p] = remote[l];}
12751fd9873aSMichael Lange       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
12761fd9873aSMichael Lange     }
12779566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
12789566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
12791fd9873aSMichael Lange   }
1280874ddda9SLisandro Dalcin 
1281874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
1282874ddda9SLisandro Dalcin   if (!processSF) {
1283874ddda9SLisandro Dalcin     PetscInt64  counter = 0;
1284874ddda9SLisandro Dalcin     PetscBool   locOverflow = PETSC_FALSE;
1285874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
1286874ddda9SLisandro Dalcin 
12879566063dSJacob Faibussowitsch     PetscCall(PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls));
1288874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
12899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootSection, neighbors[n], &dof));
12909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootSection, neighbors[n], &off));
1291874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
1292874ddda9SLisandro Dalcin       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
1293874ddda9SLisandro Dalcin       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
1294874ddda9SLisandro Dalcin #endif
1295874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt) dof;
1296874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt) off;
1297874ddda9SLisandro Dalcin     }
12989566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm));
1299874ddda9SLisandro Dalcin     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
1300874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
13019566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm));
1302874ddda9SLisandro Dalcin     if (!mpiOverflow) {
13039566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm,"Using Alltoallv for mesh distribution\n"));
1304874ddda9SLisandro Dalcin       leafSize = (PetscInt) counter;
13059566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(leafSize, &leafPoints));
13069566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm));
1307874ddda9SLisandro Dalcin     }
13089566063dSJacob Faibussowitsch     PetscCall(PetscFree4(scounts, sdispls, rcounts, rdispls));
1309874ddda9SLisandro Dalcin   }
1310874ddda9SLisandro Dalcin 
1311874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
1312874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
1313874ddda9SLisandro Dalcin     PetscSF      procSF;
1314874ddda9SLisandro Dalcin     PetscSection leafSection;
1315874ddda9SLisandro Dalcin 
1316874ddda9SLisandro Dalcin     if (processSF) {
13179566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm,"Using processSF for mesh distribution\n"));
13189566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)processSF));
1319874ddda9SLisandro Dalcin       procSF = processSF;
1320874ddda9SLisandro Dalcin     } else {
13219566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm,"Using processSF for mesh distribution (MPI overflow)\n"));
13229566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm,&procSF));
13239566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphWithPattern(procSF,NULL,PETSCSF_PATTERN_ALLTOALL));
1324874ddda9SLisandro Dalcin     }
1325874ddda9SLisandro Dalcin 
13269566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection));
13279566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeData(dm, procSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints));
13289566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafSection, &leafSize));
13299566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
13309566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&procSF));
1331874ddda9SLisandro Dalcin   }
1332874ddda9SLisandro Dalcin 
1333874ddda9SLisandro Dalcin   for (p = 0; p < leafSize; p++) {
13349566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank));
13351fd9873aSMichael Lange   }
1336874ddda9SLisandro Dalcin 
13379566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(valueIS, &neighbors));
13389566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&valueIS));
13399566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootSection));
13409566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootPoints));
13419566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafPoints));
13429566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_PartLabelInvert,dm,0,0,0));
13431fd9873aSMichael Lange   PetscFunctionReturn(0);
13441fd9873aSMichael Lange }
13451fd9873aSMichael Lange 
1346aa3148a8SMichael Lange /*@
1347aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
1348aa3148a8SMichael Lange 
1349aa3148a8SMichael Lange   Input Parameters:
1350aa3148a8SMichael Lange + dm    - The DM
1351a5b23f4aSJose E. Roman - label - DMLabel assigning ranks to remote roots
1352aa3148a8SMichael Lange 
1353aa3148a8SMichael Lange   Output Parameter:
1354fe2efc57SMark . sf    - The star forest communication context encapsulating the defined mapping
1355aa3148a8SMichael Lange 
1356aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
1357aa3148a8SMichael Lange 
1358aa3148a8SMichael Lange   Level: developer
1359aa3148a8SMichael Lange 
1360db781477SPatrick Sanan .seealso: `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1361aa3148a8SMichael Lange @*/
1362aa3148a8SMichael Lange PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
1363aa3148a8SMichael Lange {
13646e203dd9SStefano Zampini   PetscMPIInt     rank;
13656e203dd9SStefano Zampini   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
1366aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
13676e203dd9SStefano Zampini   IS              remoteRootIS, neighborsIS;
13686e203dd9SStefano Zampini   const PetscInt *remoteRoots, *neighbors;
1369aa3148a8SMichael Lange 
1370aa3148a8SMichael Lange   PetscFunctionBegin;
13719566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_PartLabelCreateSF,dm,0,0,0));
13729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
1373aa3148a8SMichael Lange 
13749566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &neighborsIS));
13756e203dd9SStefano Zampini #if 0
13766e203dd9SStefano Zampini   {
13776e203dd9SStefano Zampini     IS is;
13789566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(neighborsIS, &is));
13799566063dSJacob Faibussowitsch     PetscCall(ISSort(is));
13809566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&neighborsIS));
13816e203dd9SStefano Zampini     neighborsIS = is;
13826e203dd9SStefano Zampini   }
13836e203dd9SStefano Zampini #endif
13849566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(neighborsIS, &nNeighbors));
13859566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(neighborsIS, &neighbors));
13866e203dd9SStefano Zampini   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
13879566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(label, neighbors[n], &numPoints));
1388aa3148a8SMichael Lange     numRemote += numPoints;
1389aa3148a8SMichael Lange   }
13909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRemote, &remotePoints));
139143f7d02bSMichael Lange   /* Put owned points first */
13929566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumSize(label, rank, &numPoints));
139343f7d02bSMichael Lange   if (numPoints > 0) {
13949566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &remoteRootIS));
13959566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(remoteRootIS, &remoteRoots));
139643f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
139743f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
139843f7d02bSMichael Lange       remotePoints[idx].rank = rank;
139943f7d02bSMichael Lange       idx++;
140043f7d02bSMichael Lange     }
14019566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(remoteRootIS, &remoteRoots));
14029566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&remoteRootIS));
140343f7d02bSMichael Lange   }
140443f7d02bSMichael Lange   /* Now add remote points */
14056e203dd9SStefano Zampini   for (n = 0; n < nNeighbors; ++n) {
14066e203dd9SStefano Zampini     const PetscInt nn = neighbors[n];
14076e203dd9SStefano Zampini 
14089566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(label, nn, &numPoints));
14096e203dd9SStefano Zampini     if (nn == rank || numPoints <= 0) continue;
14109566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, nn, &remoteRootIS));
14119566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(remoteRootIS, &remoteRoots));
1412aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
1413aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
14146e203dd9SStefano Zampini       remotePoints[idx].rank = nn;
1415aa3148a8SMichael Lange       idx++;
1416aa3148a8SMichael Lange     }
14179566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(remoteRootIS, &remoteRoots));
14189566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&remoteRootIS));
1419aa3148a8SMichael Lange   }
14209566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject) dm), sf));
14219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
14229566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER));
14239566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(*sf));
14249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&neighborsIS));
14259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_PartLabelCreateSF,dm,0,0,0));
142670034214SMatthew G. Knepley   PetscFunctionReturn(0);
142770034214SMatthew G. Knepley }
1428cb87ef4cSFlorian Wechsung 
1429abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PARMETIS)
1430abe9303eSLisandro Dalcin #include <parmetis.h>
1431abe9303eSLisandro Dalcin #endif
1432abe9303eSLisandro Dalcin 
14336a3739e5SFlorian Wechsung /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
14346a3739e5SFlorian Wechsung  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
14356a3739e5SFlorian Wechsung  * them out in that case. */
14366a3739e5SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
14377a82c785SFlorian Wechsung /*@C
14387f57c1a4SFlorian Wechsung 
14397f57c1a4SFlorian Wechsung   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).
14407f57c1a4SFlorian Wechsung 
14417f57c1a4SFlorian Wechsung   Input parameters:
14427f57c1a4SFlorian Wechsung + dm                - The DMPlex object.
1443fe2efc57SMark . n                 - The number of points.
1444fe2efc57SMark . pointsToRewrite   - The points in the SF whose ownership will change.
1445fe2efc57SMark . targetOwners      - New owner for each element in pointsToRewrite.
1446fe2efc57SMark - degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.
14477f57c1a4SFlorian Wechsung 
14487f57c1a4SFlorian Wechsung   Level: developer
14497f57c1a4SFlorian Wechsung 
14507f57c1a4SFlorian Wechsung @*/
14517f57c1a4SFlorian Wechsung static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
14527f57c1a4SFlorian Wechsung {
14535f80ce2aSJacob Faibussowitsch   PetscInt      pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
14547f57c1a4SFlorian Wechsung   PetscInt     *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
14557f57c1a4SFlorian Wechsung   PetscSFNode  *leafLocationsNew;
14567f57c1a4SFlorian Wechsung   const         PetscSFNode *iremote;
14577f57c1a4SFlorian Wechsung   const         PetscInt *ilocal;
14587f57c1a4SFlorian Wechsung   PetscBool    *isLeaf;
14597f57c1a4SFlorian Wechsung   PetscSF       sf;
14607f57c1a4SFlorian Wechsung   MPI_Comm      comm;
14615a30b08bSFlorian Wechsung   PetscMPIInt   rank, size;
14627f57c1a4SFlorian Wechsung 
14637f57c1a4SFlorian Wechsung   PetscFunctionBegin;
14649566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
14659566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
14669566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
14679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
14687f57c1a4SFlorian Wechsung 
14699566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
14709566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
14719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &isLeaf));
14727f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
14737f57c1a4SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
14747f57c1a4SFlorian Wechsung   }
14757f57c1a4SFlorian Wechsung   for (i=0; i<nleafs; i++) {
14767f57c1a4SFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
14777f57c1a4SFlorian Wechsung   }
14787f57c1a4SFlorian Wechsung 
14799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart+1, &cumSumDegrees));
14807f57c1a4SFlorian Wechsung   cumSumDegrees[0] = 0;
14817f57c1a4SFlorian Wechsung   for (i=1; i<=pEnd-pStart; i++) {
14827f57c1a4SFlorian Wechsung     cumSumDegrees[i] = cumSumDegrees[i-1] + degrees[i-1];
14837f57c1a4SFlorian Wechsung   }
14847f57c1a4SFlorian Wechsung   sumDegrees = cumSumDegrees[pEnd-pStart];
14857f57c1a4SFlorian Wechsung   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
14867f57c1a4SFlorian Wechsung 
14879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(sumDegrees, &locationsOfLeafs));
14889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &rankOnLeafs));
14897f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
14907f57c1a4SFlorian Wechsung     rankOnLeafs[i] = rank;
14917f57c1a4SFlorian Wechsung   }
14929566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
14939566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
14949566063dSJacob Faibussowitsch   PetscCall(PetscFree(rankOnLeafs));
14957f57c1a4SFlorian Wechsung 
14967f57c1a4SFlorian Wechsung   /* get the remote local points of my leaves */
14979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs));
14989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &points));
14997f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
15007f57c1a4SFlorian Wechsung     points[i] = pStart+i;
15017f57c1a4SFlorian Wechsung   }
15029566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
15039566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
15049566063dSJacob Faibussowitsch   PetscCall(PetscFree(points));
15057f57c1a4SFlorian Wechsung   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
15069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &newOwners));
15079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &newNumbers));
15087f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
15097f57c1a4SFlorian Wechsung     newOwners[i] = -1;
15107f57c1a4SFlorian Wechsung     newNumbers[i] = -1;
15117f57c1a4SFlorian Wechsung   }
15127f57c1a4SFlorian Wechsung   {
15137f57c1a4SFlorian Wechsung     PetscInt oldNumber, newNumber, oldOwner, newOwner;
15147f57c1a4SFlorian Wechsung     for (i=0; i<n; i++) {
15157f57c1a4SFlorian Wechsung       oldNumber = pointsToRewrite[i];
15167f57c1a4SFlorian Wechsung       newNumber = -1;
15177f57c1a4SFlorian Wechsung       oldOwner = rank;
15187f57c1a4SFlorian Wechsung       newOwner = targetOwners[i];
15197f57c1a4SFlorian Wechsung       if (oldOwner == newOwner) {
15207f57c1a4SFlorian Wechsung         newNumber = oldNumber;
15217f57c1a4SFlorian Wechsung       } else {
15227f57c1a4SFlorian Wechsung         for (j=0; j<degrees[oldNumber]; j++) {
15237f57c1a4SFlorian Wechsung           if (locationsOfLeafs[cumSumDegrees[oldNumber]+j] == newOwner) {
15247f57c1a4SFlorian Wechsung             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber]+j];
15257f57c1a4SFlorian Wechsung             break;
15267f57c1a4SFlorian Wechsung           }
15277f57c1a4SFlorian Wechsung         }
15287f57c1a4SFlorian Wechsung       }
15295f80ce2aSJacob Faibussowitsch       PetscCheck(newNumber != -1,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
15307f57c1a4SFlorian Wechsung 
15317f57c1a4SFlorian Wechsung       newOwners[oldNumber] = newOwner;
15327f57c1a4SFlorian Wechsung       newNumbers[oldNumber] = newNumber;
15337f57c1a4SFlorian Wechsung     }
15347f57c1a4SFlorian Wechsung   }
15359566063dSJacob Faibussowitsch   PetscCall(PetscFree(cumSumDegrees));
15369566063dSJacob Faibussowitsch   PetscCall(PetscFree(locationsOfLeafs));
15379566063dSJacob Faibussowitsch   PetscCall(PetscFree(remoteLocalPointOfLeafs));
15387f57c1a4SFlorian Wechsung 
15399566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners,MPI_REPLACE));
15409566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners,MPI_REPLACE));
15419566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers,MPI_REPLACE));
15429566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers,MPI_REPLACE));
15437f57c1a4SFlorian Wechsung 
15447f57c1a4SFlorian Wechsung   /* Now count how many leafs we have on each processor. */
15457f57c1a4SFlorian Wechsung   leafCounter=0;
15467f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
15477f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
15487f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
15497f57c1a4SFlorian Wechsung         leafCounter++;
15507f57c1a4SFlorian Wechsung       }
15517f57c1a4SFlorian Wechsung     } else {
15527f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
15537f57c1a4SFlorian Wechsung         leafCounter++;
15547f57c1a4SFlorian Wechsung       }
15557f57c1a4SFlorian Wechsung     }
15567f57c1a4SFlorian Wechsung   }
15577f57c1a4SFlorian Wechsung 
15587f57c1a4SFlorian Wechsung   /* Now set up the new sf by creating the leaf arrays */
15599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(leafCounter, &leafsNew));
15609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(leafCounter, &leafLocationsNew));
15617f57c1a4SFlorian Wechsung 
15627f57c1a4SFlorian Wechsung   leafCounter = 0;
15637f57c1a4SFlorian Wechsung   counter = 0;
15647f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
15657f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
15667f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
15677f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
15687f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = newOwners[i];
15697f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = newNumbers[i];
15707f57c1a4SFlorian Wechsung         leafCounter++;
15717f57c1a4SFlorian Wechsung       }
15727f57c1a4SFlorian Wechsung     } else {
15737f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
15747f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
15757f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = iremote[counter].rank;
15767f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = iremote[counter].index;
15777f57c1a4SFlorian Wechsung         leafCounter++;
15787f57c1a4SFlorian Wechsung       }
15797f57c1a4SFlorian Wechsung     }
15807f57c1a4SFlorian Wechsung     if (isLeaf[i]) {
15817f57c1a4SFlorian Wechsung       counter++;
15827f57c1a4SFlorian Wechsung     }
15837f57c1a4SFlorian Wechsung   }
15847f57c1a4SFlorian Wechsung 
15859566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER));
15869566063dSJacob Faibussowitsch   PetscCall(PetscFree(newOwners));
15879566063dSJacob Faibussowitsch   PetscCall(PetscFree(newNumbers));
15889566063dSJacob Faibussowitsch   PetscCall(PetscFree(isLeaf));
15897f57c1a4SFlorian Wechsung   PetscFunctionReturn(0);
15907f57c1a4SFlorian Wechsung }
15917f57c1a4SFlorian Wechsung 
1592125d2a8fSFlorian Wechsung static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
1593125d2a8fSFlorian Wechsung {
15945f80ce2aSJacob Faibussowitsch   PetscInt    *distribution, min, max, sum;
15955a30b08bSFlorian Wechsung   PetscMPIInt rank, size;
15965f80ce2aSJacob Faibussowitsch 
1597125d2a8fSFlorian Wechsung   PetscFunctionBegin;
15989566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
15999566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
16009566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &distribution));
16015f80ce2aSJacob Faibussowitsch   for (PetscInt i=0; i<n; i++) {
1602125d2a8fSFlorian Wechsung     if (part) distribution[part[i]] += vtxwgt[skip*i];
1603125d2a8fSFlorian Wechsung     else distribution[rank] += vtxwgt[skip*i];
1604125d2a8fSFlorian Wechsung   }
16059566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm));
1606125d2a8fSFlorian Wechsung   min = distribution[0];
1607125d2a8fSFlorian Wechsung   max = distribution[0];
1608125d2a8fSFlorian Wechsung   sum = distribution[0];
16095f80ce2aSJacob Faibussowitsch   for (PetscInt i=1; i<size; i++) {
1610125d2a8fSFlorian Wechsung     if (distribution[i]<min) min=distribution[i];
1611125d2a8fSFlorian Wechsung     if (distribution[i]>max) max=distribution[i];
1612125d2a8fSFlorian Wechsung     sum += distribution[i];
1613125d2a8fSFlorian Wechsung   }
161463a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "Min: %" PetscInt_FMT ", Avg: %" PetscInt_FMT ", Max: %" PetscInt_FMT ", Balance: %f\n", min, sum/size, max, (max*1.*size)/sum));
16159566063dSJacob Faibussowitsch   PetscCall(PetscFree(distribution));
1616125d2a8fSFlorian Wechsung   PetscFunctionReturn(0);
1617125d2a8fSFlorian Wechsung }
1618125d2a8fSFlorian Wechsung 
16196a3739e5SFlorian Wechsung #endif
16206a3739e5SFlorian Wechsung 
1621cb87ef4cSFlorian Wechsung /*@
16225dc86ac1SFlorian 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.
1623cb87ef4cSFlorian Wechsung 
1624cb87ef4cSFlorian Wechsung   Input parameters:
1625ed44d270SFlorian Wechsung + dm               - The DMPlex object.
1626fe2efc57SMark . entityDepth      - depth of the entity to balance (0 -> balance vertices).
1627fe2efc57SMark . useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
1628fe2efc57SMark - parallel         - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.
1629cb87ef4cSFlorian Wechsung 
16308b879b41SFlorian Wechsung   Output parameters:
1631fe2efc57SMark . success          - whether the graph partitioning was successful or not. If not, try useInitialGuess=True and parallel=True.
16328b879b41SFlorian Wechsung 
163390ea27d8SSatish Balay   Level: intermediate
1634cb87ef4cSFlorian Wechsung 
1635cb87ef4cSFlorian Wechsung @*/
1636cb87ef4cSFlorian Wechsung 
16378b879b41SFlorian Wechsung PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
1638cb87ef4cSFlorian Wechsung {
163941525646SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
1640cb87ef4cSFlorian Wechsung   PetscSF     sf;
16410faf6628SFlorian Wechsung   PetscInt    ierr, i, j, idx, jdx;
16427f57c1a4SFlorian Wechsung   PetscInt    eBegin, eEnd, nroots, nleafs, pStart, pEnd;
16437f57c1a4SFlorian Wechsung   const       PetscInt *degrees, *ilocal;
16447f57c1a4SFlorian Wechsung   const       PetscSFNode *iremote;
1645cb87ef4cSFlorian Wechsung   PetscBool   *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
1646cf818975SFlorian Wechsung   PetscInt    numExclusivelyOwned, numNonExclusivelyOwned;
1647cb87ef4cSFlorian Wechsung   PetscMPIInt rank, size;
16487f57c1a4SFlorian Wechsung   PetscInt    *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
16495dc86ac1SFlorian Wechsung   const       PetscInt *cumSumVertices;
1650cb87ef4cSFlorian Wechsung   PetscInt    offset, counter;
16517f57c1a4SFlorian Wechsung   PetscInt    lenadjncy;
1652cb87ef4cSFlorian Wechsung   PetscInt    *xadj, *adjncy, *vtxwgt;
1653cb87ef4cSFlorian Wechsung   PetscInt    lenxadj;
1654cb87ef4cSFlorian Wechsung   PetscInt    *adjwgt = NULL;
1655cb87ef4cSFlorian Wechsung   PetscInt    *part, *options;
1656cf818975SFlorian Wechsung   PetscInt    nparts, wgtflag, numflag, ncon, edgecut;
1657cb87ef4cSFlorian Wechsung   real_t      *ubvec;
1658cb87ef4cSFlorian Wechsung   PetscInt    *firstVertices, *renumbering;
1659cb87ef4cSFlorian Wechsung   PetscInt    failed, failedGlobal;
1660cb87ef4cSFlorian Wechsung   MPI_Comm    comm;
16614baf1206SFlorian Wechsung   Mat         A, Apre;
166212617df9SFlorian Wechsung   const char *prefix = NULL;
16637d197802SFlorian Wechsung   PetscViewer       viewer;
16647d197802SFlorian Wechsung   PetscViewerFormat format;
16655a30b08bSFlorian Wechsung   PetscLayout layout;
166612617df9SFlorian Wechsung 
166712617df9SFlorian Wechsung   PetscFunctionBegin;
16688b879b41SFlorian Wechsung   if (success) *success = PETSC_FALSE;
16699566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
16709566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
16719566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
16727f57c1a4SFlorian Wechsung   if (size==1) PetscFunctionReturn(0);
16737f57c1a4SFlorian Wechsung 
16749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
167541525646SFlorian Wechsung 
16769566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm,((PetscObject)dm)->options, prefix,"-dm_rebalance_partition_view",&viewer,&format,NULL));
1677*1baa6e33SBarry Smith   if (viewer) PetscCall(PetscViewerPushFormat(viewer,format));
16787d197802SFlorian Wechsung 
1679ed44d270SFlorian Wechsung   /* Figure out all points in the plex that we are interested in balancing. */
16809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd));
16819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
16829566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &toBalance));
1683cf818975SFlorian Wechsung 
1684cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
16855a7e692eSFlorian Wechsung     toBalance[i] = (PetscBool)(i-pStart>=eBegin && i-pStart<eEnd);
1686cb87ef4cSFlorian Wechsung   }
1687cb87ef4cSFlorian Wechsung 
1688cf818975SFlorian Wechsung   /* There are three types of points:
1689cf818975SFlorian Wechsung    * exclusivelyOwned: points that are owned by this process and only seen by this process
1690cf818975SFlorian Wechsung    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
1691cf818975SFlorian Wechsung    * leaf: a point that is seen by this process but owned by a different process
1692cf818975SFlorian Wechsung    */
16939566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
16949566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
16959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &isLeaf));
16969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &isNonExclusivelyOwned));
16979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &isExclusivelyOwned));
1698cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
1699cb87ef4cSFlorian Wechsung     isNonExclusivelyOwned[i] = PETSC_FALSE;
1700cb87ef4cSFlorian Wechsung     isExclusivelyOwned[i] = PETSC_FALSE;
1701cf818975SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
1702cb87ef4cSFlorian Wechsung   }
1703cf818975SFlorian Wechsung 
1704cf818975SFlorian Wechsung   /* start by marking all the leafs */
1705cb87ef4cSFlorian Wechsung   for (i=0; i<nleafs; i++) {
1706cb87ef4cSFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
1707cb87ef4cSFlorian Wechsung   }
1708cb87ef4cSFlorian Wechsung 
1709cf818975SFlorian Wechsung   /* for an owned point, we can figure out whether another processor sees it or
1710cf818975SFlorian Wechsung    * not by calculating its degree */
17119566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(sf, &degrees));
17129566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(sf, &degrees));
1713cf818975SFlorian Wechsung 
1714cb87ef4cSFlorian Wechsung   numExclusivelyOwned = 0;
1715cb87ef4cSFlorian Wechsung   numNonExclusivelyOwned = 0;
1716cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
1717cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
17187f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1719cb87ef4cSFlorian Wechsung         isNonExclusivelyOwned[i] = PETSC_TRUE;
1720cb87ef4cSFlorian Wechsung         numNonExclusivelyOwned += 1;
1721cb87ef4cSFlorian Wechsung       } else {
1722cb87ef4cSFlorian Wechsung         if (!isLeaf[i]) {
1723cb87ef4cSFlorian Wechsung           isExclusivelyOwned[i] = PETSC_TRUE;
1724cb87ef4cSFlorian Wechsung           numExclusivelyOwned += 1;
1725cb87ef4cSFlorian Wechsung         }
1726cb87ef4cSFlorian Wechsung       }
1727cb87ef4cSFlorian Wechsung     }
1728cb87ef4cSFlorian Wechsung   }
1729cb87ef4cSFlorian Wechsung 
1730cf818975SFlorian Wechsung   /* We are going to build a graph with one vertex per core representing the
1731cf818975SFlorian Wechsung    * exclusively owned points and then one vertex per nonExclusively owned
1732cf818975SFlorian Wechsung    * point. */
1733cb87ef4cSFlorian Wechsung 
17349566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &layout));
17359566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned));
17369566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
17379566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRanges(layout, &cumSumVertices));
17385dc86ac1SFlorian Wechsung 
17399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &globalNumbersOfLocalOwnedVertices));
17405a427404SJunchao Zhang   for (i=0; i<pEnd-pStart; i++) {globalNumbersOfLocalOwnedVertices[i] = pStart - 1;}
1741cb87ef4cSFlorian Wechsung   offset = cumSumVertices[rank];
1742cb87ef4cSFlorian Wechsung   counter = 0;
1743cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
1744cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
17457f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1746cb87ef4cSFlorian Wechsung         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
1747cb87ef4cSFlorian Wechsung         counter++;
1748cb87ef4cSFlorian Wechsung       }
1749cb87ef4cSFlorian Wechsung     }
1750cb87ef4cSFlorian Wechsung   }
1751cb87ef4cSFlorian Wechsung 
1752cb87ef4cSFlorian Wechsung   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
17539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd-pStart, &leafGlobalNumbers));
17549566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers,MPI_REPLACE));
17559566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers,MPI_REPLACE));
1756cb87ef4cSFlorian Wechsung 
17570faf6628SFlorian Wechsung   /* Now start building the data structure for ParMETIS */
1758cb87ef4cSFlorian Wechsung 
17599566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &Apre));
17609566063dSJacob Faibussowitsch   PetscCall(MatSetType(Apre, MATPREALLOCATOR));
17619566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(Apre, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]));
17629566063dSJacob Faibussowitsch   PetscCall(MatSetUp(Apre));
17638c9a1619SFlorian Wechsung 
17648c9a1619SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
17658c9a1619SFlorian Wechsung     if (toBalance[i]) {
17660faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
17670faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
17680faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
17690faf6628SFlorian Wechsung       else continue;
17709566063dSJacob Faibussowitsch       PetscCall(MatSetValue(Apre, idx, jdx, 1, INSERT_VALUES));
17719566063dSJacob Faibussowitsch       PetscCall(MatSetValue(Apre, jdx, idx, 1, INSERT_VALUES));
17724baf1206SFlorian Wechsung     }
17734baf1206SFlorian Wechsung   }
17744baf1206SFlorian Wechsung 
17759566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Apre, MAT_FINAL_ASSEMBLY));
17769566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Apre, MAT_FINAL_ASSEMBLY));
17774baf1206SFlorian Wechsung 
17789566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
17799566063dSJacob Faibussowitsch   PetscCall(MatSetType(A, MATMPIAIJ));
17809566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(A, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]));
17819566063dSJacob Faibussowitsch   PetscCall(MatPreallocatorPreallocate(Apre, PETSC_FALSE, A));
17829566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Apre));
17834baf1206SFlorian Wechsung 
17844baf1206SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
17854baf1206SFlorian Wechsung     if (toBalance[i]) {
17860faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
17870faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
17880faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
17890faf6628SFlorian Wechsung       else continue;
17909566063dSJacob Faibussowitsch       PetscCall(MatSetValue(A, idx, jdx, 1, INSERT_VALUES));
17919566063dSJacob Faibussowitsch       PetscCall(MatSetValue(A, jdx, idx, 1, INSERT_VALUES));
17920941debbSFlorian Wechsung     }
17930941debbSFlorian Wechsung   }
17948c9a1619SFlorian Wechsung 
17959566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
17969566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
17979566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafGlobalNumbers));
17989566063dSJacob Faibussowitsch   PetscCall(PetscFree(globalNumbersOfLocalOwnedVertices));
17994baf1206SFlorian Wechsung 
180041525646SFlorian Wechsung   nparts = size;
180141525646SFlorian Wechsung   wgtflag = 2;
180241525646SFlorian Wechsung   numflag = 0;
180341525646SFlorian Wechsung   ncon = 2;
180441525646SFlorian Wechsung   real_t *tpwgts;
18059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon * nparts, &tpwgts));
180641525646SFlorian Wechsung   for (i=0; i<ncon*nparts; i++) {
180741525646SFlorian Wechsung     tpwgts[i] = 1./(nparts);
180841525646SFlorian Wechsung   }
180941525646SFlorian Wechsung 
18109566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon, &ubvec));
181141525646SFlorian Wechsung   ubvec[0] = 1.01;
18125a30b08bSFlorian Wechsung   ubvec[1] = 1.01;
18138c9a1619SFlorian Wechsung   lenadjncy = 0;
18148c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
18158c9a1619SFlorian Wechsung     PetscInt temp=0;
18169566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL));
18178c9a1619SFlorian Wechsung     lenadjncy += temp;
18189566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL));
18198c9a1619SFlorian Wechsung   }
18209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lenadjncy, &adjncy));
18217407ba93SFlorian Wechsung   lenxadj = 2 + numNonExclusivelyOwned;
18229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lenxadj, &xadj));
18230941debbSFlorian Wechsung   xadj[0] = 0;
18248c9a1619SFlorian Wechsung   counter = 0;
18258c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
18262953a68cSFlorian Wechsung     PetscInt        temp=0;
18272953a68cSFlorian Wechsung     const PetscInt *cols;
18289566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL));
18299566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(&adjncy[counter], cols, temp));
18308c9a1619SFlorian Wechsung     counter += temp;
18310941debbSFlorian Wechsung     xadj[i+1] = counter;
18329566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL));
18338c9a1619SFlorian Wechsung   }
18348c9a1619SFlorian Wechsung 
18359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cumSumVertices[rank+1]-cumSumVertices[rank], &part));
18369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon*(1 + numNonExclusivelyOwned), &vtxwgt));
183741525646SFlorian Wechsung   vtxwgt[0] = numExclusivelyOwned;
183841525646SFlorian Wechsung   if (ncon>1) vtxwgt[1] = 1;
183941525646SFlorian Wechsung   for (i=0; i<numNonExclusivelyOwned; i++) {
184041525646SFlorian Wechsung     vtxwgt[ncon*(i+1)] = 1;
184141525646SFlorian Wechsung     if (ncon>1) vtxwgt[ncon*(i+1)+1] = 0;
184241525646SFlorian Wechsung   }
18438c9a1619SFlorian Wechsung 
18445dc86ac1SFlorian Wechsung   if (viewer) {
184563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %" PetscInt_FMT " on interface of mesh distribution.\n", entityDepth));
184663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %" PetscInt_FMT "\n", cumSumVertices[size]));
184712617df9SFlorian Wechsung   }
184841525646SFlorian Wechsung   if (parallel) {
18499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(4, &options));
18505a30b08bSFlorian Wechsung     options[0] = 1;
18515a30b08bSFlorian Wechsung     options[1] = 0; /* Verbosity */
18525a30b08bSFlorian Wechsung     options[2] = 0; /* Seed */
18535a30b08bSFlorian Wechsung     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
18549566063dSJacob Faibussowitsch     if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n"));
18558c9a1619SFlorian Wechsung     if (useInitialGuess) {
18569566063dSJacob Faibussowitsch       if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n"));
18578c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_RefineKway");
18585dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_RefineKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
18595f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
18608c9a1619SFlorian Wechsung       PetscStackPop;
18618c9a1619SFlorian Wechsung     } else {
18628c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_PartKway");
18635dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_PartKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
18648c9a1619SFlorian Wechsung       PetscStackPop;
18655f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
18668c9a1619SFlorian Wechsung     }
18679566063dSJacob Faibussowitsch     PetscCall(PetscFree(options));
186841525646SFlorian Wechsung   } else {
18699566063dSJacob Faibussowitsch     if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n"));
187041525646SFlorian Wechsung     Mat As;
187141525646SFlorian Wechsung     PetscInt numRows;
187241525646SFlorian Wechsung     PetscInt *partGlobal;
18739566063dSJacob Faibussowitsch     PetscCall(MatCreateRedundantMatrix(A, size, MPI_COMM_NULL, MAT_INITIAL_MATRIX, &As));
1874cb87ef4cSFlorian Wechsung 
187541525646SFlorian Wechsung     PetscInt *numExclusivelyOwnedAll;
18769566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &numExclusivelyOwnedAll));
187741525646SFlorian Wechsung     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
18789566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,numExclusivelyOwnedAll,1,MPIU_INT,comm));
1879cb87ef4cSFlorian Wechsung 
18809566063dSJacob Faibussowitsch     PetscCall(MatGetSize(As, &numRows, NULL));
18819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRows, &partGlobal));
1882dd400576SPatrick Sanan     if (rank == 0) {
188341525646SFlorian Wechsung       PetscInt *adjncy_g, *xadj_g, *vtxwgt_g;
188441525646SFlorian Wechsung       lenadjncy = 0;
188541525646SFlorian Wechsung 
188641525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
188741525646SFlorian Wechsung         PetscInt temp=0;
18889566063dSJacob Faibussowitsch         PetscCall(MatGetRow(As, i, &temp, NULL, NULL));
188941525646SFlorian Wechsung         lenadjncy += temp;
18909566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(As, i, &temp, NULL, NULL));
189141525646SFlorian Wechsung       }
18929566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(lenadjncy, &adjncy_g));
189341525646SFlorian Wechsung       lenxadj = 1 + numRows;
18949566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(lenxadj, &xadj_g));
189541525646SFlorian Wechsung       xadj_g[0] = 0;
189641525646SFlorian Wechsung       counter = 0;
189741525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
18982953a68cSFlorian Wechsung         PetscInt        temp=0;
18992953a68cSFlorian Wechsung         const PetscInt *cols;
19009566063dSJacob Faibussowitsch         PetscCall(MatGetRow(As, i, &temp, &cols, NULL));
19019566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(&adjncy_g[counter], cols, temp));
190241525646SFlorian Wechsung         counter += temp;
190341525646SFlorian Wechsung         xadj_g[i+1] = counter;
19049566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(As, i, &temp, &cols, NULL));
190541525646SFlorian Wechsung       }
19069566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(2*numRows, &vtxwgt_g));
190741525646SFlorian Wechsung       for (i=0; i<size; i++) {
190841525646SFlorian Wechsung         vtxwgt_g[ncon*cumSumVertices[i]] = numExclusivelyOwnedAll[i];
190941525646SFlorian Wechsung         if (ncon>1) vtxwgt_g[ncon*cumSumVertices[i]+1] = 1;
191041525646SFlorian Wechsung         for (j=cumSumVertices[i]+1; j<cumSumVertices[i+1]; j++) {
191141525646SFlorian Wechsung           vtxwgt_g[ncon*j] = 1;
191241525646SFlorian Wechsung           if (ncon>1) vtxwgt_g[2*j+1] = 0;
191341525646SFlorian Wechsung         }
191441525646SFlorian Wechsung       }
19159566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(64, &options));
191641525646SFlorian Wechsung       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
19175f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
191841525646SFlorian Wechsung       options[METIS_OPTION_CONTIG] = 1;
191941525646SFlorian Wechsung       PetscStackPush("METIS_PartGraphKway");
192006b3913eSFlorian Wechsung       ierr = METIS_PartGraphKway(&numRows, &ncon, xadj_g, adjncy_g, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
192141525646SFlorian Wechsung       PetscStackPop;
19225f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
19239566063dSJacob Faibussowitsch       PetscCall(PetscFree(options));
19249566063dSJacob Faibussowitsch       PetscCall(PetscFree(xadj_g));
19259566063dSJacob Faibussowitsch       PetscCall(PetscFree(adjncy_g));
19269566063dSJacob Faibussowitsch       PetscCall(PetscFree(vtxwgt_g));
192741525646SFlorian Wechsung     }
19289566063dSJacob Faibussowitsch     PetscCall(PetscFree(numExclusivelyOwnedAll));
192941525646SFlorian Wechsung 
19305dc86ac1SFlorian Wechsung     /* Now scatter the parts array. */
19315dc86ac1SFlorian Wechsung     {
193281a13b52SFlorian Wechsung       PetscMPIInt *counts, *mpiCumSumVertices;
19339566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size, &counts));
19349566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(size+1, &mpiCumSumVertices));
19355dc86ac1SFlorian Wechsung       for (i=0; i<size; i++) {
19369566063dSJacob Faibussowitsch         PetscCall(PetscMPIIntCast(cumSumVertices[i+1] - cumSumVertices[i], &(counts[i])));
193741525646SFlorian Wechsung       }
193881a13b52SFlorian Wechsung       for (i=0; i<=size; i++) {
19399566063dSJacob Faibussowitsch         PetscCall(PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i])));
194081a13b52SFlorian Wechsung       }
19419566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm));
19429566063dSJacob Faibussowitsch       PetscCall(PetscFree(counts));
19439566063dSJacob Faibussowitsch       PetscCall(PetscFree(mpiCumSumVertices));
19445dc86ac1SFlorian Wechsung     }
19455dc86ac1SFlorian Wechsung 
19469566063dSJacob Faibussowitsch     PetscCall(PetscFree(partGlobal));
19479566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&As));
194841525646SFlorian Wechsung   }
1949cb87ef4cSFlorian Wechsung 
19509566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A));
19519566063dSJacob Faibussowitsch   PetscCall(PetscFree(ubvec));
19529566063dSJacob Faibussowitsch   PetscCall(PetscFree(tpwgts));
1953cb87ef4cSFlorian Wechsung 
1954cb87ef4cSFlorian Wechsung   /* Now rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
1955cb87ef4cSFlorian Wechsung 
19569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &firstVertices));
19579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(size, &renumbering));
1958cb87ef4cSFlorian Wechsung   firstVertices[rank] = part[0];
19599566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,firstVertices,1,MPIU_INT,comm));
1960cb87ef4cSFlorian Wechsung   for (i=0; i<size; i++) {
1961cb87ef4cSFlorian Wechsung     renumbering[firstVertices[i]] = i;
1962cb87ef4cSFlorian Wechsung   }
1963cb87ef4cSFlorian Wechsung   for (i=0; i<cumSumVertices[rank+1]-cumSumVertices[rank]; i++) {
1964cb87ef4cSFlorian Wechsung     part[i] = renumbering[part[i]];
1965cb87ef4cSFlorian Wechsung   }
1966cb87ef4cSFlorian Wechsung   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
1967cb87ef4cSFlorian Wechsung   failed = (PetscInt)(part[0] != rank);
19689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm));
1969cb87ef4cSFlorian Wechsung 
19709566063dSJacob Faibussowitsch   PetscCall(PetscFree(firstVertices));
19719566063dSJacob Faibussowitsch   PetscCall(PetscFree(renumbering));
19727f57c1a4SFlorian Wechsung 
1973cb87ef4cSFlorian Wechsung   if (failedGlobal > 0) {
19749566063dSJacob Faibussowitsch     PetscCall(PetscLayoutDestroy(&layout));
19759566063dSJacob Faibussowitsch     PetscCall(PetscFree(xadj));
19769566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjncy));
19779566063dSJacob Faibussowitsch     PetscCall(PetscFree(vtxwgt));
19789566063dSJacob Faibussowitsch     PetscCall(PetscFree(toBalance));
19799566063dSJacob Faibussowitsch     PetscCall(PetscFree(isLeaf));
19809566063dSJacob Faibussowitsch     PetscCall(PetscFree(isNonExclusivelyOwned));
19819566063dSJacob Faibussowitsch     PetscCall(PetscFree(isExclusivelyOwned));
19829566063dSJacob Faibussowitsch     PetscCall(PetscFree(part));
19837f57c1a4SFlorian Wechsung     if (viewer) {
19849566063dSJacob Faibussowitsch       PetscCall(PetscViewerPopFormat(viewer));
19859566063dSJacob Faibussowitsch       PetscCall(PetscViewerDestroy(&viewer));
19867f57c1a4SFlorian Wechsung     }
19879566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
19888b879b41SFlorian Wechsung     PetscFunctionReturn(0);
1989cb87ef4cSFlorian Wechsung   }
1990cb87ef4cSFlorian Wechsung 
19917407ba93SFlorian Wechsung   /*Let's check how well we did distributing points*/
19925dc86ac1SFlorian Wechsung   if (viewer) {
199363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Comparing number of owned entities of depth %" PetscInt_FMT " on each process before rebalancing, after rebalancing, and after consistency checks.\n", entityDepth));
19949566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Initial.     "));
19959566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, NULL, viewer));
19969566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Rebalanced.  "));
19979566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer));
19987407ba93SFlorian Wechsung   }
19997407ba93SFlorian Wechsung 
2000cb87ef4cSFlorian Wechsung   /* Now check that every vertex is owned by a process that it is actually connected to. */
200141525646SFlorian Wechsung   for (i=1; i<=numNonExclusivelyOwned; i++) {
2002cb87ef4cSFlorian Wechsung     PetscInt loc = 0;
20039566063dSJacob Faibussowitsch     PetscCall(PetscFindInt(cumSumVertices[part[i]], xadj[i+1]-xadj[i], &adjncy[xadj[i]], &loc));
20047407ba93SFlorian Wechsung     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
2005cb87ef4cSFlorian Wechsung     if (loc<0) {
200641525646SFlorian Wechsung       part[i] = rank;
2007cb87ef4cSFlorian Wechsung     }
2008cb87ef4cSFlorian Wechsung   }
2009cb87ef4cSFlorian Wechsung 
20107407ba93SFlorian Wechsung   /* Let's see how significant the influences of the previous fixing up step was.*/
20115dc86ac1SFlorian Wechsung   if (viewer) {
20129566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "After.       "));
20139566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer));
20147407ba93SFlorian Wechsung   }
20157407ba93SFlorian Wechsung 
20169566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
20179566063dSJacob Faibussowitsch   PetscCall(PetscFree(xadj));
20189566063dSJacob Faibussowitsch   PetscCall(PetscFree(adjncy));
20199566063dSJacob Faibussowitsch   PetscCall(PetscFree(vtxwgt));
2020cb87ef4cSFlorian Wechsung 
20217f57c1a4SFlorian Wechsung   /* Almost done, now rewrite the SF to reflect the new ownership. */
2022cf818975SFlorian Wechsung   {
20237f57c1a4SFlorian Wechsung     PetscInt *pointsToRewrite;
20249566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite));
20257f57c1a4SFlorian Wechsung     counter = 0;
2026cb87ef4cSFlorian Wechsung     for (i=0; i<pEnd-pStart; i++) {
2027cb87ef4cSFlorian Wechsung       if (toBalance[i]) {
2028cb87ef4cSFlorian Wechsung         if (isNonExclusivelyOwned[i]) {
20297f57c1a4SFlorian Wechsung           pointsToRewrite[counter] = i + pStart;
2030cb87ef4cSFlorian Wechsung           counter++;
2031cb87ef4cSFlorian Wechsung         }
2032cb87ef4cSFlorian Wechsung       }
2033cb87ef4cSFlorian Wechsung     }
20349566063dSJacob Faibussowitsch     PetscCall(DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part+1, degrees));
20359566063dSJacob Faibussowitsch     PetscCall(PetscFree(pointsToRewrite));
2036cf818975SFlorian Wechsung   }
2037cb87ef4cSFlorian Wechsung 
20389566063dSJacob Faibussowitsch   PetscCall(PetscFree(toBalance));
20399566063dSJacob Faibussowitsch   PetscCall(PetscFree(isLeaf));
20409566063dSJacob Faibussowitsch   PetscCall(PetscFree(isNonExclusivelyOwned));
20419566063dSJacob Faibussowitsch   PetscCall(PetscFree(isExclusivelyOwned));
20429566063dSJacob Faibussowitsch   PetscCall(PetscFree(part));
20435dc86ac1SFlorian Wechsung   if (viewer) {
20449566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
20459566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
20467d197802SFlorian Wechsung   }
20478b879b41SFlorian Wechsung   if (success) *success = PETSC_TRUE;
20489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
2049b458e8f1SJose E. Roman   PetscFunctionReturn(0);
2050240408d3SFlorian Wechsung #else
20515f441e9bSFlorian Wechsung   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
205241525646SFlorian Wechsung #endif
2053cb87ef4cSFlorian Wechsung }
2054