xref: /petsc/src/dm/impls/plex/plexpartition.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
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 
7*d71ae5a4SJacob Faibussowitsch static inline PetscInt DMPlex_GlobalID(PetscInt point)
8*d71ae5a4SJacob Faibussowitsch {
99371c9d4SSatish Balay   return point >= 0 ? point : -(point + 1);
109371c9d4SSatish Balay }
110134a67bSLisandro Dalcin 
12*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreatePartitionerGraph_Overlap(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
13*d71ae5a4SJacob Faibussowitsch {
145a107427SMatthew G. Knepley   DM              ovdm;
155a107427SMatthew G. Knepley   PetscSF         sfPoint;
165a107427SMatthew G. Knepley   IS              cellNumbering;
175a107427SMatthew G. Knepley   const PetscInt *cellNum;
185a107427SMatthew G. Knepley   PetscInt       *adj = NULL, *vOffsets = NULL, *vAdj = NULL;
195a107427SMatthew G. Knepley   PetscBool       useCone, useClosure;
205a107427SMatthew G. Knepley   PetscInt        dim, depth, overlap, cStart, cEnd, c, v;
215a107427SMatthew G. Knepley   PetscMPIInt     rank, size;
225a107427SMatthew G. Knepley 
235a107427SMatthew G. Knepley   PetscFunctionBegin;
249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
269566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
285a107427SMatthew G. Knepley   if (dim != depth) {
295a107427SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
309566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
315a107427SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
329566063dSJacob Faibussowitsch     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
335a107427SMatthew G. Knepley     /* Different behavior for empty graphs */
345a107427SMatthew G. Knepley     if (!*numVertices) {
359566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, offsets));
365a107427SMatthew G. Knepley       (*offsets)[0] = 0;
375a107427SMatthew G. Knepley     }
385a107427SMatthew G. Knepley     /* Broken in parallel */
395f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
405a107427SMatthew G. Knepley     PetscFunctionReturn(0);
415a107427SMatthew G. Knepley   }
425a107427SMatthew G. Knepley   /* Always use FVM adjacency to create partitioner graph */
439566063dSJacob Faibussowitsch   PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
449566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
455a107427SMatthew G. Knepley   /* Need overlap >= 1 */
469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetOverlap(dm, &overlap));
475a107427SMatthew G. Knepley   if (size && overlap < 1) {
489566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeOverlap(dm, 1, NULL, &ovdm));
495a107427SMatthew G. Knepley   } else {
509566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
515a107427SMatthew G. Knepley     ovdm = dm;
525a107427SMatthew G. Knepley   }
539566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(ovdm, &sfPoint));
549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(ovdm, height, &cStart, &cEnd));
559566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(ovdm, cStart, cEnd, 0, NULL, sfPoint, &cellNumbering));
565a107427SMatthew G. Knepley   if (globalNumbering) {
579566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cellNumbering));
585a107427SMatthew G. Knepley     *globalNumbering = cellNumbering;
595a107427SMatthew G. Knepley   }
609566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cellNumbering, &cellNum));
615a107427SMatthew G. Knepley   /* Determine sizes */
625a107427SMatthew G. Knepley   for (*numVertices = 0, c = cStart; c < cEnd; ++c) {
635a107427SMatthew G. Knepley     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
64b68380d8SVaclav Hapla     if (cellNum[c - cStart] < 0) continue;
655a107427SMatthew G. Knepley     (*numVertices)++;
665a107427SMatthew G. Knepley   }
679566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(*numVertices + 1, &vOffsets));
685a107427SMatthew G. Knepley   for (c = cStart, v = 0; c < cEnd; ++c) {
695a107427SMatthew G. Knepley     PetscInt adjSize = PETSC_DETERMINE, a, vsize = 0;
705a107427SMatthew G. Knepley 
71b68380d8SVaclav Hapla     if (cellNum[c - cStart] < 0) continue;
729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(ovdm, c, &adjSize, &adj));
735a107427SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
745a107427SMatthew G. Knepley       const PetscInt point = adj[a];
755a107427SMatthew G. Knepley       if (point != c && cStart <= point && point < cEnd) ++vsize;
765a107427SMatthew G. Knepley     }
775a107427SMatthew G. Knepley     vOffsets[v + 1] = vOffsets[v] + vsize;
785a107427SMatthew G. Knepley     ++v;
795a107427SMatthew G. Knepley   }
805a107427SMatthew G. Knepley   /* Determine adjacency */
819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vOffsets[*numVertices], &vAdj));
825a107427SMatthew G. Knepley   for (c = cStart, v = 0; c < cEnd; ++c) {
835a107427SMatthew G. Knepley     PetscInt adjSize = PETSC_DETERMINE, a, off = vOffsets[v];
845a107427SMatthew G. Knepley 
855a107427SMatthew G. Knepley     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
86b68380d8SVaclav Hapla     if (cellNum[c - cStart] < 0) continue;
879566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(ovdm, c, &adjSize, &adj));
885a107427SMatthew G. Knepley     for (a = 0; a < adjSize; ++a) {
895a107427SMatthew G. Knepley       const PetscInt point = adj[a];
90ad540459SPierre Jolivet       if (point != c && cStart <= point && point < cEnd) vAdj[off++] = DMPlex_GlobalID(cellNum[point - cStart]);
915a107427SMatthew G. Knepley     }
9263a3b9bcSJacob Faibussowitsch     PetscCheck(off == vOffsets[v + 1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Offsets %" PetscInt_FMT " should be %" PetscInt_FMT, off, vOffsets[v + 1]);
935a107427SMatthew G. Knepley     /* Sort adjacencies (not strictly necessary) */
949566063dSJacob Faibussowitsch     PetscCall(PetscSortInt(off - vOffsets[v], &vAdj[vOffsets[v]]));
955a107427SMatthew G. Knepley     ++v;
965a107427SMatthew G. Knepley   }
979566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
989566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cellNumbering, &cellNum));
999566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellNumbering));
1009566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
1019566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&ovdm));
1029371c9d4SSatish Balay   if (offsets) {
1039371c9d4SSatish Balay     *offsets = vOffsets;
1049371c9d4SSatish Balay   } else PetscCall(PetscFree(vOffsets));
1059371c9d4SSatish Balay   if (adjacency) {
1069371c9d4SSatish Balay     *adjacency = vAdj;
1079371c9d4SSatish Balay   } else PetscCall(PetscFree(vAdj));
1085a107427SMatthew G. Knepley   PetscFunctionReturn(0);
1095a107427SMatthew G. Knepley }
1105a107427SMatthew G. Knepley 
111*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
112*d71ae5a4SJacob Faibussowitsch {
113ffbd6163SMatthew G. Knepley   PetscInt        dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
114389e55d8SMichael Lange   PetscInt       *adj = NULL, *vOffsets = NULL, *graph = NULL;
1158cfe4c1fSMichael Lange   IS              cellNumbering;
1168cfe4c1fSMichael Lange   const PetscInt *cellNum;
117532c4e7dSMichael Lange   PetscBool       useCone, useClosure;
118532c4e7dSMichael Lange   PetscSection    section;
119532c4e7dSMichael Lange   PetscSegBuffer  adjBuffer;
1208cfe4c1fSMichael Lange   PetscSF         sfPoint;
1218f4e72b9SMatthew G. Knepley   PetscInt       *adjCells = NULL, *remoteCells = NULL;
1228f4e72b9SMatthew G. Knepley   const PetscInt *local;
1238f4e72b9SMatthew G. Knepley   PetscInt        nroots, nleaves, l;
124532c4e7dSMichael Lange   PetscMPIInt     rank;
125532c4e7dSMichael Lange 
126532c4e7dSMichael Lange   PetscFunctionBegin;
1279566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1289566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
1299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
130ffbd6163SMatthew G. Knepley   if (dim != depth) {
131ffbd6163SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
1329566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
133ffbd6163SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
1349566063dSJacob Faibussowitsch     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
135ffbd6163SMatthew G. Knepley     /* Different behavior for empty graphs */
136ffbd6163SMatthew G. Knepley     if (!*numVertices) {
1379566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, offsets));
138ffbd6163SMatthew G. Knepley       (*offsets)[0] = 0;
139ffbd6163SMatthew G. Knepley     }
140ffbd6163SMatthew G. Knepley     /* Broken in parallel */
1415f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
142ffbd6163SMatthew G. Knepley     PetscFunctionReturn(0);
143ffbd6163SMatthew G. Knepley   }
1449566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
1459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, height, &pStart, &pEnd));
146532c4e7dSMichael Lange   /* Build adjacency graph via a section/segbuffer */
1479566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
1489566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
1499566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 1000, &adjBuffer));
150532c4e7dSMichael Lange   /* Always use FVM adjacency to create partitioner graph */
1519566063dSJacob Faibussowitsch   PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
1529566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
1539566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, sfPoint, &cellNumbering));
1543fa7752dSToby Isaac   if (globalNumbering) {
1559566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cellNumbering));
1563fa7752dSToby Isaac     *globalNumbering = cellNumbering;
1573fa7752dSToby Isaac   }
1589566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cellNumbering, &cellNum));
1598f4e72b9SMatthew G. Knepley   /* For all boundary faces (including faces adjacent to a ghost cell), record the local cell in adjCells
1608f4e72b9SMatthew G. Knepley      Broadcast adjCells to remoteCells (to get cells from roots) and Reduce adjCells to remoteCells (to get cells from leaves)
1618f4e72b9SMatthew G. Knepley    */
1629566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfPoint, &nroots, &nleaves, &local, NULL));
1638f4e72b9SMatthew G. Knepley   if (nroots >= 0) {
1648f4e72b9SMatthew G. Knepley     PetscInt fStart, fEnd, f;
1658f4e72b9SMatthew G. Knepley 
1669566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nroots, &adjCells, nroots, &remoteCells));
1679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, height + 1, &fStart, &fEnd));
1688f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) adjCells[l] = -3;
1698f4e72b9SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
1708f4e72b9SMatthew G. Knepley       const PetscInt *support;
1718f4e72b9SMatthew G. Knepley       PetscInt        supportSize;
1728f4e72b9SMatthew G. Knepley 
1739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &support));
1749566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
175b68380d8SVaclav Hapla       if (supportSize == 1) adjCells[f] = DMPlex_GlobalID(cellNum[support[0] - pStart]);
1768f4e72b9SMatthew G. Knepley       else if (supportSize == 2) {
1779566063dSJacob Faibussowitsch         PetscCall(PetscFindInt(support[0], nleaves, local, &p));
178b68380d8SVaclav Hapla         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1] - pStart]);
1799566063dSJacob Faibussowitsch         PetscCall(PetscFindInt(support[1], nleaves, local, &p));
180b68380d8SVaclav Hapla         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0] - pStart]);
1810134a67bSLisandro Dalcin       }
1820134a67bSLisandro Dalcin       /* Handle non-conforming meshes */
1830134a67bSLisandro Dalcin       if (supportSize > 2) {
1840134a67bSLisandro Dalcin         PetscInt        numChildren, i;
1850134a67bSLisandro Dalcin         const PetscInt *children;
1860134a67bSLisandro Dalcin 
1879566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, &children));
1880134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1890134a67bSLisandro Dalcin           const PetscInt child = children[i];
1900134a67bSLisandro Dalcin           if (fStart <= child && child < fEnd) {
1919566063dSJacob Faibussowitsch             PetscCall(DMPlexGetSupport(dm, child, &support));
1929566063dSJacob Faibussowitsch             PetscCall(DMPlexGetSupportSize(dm, child, &supportSize));
193b68380d8SVaclav Hapla             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0] - pStart]);
1940134a67bSLisandro Dalcin             else if (supportSize == 2) {
1959566063dSJacob Faibussowitsch               PetscCall(PetscFindInt(support[0], nleaves, local, &p));
196b68380d8SVaclav Hapla               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1] - pStart]);
1979566063dSJacob Faibussowitsch               PetscCall(PetscFindInt(support[1], nleaves, local, &p));
198b68380d8SVaclav Hapla               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0] - pStart]);
1990134a67bSLisandro Dalcin             }
2000134a67bSLisandro Dalcin           }
2010134a67bSLisandro Dalcin         }
2028f4e72b9SMatthew G. Knepley       }
2038f4e72b9SMatthew G. Knepley     }
2048f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) remoteCells[l] = -1;
2059566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_REPLACE));
2069566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_REPLACE));
2079566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX));
2089566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX));
2098f4e72b9SMatthew G. Knepley   }
2108f4e72b9SMatthew G. Knepley   /* Combine local and global adjacencies */
2118cfe4c1fSMichael Lange   for (*numVertices = 0, p = pStart; p < pEnd; p++) {
2128cfe4c1fSMichael Lange     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
2139371c9d4SSatish Balay     if (nroots > 0) {
2149371c9d4SSatish Balay       if (cellNum[p - pStart] < 0) continue;
2159371c9d4SSatish Balay     }
2168f4e72b9SMatthew G. Knepley     /* Add remote cells */
2178f4e72b9SMatthew G. Knepley     if (remoteCells) {
218b68380d8SVaclav Hapla       const PetscInt  gp = DMPlex_GlobalID(cellNum[p - pStart]);
2190134a67bSLisandro Dalcin       PetscInt        coneSize, numChildren, c, i;
2200134a67bSLisandro Dalcin       const PetscInt *cone, *children;
2210134a67bSLisandro Dalcin 
2229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, p, &cone));
2239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
2248f4e72b9SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
2250134a67bSLisandro Dalcin         const PetscInt point = cone[c];
2260134a67bSLisandro Dalcin         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
2278f4e72b9SMatthew G. Knepley           PetscInt *PETSC_RESTRICT pBuf;
2289566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(section, p, 1));
2299566063dSJacob Faibussowitsch           PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2300134a67bSLisandro Dalcin           *pBuf = remoteCells[point];
2310134a67bSLisandro Dalcin         }
2320134a67bSLisandro Dalcin         /* Handle non-conforming meshes */
2339566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
2340134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
2350134a67bSLisandro Dalcin           const PetscInt child = children[i];
2360134a67bSLisandro Dalcin           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
2370134a67bSLisandro Dalcin             PetscInt *PETSC_RESTRICT pBuf;
2389566063dSJacob Faibussowitsch             PetscCall(PetscSectionAddDof(section, p, 1));
2399566063dSJacob Faibussowitsch             PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
2400134a67bSLisandro Dalcin             *pBuf = remoteCells[child];
2410134a67bSLisandro Dalcin           }
2428f4e72b9SMatthew G. Knepley         }
2438f4e72b9SMatthew G. Knepley       }
2448f4e72b9SMatthew G. Knepley     }
2458f4e72b9SMatthew G. Knepley     /* Add local cells */
246532c4e7dSMichael Lange     adjSize = PETSC_DETERMINE;
2479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
248532c4e7dSMichael Lange     for (a = 0; a < adjSize; ++a) {
249532c4e7dSMichael Lange       const PetscInt point = adj[a];
250532c4e7dSMichael Lange       if (point != p && pStart <= point && point < pEnd) {
251532c4e7dSMichael Lange         PetscInt *PETSC_RESTRICT pBuf;
2529566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(section, p, 1));
2539566063dSJacob Faibussowitsch         PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
254b68380d8SVaclav Hapla         *pBuf = DMPlex_GlobalID(cellNum[point - pStart]);
255532c4e7dSMichael Lange       }
256532c4e7dSMichael Lange     }
2578cfe4c1fSMichael Lange     (*numVertices)++;
258532c4e7dSMichael Lange   }
2599566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
2609566063dSJacob Faibussowitsch   PetscCall(PetscFree2(adjCells, remoteCells));
2619566063dSJacob Faibussowitsch   PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
2624e468a93SLisandro Dalcin 
263532c4e7dSMichael Lange   /* Derive CSR graph from section/segbuffer */
2649566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
2659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &size));
2669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(*numVertices + 1, &vOffsets));
26743f7d02bSMichael Lange   for (idx = 0, p = pStart; p < pEnd; p++) {
2689371c9d4SSatish Balay     if (nroots > 0) {
2699371c9d4SSatish Balay       if (cellNum[p - pStart] < 0) continue;
2709371c9d4SSatish Balay     }
2719566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &(vOffsets[idx++])));
27243f7d02bSMichael Lange   }
273532c4e7dSMichael Lange   vOffsets[*numVertices] = size;
2749566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &graph));
2754e468a93SLisandro Dalcin 
2764e468a93SLisandro Dalcin   if (nroots >= 0) {
2774e468a93SLisandro Dalcin     /* Filter out duplicate edges using section/segbuffer */
2789566063dSJacob Faibussowitsch     PetscCall(PetscSectionReset(section));
2799566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(section, 0, *numVertices));
2804e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2814e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p + 1];
2824e468a93SLisandro Dalcin       PetscInt numEdges = end - start, *PETSC_RESTRICT edges;
2839566063dSJacob Faibussowitsch       PetscCall(PetscSortRemoveDupsInt(&numEdges, &graph[start]));
2849566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(section, p, numEdges));
2859566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGetInts(adjBuffer, numEdges, &edges));
2869566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(edges, &graph[start], numEdges));
2874e468a93SLisandro Dalcin     }
2889566063dSJacob Faibussowitsch     PetscCall(PetscFree(vOffsets));
2899566063dSJacob Faibussowitsch     PetscCall(PetscFree(graph));
2904e468a93SLisandro Dalcin     /* Derive CSR graph from section/segbuffer */
2919566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(section));
2929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(section, &size));
2939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(*numVertices + 1, &vOffsets));
29448a46eb9SPierre Jolivet     for (idx = 0, p = 0; p < *numVertices; p++) PetscCall(PetscSectionGetOffset(section, p, &(vOffsets[idx++])));
2954e468a93SLisandro Dalcin     vOffsets[*numVertices] = size;
2969566063dSJacob Faibussowitsch     PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &graph));
2974e468a93SLisandro Dalcin   } else {
2984e468a93SLisandro Dalcin     /* Sort adjacencies (not strictly necessary) */
2994e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
3004e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p + 1];
3019566063dSJacob Faibussowitsch       PetscCall(PetscSortInt(end - start, &graph[start]));
3024e468a93SLisandro Dalcin     }
3034e468a93SLisandro Dalcin   }
3044e468a93SLisandro Dalcin 
3054e468a93SLisandro Dalcin   if (offsets) *offsets = vOffsets;
306389e55d8SMichael Lange   if (adjacency) *adjacency = graph;
3074e468a93SLisandro Dalcin 
308532c4e7dSMichael Lange   /* Cleanup */
3099566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferDestroy(&adjBuffer));
3109566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
3119566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cellNumbering, &cellNum));
3129566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellNumbering));
313532c4e7dSMichael Lange   PetscFunctionReturn(0);
314532c4e7dSMichael Lange }
315532c4e7dSMichael Lange 
316*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
317*d71ae5a4SJacob Faibussowitsch {
318bbbc8e51SStefano Zampini   Mat             conn, CSR;
319bbbc8e51SStefano Zampini   IS              fis, cis, cis_own;
320bbbc8e51SStefano Zampini   PetscSF         sfPoint;
321bbbc8e51SStefano Zampini   const PetscInt *rows, *cols, *ii, *jj;
322bbbc8e51SStefano Zampini   PetscInt       *idxs, *idxs2;
32383c5d788SMatthew G. Knepley   PetscInt        dim, depth, floc, cloc, i, M, N, c, lm, m, cStart, cEnd, fStart, fEnd;
324bbbc8e51SStefano Zampini   PetscMPIInt     rank;
325bbbc8e51SStefano Zampini   PetscBool       flg;
326bbbc8e51SStefano Zampini 
327bbbc8e51SStefano Zampini   PetscFunctionBegin;
3289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3299566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
3309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
331bbbc8e51SStefano Zampini   if (dim != depth) {
332bbbc8e51SStefano Zampini     /* We do not handle the uninterpolated case here */
3339566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
334bbbc8e51SStefano Zampini     /* DMPlexCreateNeighborCSR does not make a numbering */
3359566063dSJacob Faibussowitsch     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
336bbbc8e51SStefano Zampini     /* Different behavior for empty graphs */
337bbbc8e51SStefano Zampini     if (!*numVertices) {
3389566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(1, offsets));
339bbbc8e51SStefano Zampini       (*offsets)[0] = 0;
340bbbc8e51SStefano Zampini     }
341bbbc8e51SStefano Zampini     /* Broken in parallel */
3425f80ce2aSJacob Faibussowitsch     if (rank) PetscCheck(!*numVertices, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
343bbbc8e51SStefano Zampini     PetscFunctionReturn(0);
344bbbc8e51SStefano Zampini   }
345bbbc8e51SStefano Zampini   /* Interpolated and parallel case */
346bbbc8e51SStefano Zampini 
347bbbc8e51SStefano Zampini   /* numbering */
3489566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
3499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd));
3509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, height + 1, &fStart, &fEnd));
3519566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, &N, sfPoint, &cis));
3529566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateNumbering_Plex(dm, fStart, fEnd, 0, &M, sfPoint, &fis));
3531baa6e33SBarry Smith   if (globalNumbering) PetscCall(ISDuplicate(cis, globalNumbering));
354bbbc8e51SStefano Zampini 
355bbbc8e51SStefano Zampini   /* get positive global ids and local sizes for facets and cells */
3569566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(fis, &m));
3579566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(fis, &rows));
3589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &idxs));
359bbbc8e51SStefano Zampini   for (i = 0, floc = 0; i < m; i++) {
360bbbc8e51SStefano Zampini     const PetscInt p = rows[i];
361bbbc8e51SStefano Zampini 
362bbbc8e51SStefano Zampini     if (p < 0) {
363bbbc8e51SStefano Zampini       idxs[i] = -(p + 1);
364bbbc8e51SStefano Zampini     } else {
365bbbc8e51SStefano Zampini       idxs[i] = p;
366bbbc8e51SStefano Zampini       floc += 1;
367bbbc8e51SStefano Zampini     }
368bbbc8e51SStefano Zampini   }
3699566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(fis, &rows));
3709566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&fis));
3719566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis));
372bbbc8e51SStefano Zampini 
3739566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cis, &m));
3749566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cis, &cols));
3759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &idxs));
3769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &idxs2));
377bbbc8e51SStefano Zampini   for (i = 0, cloc = 0; i < m; i++) {
378bbbc8e51SStefano Zampini     const PetscInt p = cols[i];
379bbbc8e51SStefano Zampini 
380bbbc8e51SStefano Zampini     if (p < 0) {
381bbbc8e51SStefano Zampini       idxs[i] = -(p + 1);
382bbbc8e51SStefano Zampini     } else {
383bbbc8e51SStefano Zampini       idxs[i]       = p;
384bbbc8e51SStefano Zampini       idxs2[cloc++] = p;
385bbbc8e51SStefano Zampini     }
386bbbc8e51SStefano Zampini   }
3879566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cis, &cols));
3889566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis));
3899566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis));
3909566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own));
391bbbc8e51SStefano Zampini 
392bbbc8e51SStefano Zampini   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
3939566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), &conn));
3949566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(conn, floc, cloc, M, N));
3959566063dSJacob Faibussowitsch   PetscCall(MatSetType(conn, MATMPIAIJ));
3969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxSizes(dm, NULL, &lm));
3979566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&lm, &m, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
3989566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL));
399bbbc8e51SStefano Zampini 
400bbbc8e51SStefano Zampini   /* Assemble matrix */
4019566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(fis, &rows));
4029566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cis, &cols));
403bbbc8e51SStefano Zampini   for (c = cStart; c < cEnd; c++) {
404bbbc8e51SStefano Zampini     const PetscInt *cone;
405bbbc8e51SStefano Zampini     PetscInt        coneSize, row, col, f;
406bbbc8e51SStefano Zampini 
407bbbc8e51SStefano Zampini     col = cols[c - cStart];
4089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, c, &cone));
4099566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
410bbbc8e51SStefano Zampini     for (f = 0; f < coneSize; f++) {
411bbbc8e51SStefano Zampini       const PetscScalar v = 1.0;
412bbbc8e51SStefano Zampini       const PetscInt   *children;
413bbbc8e51SStefano Zampini       PetscInt          numChildren, ch;
414bbbc8e51SStefano Zampini 
415bbbc8e51SStefano Zampini       row = rows[cone[f] - fStart];
4169566063dSJacob Faibussowitsch       PetscCall(MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES));
417bbbc8e51SStefano Zampini 
418bbbc8e51SStefano Zampini       /* non-conforming meshes */
4199566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children));
420bbbc8e51SStefano Zampini       for (ch = 0; ch < numChildren; ch++) {
421bbbc8e51SStefano Zampini         const PetscInt child = children[ch];
422bbbc8e51SStefano Zampini 
423bbbc8e51SStefano Zampini         if (child < fStart || child >= fEnd) continue;
424bbbc8e51SStefano Zampini         row = rows[child - fStart];
4259566063dSJacob Faibussowitsch         PetscCall(MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES));
426bbbc8e51SStefano Zampini       }
427bbbc8e51SStefano Zampini     }
428bbbc8e51SStefano Zampini   }
4299566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(fis, &rows));
4309566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cis, &cols));
4319566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&fis));
4329566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis));
4339566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY));
4349566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY));
435bbbc8e51SStefano Zampini 
436bbbc8e51SStefano Zampini   /* Get parallel CSR by doing conn^T * conn */
4379566063dSJacob Faibussowitsch   PetscCall(MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR));
4389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&conn));
439bbbc8e51SStefano Zampini 
440bbbc8e51SStefano Zampini   /* extract local part of the CSR */
4419566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn));
4429566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&CSR));
4439566063dSJacob Faibussowitsch   PetscCall(MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
4445f80ce2aSJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
445bbbc8e51SStefano Zampini 
446bbbc8e51SStefano Zampini   /* get back requested output */
447bbbc8e51SStefano Zampini   if (numVertices) *numVertices = m;
448bbbc8e51SStefano Zampini   if (offsets) {
4499566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(m + 1, &idxs));
450bbbc8e51SStefano Zampini     for (i = 1; i < m + 1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
451bbbc8e51SStefano Zampini     *offsets = idxs;
452bbbc8e51SStefano Zampini   }
453bbbc8e51SStefano Zampini   if (adjacency) {
4549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ii[m] - m, &idxs));
4559566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(cis_own, &rows));
456bbbc8e51SStefano Zampini     for (i = 0, c = 0; i < m; i++) {
457bbbc8e51SStefano Zampini       PetscInt j, g = rows[i];
458bbbc8e51SStefano Zampini 
459bbbc8e51SStefano Zampini       for (j = ii[i]; j < ii[i + 1]; j++) {
460bbbc8e51SStefano Zampini         if (jj[j] == g) continue; /* again, self-connectivity */
461bbbc8e51SStefano Zampini         idxs[c++] = jj[j];
462bbbc8e51SStefano Zampini       }
463bbbc8e51SStefano Zampini     }
46463a3b9bcSJacob Faibussowitsch     PetscCheck(c == ii[m] - m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, c, ii[m] - m);
4659566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(cis_own, &rows));
466bbbc8e51SStefano Zampini     *adjacency = idxs;
467bbbc8e51SStefano Zampini   }
468bbbc8e51SStefano Zampini 
469bbbc8e51SStefano Zampini   /* cleanup */
4709566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis_own));
4719566063dSJacob Faibussowitsch   PetscCall(MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
4725f80ce2aSJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
4739566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&conn));
474bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
475bbbc8e51SStefano Zampini }
476bbbc8e51SStefano Zampini 
477bbbc8e51SStefano Zampini /*@C
478bbbc8e51SStefano Zampini   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
479bbbc8e51SStefano Zampini 
480bbbc8e51SStefano Zampini   Input Parameters:
481bbbc8e51SStefano Zampini + dm      - The mesh DM dm
482bbbc8e51SStefano Zampini - height  - Height of the strata from which to construct the graph
483bbbc8e51SStefano Zampini 
484d8d19677SJose E. Roman   Output Parameters:
485bbbc8e51SStefano Zampini + numVertices     - Number of vertices in the graph
486bbbc8e51SStefano Zampini . offsets         - Point offsets in the graph
487bbbc8e51SStefano Zampini . adjacency       - Point connectivity in the graph
488bbbc8e51SStefano 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.
489bbbc8e51SStefano Zampini 
490bbbc8e51SStefano Zampini   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
491bbbc8e51SStefano Zampini   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
492bbbc8e51SStefano Zampini 
4935a107427SMatthew G. Knepley   Options Database Keys:
4945a107427SMatthew G. Knepley . -dm_plex_csr_alg <mat,graph,overlap> - Choose the algorithm for computing the CSR graph
4955a107427SMatthew G. Knepley 
496bbbc8e51SStefano Zampini   Level: developer
497bbbc8e51SStefano Zampini 
498db781477SPatrick Sanan .seealso: `PetscPartitionerGetType()`, `PetscPartitionerCreate()`, `DMSetAdjacency()`
499bbbc8e51SStefano Zampini @*/
500*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
501*d71ae5a4SJacob Faibussowitsch {
5025a107427SMatthew G. Knepley   DMPlexCSRAlgorithm alg = DM_PLEX_CSR_GRAPH;
503bbbc8e51SStefano Zampini 
504bbbc8e51SStefano Zampini   PetscFunctionBegin;
5059566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetEnum(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_csr_alg", DMPlexCSRAlgorithms, (PetscEnum *)&alg, NULL));
5065a107427SMatthew G. Knepley   switch (alg) {
507*d71ae5a4SJacob Faibussowitsch   case DM_PLEX_CSR_MAT:
508*d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering));
509*d71ae5a4SJacob Faibussowitsch     break;
510*d71ae5a4SJacob Faibussowitsch   case DM_PLEX_CSR_GRAPH:
511*d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering));
512*d71ae5a4SJacob Faibussowitsch     break;
513*d71ae5a4SJacob Faibussowitsch   case DM_PLEX_CSR_OVERLAP:
514*d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph_Overlap(dm, height, numVertices, offsets, adjacency, globalNumbering));
515*d71ae5a4SJacob Faibussowitsch     break;
516bbbc8e51SStefano Zampini   }
517bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
518bbbc8e51SStefano Zampini }
519bbbc8e51SStefano Zampini 
520d5577e40SMatthew G. Knepley /*@C
521d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
522d5577e40SMatthew G. Knepley 
523fe2efc57SMark   Collective on DM
524d5577e40SMatthew G. Knepley 
5254165533cSJose E. Roman   Input Parameters:
526d5577e40SMatthew G. Knepley + dm - The DMPlex
527d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
528d5577e40SMatthew G. Knepley 
5294165533cSJose E. Roman   Output Parameters:
530d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
531d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
532d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
533d5577e40SMatthew G. Knepley 
534d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
535d5577e40SMatthew G. Knepley 
536d5577e40SMatthew G. Knepley   Level: advanced
537d5577e40SMatthew G. Knepley 
538db781477SPatrick Sanan .seealso: `DMPlexCreate()`
539d5577e40SMatthew G. Knepley @*/
540*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
541*d71ae5a4SJacob Faibussowitsch {
54270034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
54370034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
54470034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
54570034214SMatthew G. Knepley   PetscInt      *off, *adj;
54670034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
54770034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
54870034214SMatthew G. Knepley 
54970034214SMatthew G. Knepley   PetscFunctionBegin;
55070034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
5519566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
55270034214SMatthew G. Knepley   cellDim = dim - cellHeight;
5539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
5549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
55570034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
55670034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
55770034214SMatthew G. Knepley     if (offsets) *offsets = NULL;
55870034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
55970034214SMatthew G. Knepley     PetscFunctionReturn(0);
56070034214SMatthew G. Knepley   }
56170034214SMatthew G. Knepley   numCells  = cEnd - cStart;
56270034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
56370034214SMatthew G. Knepley   if (dim == depth) {
56470034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
56570034214SMatthew G. Knepley 
5669566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(numCells + 1, &off));
56770034214SMatthew G. Knepley     /* Count neighboring cells */
5689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight + 1, &fStart, &fEnd));
56970034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
57070034214SMatthew G. Knepley       const PetscInt *support;
57170034214SMatthew G. Knepley       PetscInt        supportSize;
5729566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
5739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &support));
57470034214SMatthew G. Knepley       if (supportSize == 2) {
5759ffc88e4SToby Isaac         PetscInt numChildren;
5769ffc88e4SToby Isaac 
5779566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
5789ffc88e4SToby Isaac         if (!numChildren) {
57970034214SMatthew G. Knepley           ++off[support[0] - cStart + 1];
58070034214SMatthew G. Knepley           ++off[support[1] - cStart + 1];
58170034214SMatthew G. Knepley         }
58270034214SMatthew G. Knepley       }
5839ffc88e4SToby Isaac     }
58470034214SMatthew G. Knepley     /* Prefix sum */
58570034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c - 1];
58670034214SMatthew G. Knepley     if (adjacency) {
58770034214SMatthew G. Knepley       PetscInt *tmp;
58870034214SMatthew G. Knepley 
5899566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(off[numCells], &adj));
5909566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numCells + 1, &tmp));
5919566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(tmp, off, numCells + 1));
59270034214SMatthew G. Knepley       /* Get neighboring cells */
59370034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
59470034214SMatthew G. Knepley         const PetscInt *support;
59570034214SMatthew G. Knepley         PetscInt        supportSize;
5969566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
5979566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, f, &support));
59870034214SMatthew G. Knepley         if (supportSize == 2) {
5999ffc88e4SToby Isaac           PetscInt numChildren;
6009ffc88e4SToby Isaac 
6019566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
6029ffc88e4SToby Isaac           if (!numChildren) {
60370034214SMatthew G. Knepley             adj[tmp[support[0] - cStart]++] = support[1];
60470034214SMatthew G. Knepley             adj[tmp[support[1] - cStart]++] = support[0];
60570034214SMatthew G. Knepley           }
60670034214SMatthew G. Knepley         }
6079ffc88e4SToby Isaac       }
60863a3b9bcSJacob 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);
6099566063dSJacob Faibussowitsch       PetscCall(PetscFree(tmp));
61070034214SMatthew G. Knepley     }
61170034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
61270034214SMatthew G. Knepley     if (offsets) *offsets = off;
61370034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
61470034214SMatthew G. Knepley     PetscFunctionReturn(0);
61570034214SMatthew G. Knepley   }
61670034214SMatthew G. Knepley   /* Setup face recognition */
61770034214SMatthew G. Knepley   if (faceDepth == 1) {
61870034214SMatthew 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 */
61970034214SMatthew G. Knepley 
62070034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
62170034214SMatthew G. Knepley       PetscInt corners;
62270034214SMatthew G. Knepley 
6239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &corners));
62470034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
62570034214SMatthew G. Knepley         PetscInt nFV;
62670034214SMatthew G. Knepley 
6275f80ce2aSJacob Faibussowitsch         PetscCheck(numFaceCases < maxFaceCases, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
62870034214SMatthew G. Knepley         cornersSeen[corners] = 1;
62970034214SMatthew G. Knepley 
6309566063dSJacob Faibussowitsch         PetscCall(DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV));
63170034214SMatthew G. Knepley 
63270034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
63370034214SMatthew G. Knepley       }
63470034214SMatthew G. Knepley     }
63570034214SMatthew G. Knepley   }
6369566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numCells + 1, &off));
63770034214SMatthew G. Knepley   /* Count neighboring cells */
63870034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
63970034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
64070034214SMatthew G. Knepley 
6419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
64270034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
64370034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
64470034214SMatthew G. Knepley       PetscInt        cellPair[2];
64570034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
64670034214SMatthew G. Knepley       PetscInt        meetSize = 0;
64770034214SMatthew G. Knepley       const PetscInt *meet     = NULL;
64870034214SMatthew G. Knepley 
6499371c9d4SSatish Balay       cellPair[0] = cell;
6509371c9d4SSatish Balay       cellPair[1] = neighborCells[n];
65170034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
65270034214SMatthew G. Knepley       if (!found) {
6539566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
65470034214SMatthew G. Knepley         if (meetSize) {
65570034214SMatthew G. Knepley           PetscInt f;
65670034214SMatthew G. Knepley 
65770034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
65870034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
65970034214SMatthew G. Knepley               found = PETSC_TRUE;
66070034214SMatthew G. Knepley               break;
66170034214SMatthew G. Knepley             }
66270034214SMatthew G. Knepley           }
66370034214SMatthew G. Knepley         }
6649566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
66570034214SMatthew G. Knepley       }
66670034214SMatthew G. Knepley       if (found) ++off[cell - cStart + 1];
66770034214SMatthew G. Knepley     }
66870034214SMatthew G. Knepley   }
66970034214SMatthew G. Knepley   /* Prefix sum */
67070034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell - 1];
67170034214SMatthew G. Knepley 
67270034214SMatthew G. Knepley   if (adjacency) {
6739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(off[numCells], &adj));
67470034214SMatthew G. Knepley     /* Get neighboring cells */
67570034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
67670034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
67770034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
67870034214SMatthew G. Knepley 
6799566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
68070034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
68170034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
68270034214SMatthew G. Knepley         PetscInt        cellPair[2];
68370034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
68470034214SMatthew G. Knepley         PetscInt        meetSize = 0;
68570034214SMatthew G. Knepley         const PetscInt *meet     = NULL;
68670034214SMatthew G. Knepley 
6879371c9d4SSatish Balay         cellPair[0] = cell;
6889371c9d4SSatish Balay         cellPair[1] = neighborCells[n];
68970034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
69070034214SMatthew G. Knepley         if (!found) {
6919566063dSJacob Faibussowitsch           PetscCall(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
69270034214SMatthew G. Knepley           if (meetSize) {
69370034214SMatthew G. Knepley             PetscInt f;
69470034214SMatthew G. Knepley 
69570034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
69670034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
69770034214SMatthew G. Knepley                 found = PETSC_TRUE;
69870034214SMatthew G. Knepley                 break;
69970034214SMatthew G. Knepley               }
70070034214SMatthew G. Knepley             }
70170034214SMatthew G. Knepley           }
7029566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
70370034214SMatthew G. Knepley         }
70470034214SMatthew G. Knepley         if (found) {
70570034214SMatthew G. Knepley           adj[off[cell - cStart] + cellOffset] = neighborCells[n];
70670034214SMatthew G. Knepley           ++cellOffset;
70770034214SMatthew G. Knepley         }
70870034214SMatthew G. Knepley       }
70970034214SMatthew G. Knepley     }
71070034214SMatthew G. Knepley   }
7119566063dSJacob Faibussowitsch   PetscCall(PetscFree(neighborCells));
71270034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
71370034214SMatthew G. Knepley   if (offsets) *offsets = off;
71470034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
71570034214SMatthew G. Knepley   PetscFunctionReturn(0);
71670034214SMatthew G. Knepley }
71770034214SMatthew G. Knepley 
71877623264SMatthew G. Knepley /*@
7193c41b853SStefano Zampini   PetscPartitionerDMPlexPartition - Create a non-overlapping partition of the cells in the mesh
72077623264SMatthew G. Knepley 
721fe2efc57SMark   Collective on PetscPartitioner
72277623264SMatthew G. Knepley 
72377623264SMatthew G. Knepley   Input Parameters:
72477623264SMatthew G. Knepley + part    - The PetscPartitioner
7253c41b853SStefano Zampini . targetSection - The PetscSection describing the absolute weight of each partition (can be NULL)
726f8987ae8SMichael Lange - dm      - The mesh DM
72777623264SMatthew G. Knepley 
72877623264SMatthew G. Knepley   Output Parameters:
72977623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
730f8987ae8SMichael Lange - partition       - The list of points by partition
73177623264SMatthew G. Knepley 
7323c41b853SStefano Zampini   Notes:
7333c41b853SStefano Zampini     If the DM has a local section associated, each point to be partitioned will be weighted by the total number of dofs identified
7343c41b853SStefano Zampini     by the section in the transitive closure of the point.
73577623264SMatthew G. Knepley 
73677623264SMatthew G. Knepley   Level: developer
73777623264SMatthew G. Knepley 
738db781477SPatrick Sanan .seealso `DMPlexDistribute()`, `PetscPartitionerCreate()`, `PetscSectionCreate()`, `PetscSectionSetChart()`, `PetscPartitionerPartition()`
7394b15ede2SMatthew G. Knepley @*/
740*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPartitionerDMPlexPartition(PetscPartitioner part, DM dm, PetscSection targetSection, PetscSection partSection, IS *partition)
741*d71ae5a4SJacob Faibussowitsch {
74277623264SMatthew G. Knepley   PetscMPIInt  size;
7433c41b853SStefano Zampini   PetscBool    isplex;
7443c41b853SStefano Zampini   PetscSection vertSection = NULL;
74577623264SMatthew G. Knepley 
74677623264SMatthew G. Knepley   PetscFunctionBegin;
74777623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
74877623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
7493c41b853SStefano Zampini   if (targetSection) PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 3);
75077623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
75177623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
7529566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isplex));
7535f80ce2aSJacob Faibussowitsch   PetscCheck(isplex, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not for type %s", ((PetscObject)dm)->type_name);
7549566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)part), &size));
75577623264SMatthew G. Knepley   if (size == 1) {
75677623264SMatthew G. Knepley     PetscInt *points;
75777623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
75877623264SMatthew G. Knepley 
7599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
7609566063dSJacob Faibussowitsch     PetscCall(PetscSectionReset(partSection));
7619566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(partSection, 0, size));
7629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(partSection, 0, cEnd - cStart));
7639566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(partSection));
7649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cEnd - cStart, &points));
76577623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
7669566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)part), cEnd - cStart, points, PETSC_OWN_POINTER, partition));
76777623264SMatthew G. Knepley     PetscFunctionReturn(0);
76877623264SMatthew G. Knepley   }
76977623264SMatthew G. Knepley   if (part->height == 0) {
770074d466cSStefano Zampini     PetscInt  numVertices = 0;
77177623264SMatthew G. Knepley     PetscInt *start       = NULL;
77277623264SMatthew G. Knepley     PetscInt *adjacency   = NULL;
7733fa7752dSToby Isaac     IS        globalNumbering;
77477623264SMatthew G. Knepley 
775074d466cSStefano Zampini     if (!part->noGraph || part->viewGraph) {
7769566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering));
77713911537SStefano Zampini     } else { /* only compute the number of owned local vertices */
778074d466cSStefano Zampini       const PetscInt *idxs;
779074d466cSStefano Zampini       PetscInt        p, pStart, pEnd;
780074d466cSStefano Zampini 
7819566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
7829566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering));
7839566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(globalNumbering, &idxs));
784074d466cSStefano Zampini       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
7859566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(globalNumbering, &idxs));
786074d466cSStefano Zampini     }
7873c41b853SStefano Zampini     if (part->usevwgt) {
7883c41b853SStefano Zampini       PetscSection    section = dm->localSection, clSection = NULL;
7893c41b853SStefano Zampini       IS              clPoints = NULL;
7903c41b853SStefano Zampini       const PetscInt *gid, *clIdx;
7913c41b853SStefano Zampini       PetscInt        v, p, pStart, pEnd;
7920358368aSMatthew G. Knepley 
7933c41b853SStefano 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) */
7943c41b853SStefano Zampini       /* We do this only if the local section has been set */
7953c41b853SStefano Zampini       if (section) {
7969566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, NULL));
79748a46eb9SPierre Jolivet         if (!clSection) PetscCall(DMPlexCreateClosureIndex(dm, NULL));
7989566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, &clPoints));
7999566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(clPoints, &clIdx));
8003c41b853SStefano Zampini       }
8019566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
8029566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &vertSection));
8039566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(vertSection, 0, numVertices));
8043c41b853SStefano Zampini       if (globalNumbering) {
8059566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(globalNumbering, &gid));
8063c41b853SStefano Zampini       } else gid = NULL;
8073c41b853SStefano Zampini       for (p = pStart, v = 0; p < pEnd; ++p) {
8083c41b853SStefano Zampini         PetscInt dof = 1;
8090358368aSMatthew G. Knepley 
8103c41b853SStefano Zampini         /* skip cells in the overlap */
8113c41b853SStefano Zampini         if (gid && gid[p - pStart] < 0) continue;
8123c41b853SStefano Zampini 
8133c41b853SStefano Zampini         if (section) {
8143c41b853SStefano Zampini           PetscInt cl, clSize, clOff;
8153c41b853SStefano Zampini 
8163c41b853SStefano Zampini           dof = 0;
8179566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(clSection, p, &clSize));
8189566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(clSection, p, &clOff));
8193c41b853SStefano Zampini           for (cl = 0; cl < clSize; cl += 2) {
8203c41b853SStefano Zampini             PetscInt clDof, clPoint = clIdx[clOff + cl]; /* odd indices are reserved for orientations */
8213c41b853SStefano Zampini 
8229566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, clPoint, &clDof));
8233c41b853SStefano Zampini             dof += clDof;
8240358368aSMatthew G. Knepley           }
8250358368aSMatthew G. Knepley         }
82663a3b9bcSJacob Faibussowitsch         PetscCheck(dof, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of dofs for point %" PetscInt_FMT " in the local section should be positive", p);
8279566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(vertSection, v, dof));
8283c41b853SStefano Zampini         v++;
8293c41b853SStefano Zampini       }
83048a46eb9SPierre Jolivet       if (globalNumbering) PetscCall(ISRestoreIndices(globalNumbering, &gid));
83148a46eb9SPierre Jolivet       if (clPoints) PetscCall(ISRestoreIndices(clPoints, &clIdx));
8329566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(vertSection));
8333c41b853SStefano Zampini     }
8349566063dSJacob Faibussowitsch     PetscCall(PetscPartitionerPartition(part, size, numVertices, start, adjacency, vertSection, targetSection, partSection, partition));
8359566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
8369566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
8373fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
8383fa7752dSToby Isaac       const PetscInt *globalNum;
8393fa7752dSToby Isaac       const PetscInt *partIdx;
8403fa7752dSToby Isaac       PetscInt       *map, cStart, cEnd;
8413fa7752dSToby Isaac       PetscInt       *adjusted, i, localSize, offset;
8423fa7752dSToby Isaac       IS              newPartition;
8433fa7752dSToby Isaac 
8449566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(*partition, &localSize));
8459566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localSize, &adjusted));
8469566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(globalNumbering, &globalNum));
8479566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(*partition, &partIdx));
8489566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localSize, &map));
8499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
8503fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
8513fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
8523fa7752dSToby Isaac       }
853ad540459SPierre Jolivet       for (i = 0; i < localSize; i++) adjusted[i] = map[partIdx[i]];
8549566063dSJacob Faibussowitsch       PetscCall(PetscFree(map));
8559566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(*partition, &partIdx));
8569566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(globalNumbering, &globalNum));
8579566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, localSize, adjusted, PETSC_OWN_POINTER, &newPartition));
8589566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalNumbering));
8599566063dSJacob Faibussowitsch       PetscCall(ISDestroy(partition));
8603fa7752dSToby Isaac       *partition = newPartition;
8613fa7752dSToby Isaac     }
86263a3b9bcSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %" PetscInt_FMT " for points to partition", part->height);
8639566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&vertSection));
86477623264SMatthew G. Knepley   PetscFunctionReturn(0);
86577623264SMatthew G. Knepley }
86677623264SMatthew G. Knepley 
8675680f57bSMatthew G. Knepley /*@
8685680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
8695680f57bSMatthew G. Knepley 
8705680f57bSMatthew G. Knepley   Not collective
8715680f57bSMatthew G. Knepley 
8725680f57bSMatthew G. Knepley   Input Parameter:
8735680f57bSMatthew G. Knepley . dm - The DM
8745680f57bSMatthew G. Knepley 
8755680f57bSMatthew G. Knepley   Output Parameter:
8765680f57bSMatthew G. Knepley . part - The PetscPartitioner
8775680f57bSMatthew G. Knepley 
8785680f57bSMatthew G. Knepley   Level: developer
8795680f57bSMatthew G. Knepley 
88098599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
88198599a47SLawrence Mitchell 
882db781477SPatrick Sanan .seealso `DMPlexDistribute()`, `DMPlexSetPartitioner()`, `PetscPartitionerDMPlexPartition()`, `PetscPartitionerCreate()`
8835680f57bSMatthew G. Knepley @*/
884*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
885*d71ae5a4SJacob Faibussowitsch {
8865680f57bSMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
8875680f57bSMatthew G. Knepley 
8885680f57bSMatthew G. Knepley   PetscFunctionBegin;
8895680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8905680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
8915680f57bSMatthew G. Knepley   *part = mesh->partitioner;
8925680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
8935680f57bSMatthew G. Knepley }
8945680f57bSMatthew G. Knepley 
89571bb2955SLawrence Mitchell /*@
89671bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
89771bb2955SLawrence Mitchell 
898fe2efc57SMark   logically collective on DM
89971bb2955SLawrence Mitchell 
90071bb2955SLawrence Mitchell   Input Parameters:
90171bb2955SLawrence Mitchell + dm - The DM
90271bb2955SLawrence Mitchell - part - The partitioner
90371bb2955SLawrence Mitchell 
90471bb2955SLawrence Mitchell   Level: developer
90571bb2955SLawrence Mitchell 
90671bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
90771bb2955SLawrence Mitchell 
908db781477SPatrick Sanan .seealso `DMPlexDistribute()`, `DMPlexGetPartitioner()`, `PetscPartitionerCreate()`
90971bb2955SLawrence Mitchell @*/
910*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
911*d71ae5a4SJacob Faibussowitsch {
91271bb2955SLawrence Mitchell   DM_Plex *mesh = (DM_Plex *)dm->data;
91371bb2955SLawrence Mitchell 
91471bb2955SLawrence Mitchell   PetscFunctionBegin;
91571bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
91671bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
9179566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)part));
9189566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
91971bb2955SLawrence Mitchell   mesh->partitioner = part;
92071bb2955SLawrence Mitchell   PetscFunctionReturn(0);
92171bb2955SLawrence Mitchell }
92271bb2955SLawrence Mitchell 
923*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point)
924*d71ae5a4SJacob Faibussowitsch {
9258e330a33SStefano Zampini   const PetscInt *cone;
9268e330a33SStefano Zampini   PetscInt        coneSize, c;
9278e330a33SStefano Zampini   PetscBool       missing;
9288e330a33SStefano Zampini 
9298e330a33SStefano Zampini   PetscFunctionBeginHot;
9309566063dSJacob Faibussowitsch   PetscCall(PetscHSetIQueryAdd(ht, point, &missing));
9318e330a33SStefano Zampini   if (missing) {
9329566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
9339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
93448a46eb9SPierre Jolivet     for (c = 0; c < coneSize; c++) PetscCall(DMPlexAddClosure_Private(dm, ht, cone[c]));
9358e330a33SStefano Zampini   }
9368e330a33SStefano Zampini   PetscFunctionReturn(0);
9378e330a33SStefano Zampini }
9388e330a33SStefano Zampini 
939*d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
940*d71ae5a4SJacob Faibussowitsch {
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 
978*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point)
979*d71ae5a4SJacob Faibussowitsch {
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 
1001*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point)
1002*d71ae5a4SJacob Faibussowitsch {
10038e330a33SStefano Zampini   PetscInt        i, numChildren;
10048e330a33SStefano Zampini   const PetscInt *children;
10058e330a33SStefano Zampini 
10068e330a33SStefano Zampini   PetscFunctionBeginHot;
10079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
100848a46eb9SPierre Jolivet   for (i = 0; i < numChildren; i++) PetscCall(PetscHSetIAdd(ht, children[i]));
10098e330a33SStefano Zampini   PetscFunctionReturn(0);
10108e330a33SStefano Zampini }
10118e330a33SStefano Zampini 
1012*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point)
1013*d71ae5a4SJacob Faibussowitsch {
10148e330a33SStefano Zampini   const PetscInt *cone;
10158e330a33SStefano Zampini   PetscInt        coneSize, c;
10168e330a33SStefano Zampini 
10178e330a33SStefano Zampini   PetscFunctionBeginHot;
10189566063dSJacob Faibussowitsch   PetscCall(PetscHSetIAdd(ht, point));
10199566063dSJacob Faibussowitsch   PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, point));
10209566063dSJacob Faibussowitsch   PetscCall(DMPlexAddClosureTree_Down_Private(dm, ht, point));
10219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
10229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
102348a46eb9SPierre Jolivet   for (c = 0; c < coneSize; c++) PetscCall(DMPlexAddClosureTree_Private(dm, ht, cone[c]));
10248e330a33SStefano Zampini   PetscFunctionReturn(0);
10258e330a33SStefano Zampini }
10268e330a33SStefano Zampini 
1027*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS)
1028*d71ae5a4SJacob Faibussowitsch {
1029825f8a23SLisandro Dalcin   DM_Plex        *mesh    = (DM_Plex *)dm->data;
10308e330a33SStefano Zampini   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
10318e330a33SStefano Zampini   PetscInt        nelems, *elems, off = 0, p;
103227104ee2SJacob Faibussowitsch   PetscHSetI      ht = NULL;
1033825f8a23SLisandro Dalcin 
1034825f8a23SLisandro Dalcin   PetscFunctionBegin;
10359566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
10369566063dSJacob Faibussowitsch   PetscCall(PetscHSetIResize(ht, numPoints * 16));
10378e330a33SStefano Zampini   if (!hasTree) {
103848a46eb9SPierre Jolivet     for (p = 0; p < numPoints; ++p) PetscCall(DMPlexAddClosure_Private(dm, ht, points[p]));
10398e330a33SStefano Zampini   } else {
10408e330a33SStefano Zampini #if 1
104148a46eb9SPierre Jolivet     for (p = 0; p < numPoints; ++p) PetscCall(DMPlexAddClosureTree_Private(dm, ht, points[p]));
10428e330a33SStefano Zampini #else
10438e330a33SStefano Zampini     PetscInt *closure = NULL, closureSize, c;
1044825f8a23SLisandro Dalcin     for (p = 0; p < numPoints; ++p) {
10459566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure));
1046825f8a23SLisandro Dalcin       for (c = 0; c < closureSize * 2; c += 2) {
10479566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(ht, closure[c]));
10489566063dSJacob Faibussowitsch         if (hasTree) PetscCall(DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE));
1049825f8a23SLisandro Dalcin       }
1050825f8a23SLisandro Dalcin     }
10519566063dSJacob Faibussowitsch     if (closure) PetscCall(DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure));
10528e330a33SStefano Zampini #endif
10538e330a33SStefano Zampini   }
10549566063dSJacob Faibussowitsch   PetscCall(PetscHSetIGetSize(ht, &nelems));
10559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nelems, &elems));
10569566063dSJacob Faibussowitsch   PetscCall(PetscHSetIGetElems(ht, &off, elems));
10579566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
10589566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(nelems, elems));
10599566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS));
1060825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
1061825f8a23SLisandro Dalcin }
1062825f8a23SLisandro Dalcin 
10635abbe4feSMichael Lange /*@
10645abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
10655abbe4feSMichael Lange 
10665abbe4feSMichael Lange   Input Parameters:
10675abbe4feSMichael Lange + dm     - The DM
1068a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
10695abbe4feSMichael Lange 
10705abbe4feSMichael Lange   Level: developer
10715abbe4feSMichael Lange 
1072db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
10735abbe4feSMichael Lange @*/
1074*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
1075*d71ae5a4SJacob Faibussowitsch {
1076825f8a23SLisandro Dalcin   IS              rankIS, pointIS, closureIS;
10775abbe4feSMichael Lange   const PetscInt *ranks, *points;
1078825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
10799ffc88e4SToby Isaac 
10809ffc88e4SToby Isaac   PetscFunctionBegin;
10819566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &rankIS));
10829566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
10839566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
10845abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
10855abbe4feSMichael Lange     const PetscInt rank = ranks[r];
10869566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &pointIS));
10879566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
10889566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
10899566063dSJacob Faibussowitsch     PetscCall(DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS));
10909566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
10919566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
10929566063dSJacob Faibussowitsch     PetscCall(DMLabelSetStratumIS(label, rank, closureIS));
10939566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&closureIS));
10949ffc88e4SToby Isaac   }
10959566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
10969566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
10979ffc88e4SToby Isaac   PetscFunctionReturn(0);
10989ffc88e4SToby Isaac }
10999ffc88e4SToby Isaac 
110024d039d7SMichael Lange /*@
110124d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
110224d039d7SMichael Lange 
110324d039d7SMichael Lange   Input Parameters:
110424d039d7SMichael Lange + dm     - The DM
1105a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
110624d039d7SMichael Lange 
110724d039d7SMichael Lange   Level: developer
110824d039d7SMichael Lange 
1109db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
111024d039d7SMichael Lange @*/
1111*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
1112*d71ae5a4SJacob Faibussowitsch {
111324d039d7SMichael Lange   IS              rankIS, pointIS;
111424d039d7SMichael Lange   const PetscInt *ranks, *points;
111524d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
111624d039d7SMichael Lange   PetscInt       *adj = NULL;
111770034214SMatthew G. Knepley 
111870034214SMatthew G. Knepley   PetscFunctionBegin;
11199566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &rankIS));
11209566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
11219566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
112224d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
112324d039d7SMichael Lange     const PetscInt rank = ranks[r];
112470034214SMatthew G. Knepley 
11259566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &pointIS));
11269566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
11279566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
112870034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
112924d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
11309566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency(dm, points[p], &adjSize, &adj));
11319566063dSJacob Faibussowitsch       for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(label, adj[a], rank));
113270034214SMatthew G. Knepley     }
11339566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
11349566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
113570034214SMatthew G. Knepley   }
11369566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11379566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11389566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
113924d039d7SMichael Lange   PetscFunctionReturn(0);
114070034214SMatthew G. Knepley }
114170034214SMatthew G. Knepley 
1142be200f8dSMichael Lange /*@
1143be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
1144be200f8dSMichael Lange 
1145be200f8dSMichael Lange   Input Parameters:
1146be200f8dSMichael Lange + dm     - The DM
1147a5b23f4aSJose E. Roman - label  - DMLabel assigning ranks to remote roots
1148be200f8dSMichael Lange 
1149be200f8dSMichael Lange   Level: developer
1150be200f8dSMichael Lange 
1151be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
1152be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
1153be200f8dSMichael Lange 
1154db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1155be200f8dSMichael Lange @*/
1156*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
1157*d71ae5a4SJacob Faibussowitsch {
1158be200f8dSMichael Lange   MPI_Comm        comm;
1159be200f8dSMichael Lange   PetscMPIInt     rank;
1160be200f8dSMichael Lange   PetscSF         sfPoint;
11615d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
1162be200f8dSMichael Lange   IS              rankIS, pointIS;
1163be200f8dSMichael Lange   const PetscInt *ranks;
1164be200f8dSMichael Lange   PetscInt        numRanks, r;
1165be200f8dSMichael Lange 
1166be200f8dSMichael Lange   PetscFunctionBegin;
11679566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
11689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
11699566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
11705d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
11719566063dSJacob Faibussowitsch   PetscCall(DMLabelGather(label, sfPoint, &lblLeaves));
11729566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(lblLeaves, &rankIS));
11739566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
11749566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
11755d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
11765d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
11775d04f6ebSMichael Lange     if (remoteRank == rank) continue;
11789566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS));
11799566063dSJacob Faibussowitsch     PetscCall(DMLabelInsertIS(label, pointIS, remoteRank));
11809566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
11815d04f6ebSMichael Lange   }
11829566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11839566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11849566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lblLeaves));
1185be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
11869566063dSJacob Faibussowitsch   PetscCall(DMLabelDistribute(label, sfPoint, &lblRoots));
11879566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(lblRoots, &rankIS));
11889566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
11899566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
1190be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
1191be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
1192be200f8dSMichael Lange     if (remoteRank == rank) continue;
11939566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS));
11949566063dSJacob Faibussowitsch     PetscCall(DMLabelInsertIS(label, pointIS, remoteRank));
11959566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
1196be200f8dSMichael Lange   }
11979566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11989566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11999566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lblRoots));
1200be200f8dSMichael Lange   PetscFunctionReturn(0);
1201be200f8dSMichael Lange }
1202be200f8dSMichael Lange 
12031fd9873aSMichael Lange /*@
12041fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
12051fd9873aSMichael Lange 
12061fd9873aSMichael Lange   Input Parameters:
12071fd9873aSMichael Lange + dm        - The DM
1208a5b23f4aSJose E. Roman . rootLabel - DMLabel assigning ranks to local roots
1209fe2efc57SMark - processSF - A star forest mapping into the local index on each remote rank
12101fd9873aSMichael Lange 
12111fd9873aSMichael Lange   Output Parameter:
1212a5b23f4aSJose E. Roman . leafLabel - DMLabel assigning ranks to remote roots
12131fd9873aSMichael Lange 
12141fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
12151fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
12161fd9873aSMichael Lange 
12171fd9873aSMichael Lange   Level: developer
12181fd9873aSMichael Lange 
1219db781477SPatrick Sanan .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
12201fd9873aSMichael Lange @*/
1221*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
1222*d71ae5a4SJacob Faibussowitsch {
12231fd9873aSMichael Lange   MPI_Comm           comm;
1224874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
1225874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
12261fd9873aSMichael Lange   PetscSF            sfPoint;
1227874ddda9SLisandro Dalcin   PetscSection       rootSection;
12281fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
12291fd9873aSMichael Lange   const PetscSFNode *remote;
12301fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
12311fd9873aSMichael Lange   IS                 valueIS;
1232874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
12331fd9873aSMichael Lange 
12341fd9873aSMichael Lange   PetscFunctionBegin;
12359566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_PartLabelInvert, dm, 0, 0, 0));
12369566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
12379566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
12389566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
12399566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
12401fd9873aSMichael Lange 
12411fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
12429566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &rootSection));
12439566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootSection, 0, size));
12449566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(rootLabel, &valueIS));
12459566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(valueIS, &numNeighbors));
12469566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(valueIS, &neighbors));
12471fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
12489566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints));
12499566063dSJacob Faibussowitsch     PetscCall(PetscSectionAddDof(rootSection, neighbors[n], numPoints));
12501fd9873aSMichael Lange   }
12519566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootSection));
12529566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(rootSection, &rootSize));
12539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rootSize, &rootPoints));
12549566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote));
12551fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
12561fd9873aSMichael Lange     IS              pointIS;
12571fd9873aSMichael Lange     const PetscInt *points;
12581fd9873aSMichael Lange 
12599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(rootSection, neighbors[n], &off));
12609566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS));
12619566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
12629566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
12631fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
12649566063dSJacob Faibussowitsch       if (local) PetscCall(PetscFindInt(points[p], nleaves, local, &l));
1265ad540459SPierre Jolivet       else l = -1;
12669371c9d4SSatish Balay       if (l >= 0) {
12679371c9d4SSatish Balay         rootPoints[off + p] = remote[l];
12689371c9d4SSatish Balay       } else {
12699371c9d4SSatish Balay         rootPoints[off + p].index = points[p];
12709371c9d4SSatish Balay         rootPoints[off + p].rank  = rank;
12719371c9d4SSatish Balay       }
12721fd9873aSMichael Lange     }
12739566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
12749566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
12751fd9873aSMichael Lange   }
1276874ddda9SLisandro Dalcin 
1277874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
1278874ddda9SLisandro Dalcin   if (!processSF) {
1279874ddda9SLisandro Dalcin     PetscInt64   counter     = 0;
1280874ddda9SLisandro Dalcin     PetscBool    locOverflow = PETSC_FALSE;
1281874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
1282874ddda9SLisandro Dalcin 
12839566063dSJacob Faibussowitsch     PetscCall(PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls));
1284874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
12859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootSection, neighbors[n], &dof));
12869566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootSection, neighbors[n], &off));
1287874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
12889371c9d4SSatish Balay       if (dof > PETSC_MPI_INT_MAX) {
12899371c9d4SSatish Balay         locOverflow = PETSC_TRUE;
12909371c9d4SSatish Balay         break;
12919371c9d4SSatish Balay       }
12929371c9d4SSatish Balay       if (off > PETSC_MPI_INT_MAX) {
12939371c9d4SSatish Balay         locOverflow = PETSC_TRUE;
12949371c9d4SSatish Balay         break;
12959371c9d4SSatish Balay       }
1296874ddda9SLisandro Dalcin #endif
1297874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt)dof;
1298874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt)off;
1299874ddda9SLisandro Dalcin     }
13009566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm));
13019371c9d4SSatish Balay     for (r = 0; r < size; ++r) {
13029371c9d4SSatish Balay       rdispls[r] = (int)counter;
13039371c9d4SSatish Balay       counter += rcounts[r];
13049371c9d4SSatish Balay     }
1305874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
13069566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm));
1307874ddda9SLisandro Dalcin     if (!mpiOverflow) {
13089566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Using Alltoallv for mesh distribution\n"));
1309874ddda9SLisandro Dalcin       leafSize = (PetscInt)counter;
13109566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(leafSize, &leafPoints));
13119566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm));
1312874ddda9SLisandro Dalcin     }
13139566063dSJacob Faibussowitsch     PetscCall(PetscFree4(scounts, sdispls, rcounts, rdispls));
1314874ddda9SLisandro Dalcin   }
1315874ddda9SLisandro Dalcin 
1316874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
1317874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
1318874ddda9SLisandro Dalcin     PetscSF      procSF;
1319874ddda9SLisandro Dalcin     PetscSection leafSection;
1320874ddda9SLisandro Dalcin 
1321874ddda9SLisandro Dalcin     if (processSF) {
13229566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Using processSF for mesh distribution\n"));
13239566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)processSF));
1324874ddda9SLisandro Dalcin       procSF = processSF;
1325874ddda9SLisandro Dalcin     } else {
13269566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Using processSF for mesh distribution (MPI overflow)\n"));
13279566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, &procSF));
13289566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphWithPattern(procSF, NULL, PETSCSF_PATTERN_ALLTOALL));
1329874ddda9SLisandro Dalcin     }
1330874ddda9SLisandro Dalcin 
13319566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection));
13329566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeData(dm, procSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void **)&leafPoints));
13339566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafSection, &leafSize));
13349566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
13359566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&procSF));
1336874ddda9SLisandro Dalcin   }
1337874ddda9SLisandro Dalcin 
133848a46eb9SPierre Jolivet   for (p = 0; p < leafSize; p++) PetscCall(DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank));
1339874ddda9SLisandro Dalcin 
13409566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(valueIS, &neighbors));
13419566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&valueIS));
13429566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootSection));
13439566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootPoints));
13449566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafPoints));
13459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_PartLabelInvert, dm, 0, 0, 0));
13461fd9873aSMichael Lange   PetscFunctionReturn(0);
13471fd9873aSMichael Lange }
13481fd9873aSMichael Lange 
1349aa3148a8SMichael Lange /*@
1350aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
1351aa3148a8SMichael Lange 
1352aa3148a8SMichael Lange   Input Parameters:
1353aa3148a8SMichael Lange + dm    - The DM
1354a5b23f4aSJose E. Roman - label - DMLabel assigning ranks to remote roots
1355aa3148a8SMichael Lange 
1356aa3148a8SMichael Lange   Output Parameter:
1357fe2efc57SMark . sf    - The star forest communication context encapsulating the defined mapping
1358aa3148a8SMichael Lange 
1359aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
1360aa3148a8SMichael Lange 
1361aa3148a8SMichael Lange   Level: developer
1362aa3148a8SMichael Lange 
1363db781477SPatrick Sanan .seealso: `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1364aa3148a8SMichael Lange @*/
1365*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
1366*d71ae5a4SJacob Faibussowitsch {
13676e203dd9SStefano Zampini   PetscMPIInt     rank;
13686e203dd9SStefano Zampini   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
1369aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
13706e203dd9SStefano Zampini   IS              remoteRootIS, neighborsIS;
13716e203dd9SStefano Zampini   const PetscInt *remoteRoots, *neighbors;
1372aa3148a8SMichael Lange 
1373aa3148a8SMichael Lange   PetscFunctionBegin;
13749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_PartLabelCreateSF, dm, 0, 0, 0));
13759566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1376aa3148a8SMichael Lange 
13779566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &neighborsIS));
13786e203dd9SStefano Zampini #if 0
13796e203dd9SStefano Zampini   {
13806e203dd9SStefano Zampini     IS is;
13819566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(neighborsIS, &is));
13829566063dSJacob Faibussowitsch     PetscCall(ISSort(is));
13839566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&neighborsIS));
13846e203dd9SStefano Zampini     neighborsIS = is;
13856e203dd9SStefano Zampini   }
13866e203dd9SStefano Zampini #endif
13879566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(neighborsIS, &nNeighbors));
13889566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(neighborsIS, &neighbors));
13896e203dd9SStefano Zampini   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
13909566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(label, neighbors[n], &numPoints));
1391aa3148a8SMichael Lange     numRemote += numPoints;
1392aa3148a8SMichael Lange   }
13939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRemote, &remotePoints));
139443f7d02bSMichael Lange   /* Put owned points first */
13959566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumSize(label, rank, &numPoints));
139643f7d02bSMichael Lange   if (numPoints > 0) {
13979566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &remoteRootIS));
13989566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(remoteRootIS, &remoteRoots));
139943f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
140043f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
140143f7d02bSMichael Lange       remotePoints[idx].rank  = rank;
140243f7d02bSMichael Lange       idx++;
140343f7d02bSMichael Lange     }
14049566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(remoteRootIS, &remoteRoots));
14059566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&remoteRootIS));
140643f7d02bSMichael Lange   }
140743f7d02bSMichael Lange   /* Now add remote points */
14086e203dd9SStefano Zampini   for (n = 0; n < nNeighbors; ++n) {
14096e203dd9SStefano Zampini     const PetscInt nn = neighbors[n];
14106e203dd9SStefano Zampini 
14119566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(label, nn, &numPoints));
14126e203dd9SStefano Zampini     if (nn == rank || numPoints <= 0) continue;
14139566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, nn, &remoteRootIS));
14149566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(remoteRootIS, &remoteRoots));
1415aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
1416aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
14176e203dd9SStefano Zampini       remotePoints[idx].rank  = nn;
1418aa3148a8SMichael Lange       idx++;
1419aa3148a8SMichael Lange     }
14209566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(remoteRootIS, &remoteRoots));
14219566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&remoteRootIS));
1422aa3148a8SMichael Lange   }
14239566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), sf));
14249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
14259566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, pEnd - pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER));
14269566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(*sf));
14279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&neighborsIS));
14289566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_PartLabelCreateSF, dm, 0, 0, 0));
142970034214SMatthew G. Knepley   PetscFunctionReturn(0);
143070034214SMatthew G. Knepley }
1431cb87ef4cSFlorian Wechsung 
1432abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PARMETIS)
1433abe9303eSLisandro Dalcin   #include <parmetis.h>
1434abe9303eSLisandro Dalcin #endif
1435abe9303eSLisandro Dalcin 
14366a3739e5SFlorian Wechsung /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
14376a3739e5SFlorian Wechsung  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
14386a3739e5SFlorian Wechsung  * them out in that case. */
14396a3739e5SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
14407a82c785SFlorian Wechsung /*@C
14417f57c1a4SFlorian Wechsung 
14427f57c1a4SFlorian Wechsung   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).
14437f57c1a4SFlorian Wechsung 
14447f57c1a4SFlorian Wechsung   Input parameters:
14457f57c1a4SFlorian Wechsung + dm                - The DMPlex object.
1446fe2efc57SMark . n                 - The number of points.
1447fe2efc57SMark . pointsToRewrite   - The points in the SF whose ownership will change.
1448fe2efc57SMark . targetOwners      - New owner for each element in pointsToRewrite.
1449fe2efc57SMark - degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.
14507f57c1a4SFlorian Wechsung 
14517f57c1a4SFlorian Wechsung   Level: developer
14527f57c1a4SFlorian Wechsung 
14537f57c1a4SFlorian Wechsung @*/
1454*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
1455*d71ae5a4SJacob Faibussowitsch {
14565f80ce2aSJacob Faibussowitsch   PetscInt           pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
14577f57c1a4SFlorian Wechsung   PetscInt          *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
14587f57c1a4SFlorian Wechsung   PetscSFNode       *leafLocationsNew;
14597f57c1a4SFlorian Wechsung   const PetscSFNode *iremote;
14607f57c1a4SFlorian Wechsung   const PetscInt    *ilocal;
14617f57c1a4SFlorian Wechsung   PetscBool         *isLeaf;
14627f57c1a4SFlorian Wechsung   PetscSF            sf;
14637f57c1a4SFlorian Wechsung   MPI_Comm           comm;
14645a30b08bSFlorian Wechsung   PetscMPIInt        rank, size;
14657f57c1a4SFlorian Wechsung 
14667f57c1a4SFlorian Wechsung   PetscFunctionBegin;
14679566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
14689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
14699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
14709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
14717f57c1a4SFlorian Wechsung 
14729566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
14739566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
14749566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isLeaf));
1475ad540459SPierre Jolivet   for (i = 0; i < pEnd - pStart; i++) isLeaf[i] = PETSC_FALSE;
1476ad540459SPierre Jolivet   for (i = 0; i < nleafs; i++) isLeaf[ilocal[i] - pStart] = PETSC_TRUE;
14777f57c1a4SFlorian Wechsung 
14789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart + 1, &cumSumDegrees));
14797f57c1a4SFlorian Wechsung   cumSumDegrees[0] = 0;
1480ad540459SPierre Jolivet   for (i = 1; i <= pEnd - pStart; i++) cumSumDegrees[i] = cumSumDegrees[i - 1] + degrees[i - 1];
14817f57c1a4SFlorian Wechsung   sumDegrees = cumSumDegrees[pEnd - pStart];
14827f57c1a4SFlorian Wechsung   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
14837f57c1a4SFlorian Wechsung 
14849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(sumDegrees, &locationsOfLeafs));
14859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &rankOnLeafs));
1486ad540459SPierre Jolivet   for (i = 0; i < pEnd - pStart; i++) rankOnLeafs[i] = rank;
14879566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
14889566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
14899566063dSJacob Faibussowitsch   PetscCall(PetscFree(rankOnLeafs));
14907f57c1a4SFlorian Wechsung 
14917f57c1a4SFlorian Wechsung   /* get the remote local points of my leaves */
14929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs));
14939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &points));
1494ad540459SPierre Jolivet   for (i = 0; i < pEnd - pStart; i++) points[i] = pStart + i;
14959566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
14969566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
14979566063dSJacob Faibussowitsch   PetscCall(PetscFree(points));
14987f57c1a4SFlorian Wechsung   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
14999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &newOwners));
15009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &newNumbers));
15017f57c1a4SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
15027f57c1a4SFlorian Wechsung     newOwners[i]  = -1;
15037f57c1a4SFlorian Wechsung     newNumbers[i] = -1;
15047f57c1a4SFlorian Wechsung   }
15057f57c1a4SFlorian Wechsung   {
15067f57c1a4SFlorian Wechsung     PetscInt oldNumber, newNumber, oldOwner, newOwner;
15077f57c1a4SFlorian Wechsung     for (i = 0; i < n; i++) {
15087f57c1a4SFlorian Wechsung       oldNumber = pointsToRewrite[i];
15097f57c1a4SFlorian Wechsung       newNumber = -1;
15107f57c1a4SFlorian Wechsung       oldOwner  = rank;
15117f57c1a4SFlorian Wechsung       newOwner  = targetOwners[i];
15127f57c1a4SFlorian Wechsung       if (oldOwner == newOwner) {
15137f57c1a4SFlorian Wechsung         newNumber = oldNumber;
15147f57c1a4SFlorian Wechsung       } else {
15157f57c1a4SFlorian Wechsung         for (j = 0; j < degrees[oldNumber]; j++) {
15167f57c1a4SFlorian Wechsung           if (locationsOfLeafs[cumSumDegrees[oldNumber] + j] == newOwner) {
15177f57c1a4SFlorian Wechsung             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber] + j];
15187f57c1a4SFlorian Wechsung             break;
15197f57c1a4SFlorian Wechsung           }
15207f57c1a4SFlorian Wechsung         }
15217f57c1a4SFlorian Wechsung       }
15225f80ce2aSJacob Faibussowitsch       PetscCheck(newNumber != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
15237f57c1a4SFlorian Wechsung 
15247f57c1a4SFlorian Wechsung       newOwners[oldNumber]  = newOwner;
15257f57c1a4SFlorian Wechsung       newNumbers[oldNumber] = newNumber;
15267f57c1a4SFlorian Wechsung     }
15277f57c1a4SFlorian Wechsung   }
15289566063dSJacob Faibussowitsch   PetscCall(PetscFree(cumSumDegrees));
15299566063dSJacob Faibussowitsch   PetscCall(PetscFree(locationsOfLeafs));
15309566063dSJacob Faibussowitsch   PetscCall(PetscFree(remoteLocalPointOfLeafs));
15317f57c1a4SFlorian Wechsung 
15329566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners, MPI_REPLACE));
15339566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners, MPI_REPLACE));
15349566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers, MPI_REPLACE));
15359566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers, MPI_REPLACE));
15367f57c1a4SFlorian Wechsung 
15377f57c1a4SFlorian Wechsung   /* Now count how many leafs we have on each processor. */
15387f57c1a4SFlorian Wechsung   leafCounter = 0;
15397f57c1a4SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
15407f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
1541ad540459SPierre Jolivet       if (newOwners[i] != rank) leafCounter++;
15427f57c1a4SFlorian Wechsung     } else {
1543ad540459SPierre Jolivet       if (isLeaf[i]) leafCounter++;
15447f57c1a4SFlorian Wechsung     }
15457f57c1a4SFlorian Wechsung   }
15467f57c1a4SFlorian Wechsung 
15477f57c1a4SFlorian Wechsung   /* Now set up the new sf by creating the leaf arrays */
15489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(leafCounter, &leafsNew));
15499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(leafCounter, &leafLocationsNew));
15507f57c1a4SFlorian Wechsung 
15517f57c1a4SFlorian Wechsung   leafCounter = 0;
15527f57c1a4SFlorian Wechsung   counter     = 0;
15537f57c1a4SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
15547f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
15557f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
15567f57c1a4SFlorian Wechsung         leafsNew[leafCounter]               = i;
15577f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank  = newOwners[i];
15587f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = newNumbers[i];
15597f57c1a4SFlorian Wechsung         leafCounter++;
15607f57c1a4SFlorian Wechsung       }
15617f57c1a4SFlorian Wechsung     } else {
15627f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
15637f57c1a4SFlorian Wechsung         leafsNew[leafCounter]               = i;
15647f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank  = iremote[counter].rank;
15657f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = iremote[counter].index;
15667f57c1a4SFlorian Wechsung         leafCounter++;
15677f57c1a4SFlorian Wechsung       }
15687f57c1a4SFlorian Wechsung     }
1569ad540459SPierre Jolivet     if (isLeaf[i]) counter++;
15707f57c1a4SFlorian Wechsung   }
15717f57c1a4SFlorian Wechsung 
15729566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER));
15739566063dSJacob Faibussowitsch   PetscCall(PetscFree(newOwners));
15749566063dSJacob Faibussowitsch   PetscCall(PetscFree(newNumbers));
15759566063dSJacob Faibussowitsch   PetscCall(PetscFree(isLeaf));
15767f57c1a4SFlorian Wechsung   PetscFunctionReturn(0);
15777f57c1a4SFlorian Wechsung }
15787f57c1a4SFlorian Wechsung 
1579*d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
1580*d71ae5a4SJacob Faibussowitsch {
15815f80ce2aSJacob Faibussowitsch   PetscInt   *distribution, min, max, sum;
15825a30b08bSFlorian Wechsung   PetscMPIInt rank, size;
15835f80ce2aSJacob Faibussowitsch 
1584125d2a8fSFlorian Wechsung   PetscFunctionBegin;
15859566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
15869566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
15879566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &distribution));
15885f80ce2aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; i++) {
1589125d2a8fSFlorian Wechsung     if (part) distribution[part[i]] += vtxwgt[skip * i];
1590125d2a8fSFlorian Wechsung     else distribution[rank] += vtxwgt[skip * i];
1591125d2a8fSFlorian Wechsung   }
15929566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm));
1593125d2a8fSFlorian Wechsung   min = distribution[0];
1594125d2a8fSFlorian Wechsung   max = distribution[0];
1595125d2a8fSFlorian Wechsung   sum = distribution[0];
15965f80ce2aSJacob Faibussowitsch   for (PetscInt i = 1; i < size; i++) {
1597125d2a8fSFlorian Wechsung     if (distribution[i] < min) min = distribution[i];
1598125d2a8fSFlorian Wechsung     if (distribution[i] > max) max = distribution[i];
1599125d2a8fSFlorian Wechsung     sum += distribution[i];
1600125d2a8fSFlorian Wechsung   }
160163a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "Min: %" PetscInt_FMT ", Avg: %" PetscInt_FMT ", Max: %" PetscInt_FMT ", Balance: %f\n", min, sum / size, max, (max * 1. * size) / sum));
16029566063dSJacob Faibussowitsch   PetscCall(PetscFree(distribution));
1603125d2a8fSFlorian Wechsung   PetscFunctionReturn(0);
1604125d2a8fSFlorian Wechsung }
1605125d2a8fSFlorian Wechsung 
16066a3739e5SFlorian Wechsung #endif
16076a3739e5SFlorian Wechsung 
1608cb87ef4cSFlorian Wechsung /*@
16095dc86ac1SFlorian 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.
1610cb87ef4cSFlorian Wechsung 
1611cb87ef4cSFlorian Wechsung   Input parameters:
1612ed44d270SFlorian Wechsung + dm               - The DMPlex object.
1613fe2efc57SMark . entityDepth      - depth of the entity to balance (0 -> balance vertices).
1614fe2efc57SMark . useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
1615fe2efc57SMark - parallel         - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.
1616cb87ef4cSFlorian Wechsung 
16178b879b41SFlorian Wechsung   Output parameters:
1618252a1336SBarry Smith . success          - whether the graph partitioning was successful or not, optional. Unsuccessful simply means no change to the partitioning
1619252a1336SBarry Smith 
1620252a1336SBarry Smith   Options Database:
1621252a1336SBarry Smith +  -dm_plex_rebalance_shared_points_parmetis - Use ParMetis instead of Metis for the partitioner
1622252a1336SBarry Smith .  -dm_plex_rebalance_shared_points_use_initial_guess - Use current partition to bootstrap ParMetis partition
1623252a1336SBarry Smith .  -dm_plex_rebalance_shared_points_use_mat_partitioning - Use the MatPartitioning object to perform the partition, the prefix for those operations is -dm_plex_rebalance_shared_points_
1624252a1336SBarry Smith -  -dm_plex_rebalance_shared_points_monitor - Monitor the shared points rebalance process
1625252a1336SBarry Smith 
1626252a1336SBarry Smith   Developer Notes:
1627252a1336SBarry Smith   This should use MatPartitioning to allow the use of any partitioner and not be hardwired to use ParMetis
16288b879b41SFlorian Wechsung 
162990ea27d8SSatish Balay   Level: intermediate
1630cb87ef4cSFlorian Wechsung @*/
1631*d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
1632*d71ae5a4SJacob Faibussowitsch {
163341525646SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
1634cb87ef4cSFlorian Wechsung   PetscSF            sf;
16350faf6628SFlorian Wechsung   PetscInt           ierr, i, j, idx, jdx;
16367f57c1a4SFlorian Wechsung   PetscInt           eBegin, eEnd, nroots, nleafs, pStart, pEnd;
16377f57c1a4SFlorian Wechsung   const PetscInt    *degrees, *ilocal;
16387f57c1a4SFlorian Wechsung   const PetscSFNode *iremote;
1639cb87ef4cSFlorian Wechsung   PetscBool         *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
1640cf818975SFlorian Wechsung   PetscInt           numExclusivelyOwned, numNonExclusivelyOwned;
1641cb87ef4cSFlorian Wechsung   PetscMPIInt        rank, size;
16427f57c1a4SFlorian Wechsung   PetscInt          *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
16435dc86ac1SFlorian Wechsung   const PetscInt    *cumSumVertices;
1644cb87ef4cSFlorian Wechsung   PetscInt           offset, counter;
1645252a1336SBarry Smith   PetscInt          *vtxwgt;
1646252a1336SBarry Smith   const PetscInt    *xadj, *adjncy;
1647cb87ef4cSFlorian Wechsung   PetscInt          *part, *options;
1648cf818975SFlorian Wechsung   PetscInt           nparts, wgtflag, numflag, ncon, edgecut;
1649cb87ef4cSFlorian Wechsung   real_t            *ubvec;
1650cb87ef4cSFlorian Wechsung   PetscInt          *firstVertices, *renumbering;
1651cb87ef4cSFlorian Wechsung   PetscInt           failed, failedGlobal;
1652cb87ef4cSFlorian Wechsung   MPI_Comm           comm;
1653252a1336SBarry Smith   Mat                A;
16547d197802SFlorian Wechsung   PetscViewer        viewer;
16557d197802SFlorian Wechsung   PetscViewerFormat  format;
16565a30b08bSFlorian Wechsung   PetscLayout        layout;
1657252a1336SBarry Smith   real_t            *tpwgts;
1658252a1336SBarry Smith   PetscMPIInt       *counts, *mpiCumSumVertices;
1659252a1336SBarry Smith   PetscInt          *pointsToRewrite;
1660252a1336SBarry Smith   PetscInt           numRows;
1661252a1336SBarry Smith   PetscBool          done, usematpartitioning = PETSC_FALSE;
1662252a1336SBarry Smith   IS                 ispart = NULL;
1663252a1336SBarry Smith   MatPartitioning    mp;
1664252a1336SBarry Smith   const char        *prefix;
166512617df9SFlorian Wechsung 
166612617df9SFlorian Wechsung   PetscFunctionBegin;
16679566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
16689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
1669252a1336SBarry Smith   if (size == 1) {
1670252a1336SBarry Smith     if (success) *success = PETSC_TRUE;
1671252a1336SBarry Smith     PetscFunctionReturn(0);
1672252a1336SBarry Smith   }
1673252a1336SBarry Smith   if (success) *success = PETSC_FALSE;
1674252a1336SBarry Smith   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1675252a1336SBarry Smith 
1676252a1336SBarry Smith   parallel        = PETSC_FALSE;
1677252a1336SBarry Smith   useInitialGuess = PETSC_FALSE;
1678252a1336SBarry Smith   PetscObjectOptionsBegin((PetscObject)dm);
1679252a1336SBarry Smith   PetscCall(PetscOptionsName("-dm_plex_rebalance_shared_points_parmetis", "Use ParMetis instead of Metis for the partitioner", "DMPlexRebalanceSharedPoints", &parallel));
1680252a1336SBarry Smith   PetscCall(PetscOptionsBool("-dm_plex_rebalance_shared_points_use_initial_guess", "Use current partition to bootstrap ParMetis partition", "DMPlexRebalanceSharedPoints", useInitialGuess, &useInitialGuess, NULL));
1681252a1336SBarry Smith   PetscCall(PetscOptionsBool("-dm_plex_rebalance_shared_points_use_mat_partitioning", "Use the MatPartitioning object to partition", "DMPlexRebalanceSharedPoints", usematpartitioning, &usematpartitioning, NULL));
1682252a1336SBarry Smith   PetscCall(PetscOptionsViewer("-dm_plex_rebalance_shared_points_monitor", "Monitor the shared points rebalance process", "DMPlexRebalanceSharedPoints", &viewer, &format, NULL));
1683252a1336SBarry Smith   PetscOptionsEnd();
1684252a1336SBarry Smith   if (viewer) PetscCall(PetscViewerPushFormat(viewer, format));
16857f57c1a4SFlorian Wechsung 
16869566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
168741525646SFlorian Wechsung 
1688252a1336SBarry Smith   PetscCall(DMGetOptionsPrefix(dm, &prefix));
16899566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, ((PetscObject)dm)->options, prefix, "-dm_rebalance_partition_view", &viewer, &format, NULL));
16901baa6e33SBarry Smith   if (viewer) PetscCall(PetscViewerPushFormat(viewer, format));
16917d197802SFlorian Wechsung 
1692ed44d270SFlorian Wechsung   /* Figure out all points in the plex that we are interested in balancing. */
16939566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd));
16949566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
16959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &toBalance));
1696ad540459SPierre Jolivet   for (i = 0; i < pEnd - pStart; i++) toBalance[i] = (PetscBool)(i >= eBegin && i < eEnd);
1697cb87ef4cSFlorian Wechsung 
1698cf818975SFlorian Wechsung   /* There are three types of points:
1699cf818975SFlorian Wechsung    * exclusivelyOwned: points that are owned by this process and only seen by this process
1700cf818975SFlorian Wechsung    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
1701cf818975SFlorian Wechsung    * leaf: a point that is seen by this process but owned by a different process
1702cf818975SFlorian Wechsung    */
17039566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
17049566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
17059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isLeaf));
17069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isNonExclusivelyOwned));
17079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isExclusivelyOwned));
1708cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1709cb87ef4cSFlorian Wechsung     isNonExclusivelyOwned[i] = PETSC_FALSE;
1710cb87ef4cSFlorian Wechsung     isExclusivelyOwned[i]    = PETSC_FALSE;
1711cf818975SFlorian Wechsung     isLeaf[i]                = PETSC_FALSE;
1712cb87ef4cSFlorian Wechsung   }
1713cf818975SFlorian Wechsung 
1714252a1336SBarry Smith   /* mark all the leafs */
1715ad540459SPierre Jolivet   for (i = 0; i < nleafs; i++) isLeaf[ilocal[i] - pStart] = PETSC_TRUE;
1716cb87ef4cSFlorian Wechsung 
1717cf818975SFlorian Wechsung   /* for an owned point, we can figure out whether another processor sees it or
1718cf818975SFlorian Wechsung    * not by calculating its degree */
17199566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(sf, &degrees));
17209566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(sf, &degrees));
1721cb87ef4cSFlorian Wechsung   numExclusivelyOwned    = 0;
1722cb87ef4cSFlorian Wechsung   numNonExclusivelyOwned = 0;
1723cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1724cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
17257f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1726cb87ef4cSFlorian Wechsung         isNonExclusivelyOwned[i] = PETSC_TRUE;
1727cb87ef4cSFlorian Wechsung         numNonExclusivelyOwned += 1;
1728cb87ef4cSFlorian Wechsung       } else {
1729cb87ef4cSFlorian Wechsung         if (!isLeaf[i]) {
1730cb87ef4cSFlorian Wechsung           isExclusivelyOwned[i] = PETSC_TRUE;
1731cb87ef4cSFlorian Wechsung           numExclusivelyOwned += 1;
1732cb87ef4cSFlorian Wechsung         }
1733cb87ef4cSFlorian Wechsung       }
1734cb87ef4cSFlorian Wechsung     }
1735cb87ef4cSFlorian Wechsung   }
1736cb87ef4cSFlorian Wechsung 
1737252a1336SBarry Smith   /* Build a graph with one vertex per core representing the
1738cf818975SFlorian Wechsung    * exclusively owned points and then one vertex per nonExclusively owned
1739cf818975SFlorian Wechsung    * point. */
17409566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &layout));
17419566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned));
17429566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
17439566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRanges(layout, &cumSumVertices));
17449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &globalNumbersOfLocalOwnedVertices));
1745ad540459SPierre Jolivet   for (i = 0; i < pEnd - pStart; i++) globalNumbersOfLocalOwnedVertices[i] = pStart - 1;
1746cb87ef4cSFlorian Wechsung   offset  = cumSumVertices[rank];
1747cb87ef4cSFlorian Wechsung   counter = 0;
1748cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1749cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
17507f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1751cb87ef4cSFlorian Wechsung         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
1752cb87ef4cSFlorian Wechsung         counter++;
1753cb87ef4cSFlorian Wechsung       }
1754cb87ef4cSFlorian Wechsung     }
1755cb87ef4cSFlorian Wechsung   }
1756cb87ef4cSFlorian Wechsung 
1757cb87ef4cSFlorian Wechsung   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
17589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &leafGlobalNumbers));
17599566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers, MPI_REPLACE));
17609566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers, MPI_REPLACE));
1761cb87ef4cSFlorian Wechsung 
1762252a1336SBarry Smith   /* Build the graph for partitioning */
1763252a1336SBarry Smith   numRows = 1 + numNonExclusivelyOwned;
1764252a1336SBarry Smith   PetscCall(PetscLogEventBegin(DMPLEX_RebalBuildGraph, dm, 0, 0, 0));
17659566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
1766252a1336SBarry Smith   PetscCall(MatSetType(A, MATMPIADJ));
1767252a1336SBarry Smith   PetscCall(MatSetSizes(A, numRows, numRows, cumSumVertices[size], cumSumVertices[size]));
1768252a1336SBarry Smith   idx = cumSumVertices[rank];
17694baf1206SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
17704baf1206SFlorian Wechsung     if (toBalance[i]) {
17710faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
17720faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
17730faf6628SFlorian Wechsung       else continue;
17749566063dSJacob Faibussowitsch       PetscCall(MatSetValue(A, idx, jdx, 1, INSERT_VALUES));
17759566063dSJacob Faibussowitsch       PetscCall(MatSetValue(A, jdx, idx, 1, INSERT_VALUES));
17760941debbSFlorian Wechsung     }
17770941debbSFlorian Wechsung   }
1778252a1336SBarry Smith   PetscCall(PetscFree(globalNumbersOfLocalOwnedVertices));
1779252a1336SBarry Smith   PetscCall(PetscFree(leafGlobalNumbers));
17809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
17819566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1782252a1336SBarry Smith   PetscCall(PetscLogEventEnd(DMPLEX_RebalBuildGraph, dm, 0, 0, 0));
17834baf1206SFlorian Wechsung 
178441525646SFlorian Wechsung   nparts = size;
1785252a1336SBarry Smith   ncon   = 1;
17869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon * nparts, &tpwgts));
1787ad540459SPierre Jolivet   for (i = 0; i < ncon * nparts; i++) tpwgts[i] = 1. / (nparts);
17889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon, &ubvec));
1789252a1336SBarry Smith   ubvec[0] = 1.05;
1790252a1336SBarry Smith   ubvec[1] = 1.05;
17918c9a1619SFlorian Wechsung 
17929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon * (1 + numNonExclusivelyOwned), &vtxwgt));
1793252a1336SBarry Smith   if (ncon == 2) {
179441525646SFlorian Wechsung     vtxwgt[0] = numExclusivelyOwned;
1795252a1336SBarry Smith     vtxwgt[1] = 1;
179641525646SFlorian Wechsung     for (i = 0; i < numNonExclusivelyOwned; i++) {
179741525646SFlorian Wechsung       vtxwgt[ncon * (i + 1)]     = 1;
1798252a1336SBarry Smith       vtxwgt[ncon * (i + 1) + 1] = 0;
1799252a1336SBarry Smith     }
1800252a1336SBarry Smith   } else {
1801252a1336SBarry Smith     PetscInt base, ms;
1802252a1336SBarry Smith     PetscCallMPI(MPI_Allreduce(&numExclusivelyOwned, &base, 1, MPIU_INT, MPIU_MAX, PetscObjectComm((PetscObject)dm)));
1803252a1336SBarry Smith     PetscCall(MatGetSize(A, &ms, NULL));
1804252a1336SBarry Smith     ms -= size;
1805252a1336SBarry Smith     base      = PetscMax(base, ms);
1806252a1336SBarry Smith     vtxwgt[0] = base + numExclusivelyOwned;
1807ad540459SPierre Jolivet     for (i = 0; i < numNonExclusivelyOwned; i++) vtxwgt[i + 1] = 1;
180841525646SFlorian Wechsung   }
18098c9a1619SFlorian Wechsung 
18105dc86ac1SFlorian Wechsung   if (viewer) {
181163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %" PetscInt_FMT " on interface of mesh distribution.\n", entityDepth));
181263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %" PetscInt_FMT "\n", cumSumVertices[size]));
181312617df9SFlorian Wechsung   }
1814252a1336SBarry Smith   /* TODO: Drop the parallel/sequential choice here and just use MatPartioner for much more flexibility */
1815252a1336SBarry Smith   if (usematpartitioning) {
1816252a1336SBarry Smith     const char *prefix;
1817252a1336SBarry Smith 
1818252a1336SBarry Smith     PetscCall(MatPartitioningCreate(PetscObjectComm((PetscObject)dm), &mp));
1819252a1336SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mp, "dm_plex_rebalance_shared_points_"));
1820252a1336SBarry Smith     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
1821252a1336SBarry Smith     PetscCall(PetscObjectPrependOptionsPrefix((PetscObject)mp, prefix));
1822252a1336SBarry Smith     PetscCall(MatPartitioningSetAdjacency(mp, A));
1823252a1336SBarry Smith     PetscCall(MatPartitioningSetNumberVertexWeights(mp, ncon));
1824252a1336SBarry Smith     PetscCall(MatPartitioningSetVertexWeights(mp, vtxwgt));
1825252a1336SBarry Smith     PetscCall(MatPartitioningSetFromOptions(mp));
1826252a1336SBarry Smith     PetscCall(MatPartitioningApply(mp, &ispart));
1827252a1336SBarry Smith     PetscCall(ISGetIndices(ispart, (const PetscInt **)&part));
1828252a1336SBarry Smith   } else if (parallel) {
1829252a1336SBarry Smith     if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n"));
1830252a1336SBarry Smith     PetscCall(PetscMalloc1(cumSumVertices[rank + 1] - cumSumVertices[rank], &part));
1831252a1336SBarry Smith     PetscCall(MatGetRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, &xadj, &adjncy, &done));
1832252a1336SBarry Smith     PetscCheck(done, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Could not get adjacency information");
18339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(4, &options));
18345a30b08bSFlorian Wechsung     options[0] = 1;
18355a30b08bSFlorian Wechsung     options[1] = 0; /* Verbosity */
1836252a1336SBarry Smith     if (viewer) options[1] = 1;
18375a30b08bSFlorian Wechsung     options[2] = 0;                    /* Seed */
18385a30b08bSFlorian Wechsung     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
1839252a1336SBarry Smith     wgtflag    = 2;
1840252a1336SBarry Smith     numflag    = 0;
18418c9a1619SFlorian Wechsung     if (useInitialGuess) {
1842252a1336SBarry Smith       PetscCall(PetscViewerASCIIPrintf(viewer, "THIS DOES NOT WORK! I don't know why. Using current distribution of points as initial guess.\n"));
1843252a1336SBarry Smith       for (i = 0; i < numRows; i++) part[i] = rank;
18449566063dSJacob Faibussowitsch       if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n"));
1845792fecdfSBarry Smith       PetscStackPushExternal("ParMETIS_V3_RefineKway");
1846252a1336SBarry Smith       PetscCall(PetscLogEventBegin(DMPLEX_RebalPartition, 0, 0, 0, 0));
1847252a1336SBarry Smith       ierr = ParMETIS_V3_RefineKway((PetscInt *)cumSumVertices, (idx_t *)xadj, (idx_t *)adjncy, vtxwgt, NULL, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
1848252a1336SBarry Smith       PetscCall(PetscLogEventEnd(DMPLEX_RebalPartition, 0, 0, 0, 0));
18498c9a1619SFlorian Wechsung       PetscStackPop;
1850252a1336SBarry Smith       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
18518c9a1619SFlorian Wechsung     } else {
1852792fecdfSBarry Smith       PetscStackPushExternal("ParMETIS_V3_PartKway");
1853252a1336SBarry Smith       PetscCall(PetscLogEventBegin(DMPLEX_RebalPartition, 0, 0, 0, 0));
1854252a1336SBarry Smith       ierr = ParMETIS_V3_PartKway((PetscInt *)cumSumVertices, (idx_t *)xadj, (idx_t *)adjncy, vtxwgt, NULL, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
1855252a1336SBarry Smith       PetscCall(PetscLogEventEnd(DMPLEX_RebalPartition, 0, 0, 0, 0));
18568c9a1619SFlorian Wechsung       PetscStackPop;
18575f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
18588c9a1619SFlorian Wechsung     }
1859252a1336SBarry Smith     PetscCall(MatRestoreRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, &xadj, &adjncy, &done));
18609566063dSJacob Faibussowitsch     PetscCall(PetscFree(options));
186141525646SFlorian Wechsung   } else {
18629566063dSJacob Faibussowitsch     if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n"));
186341525646SFlorian Wechsung     Mat       As;
186441525646SFlorian Wechsung     PetscInt *partGlobal;
186541525646SFlorian Wechsung     PetscInt *numExclusivelyOwnedAll;
1866252a1336SBarry Smith 
1867252a1336SBarry Smith     PetscCall(PetscMalloc1(cumSumVertices[rank + 1] - cumSumVertices[rank], &part));
1868252a1336SBarry Smith     PetscCall(MatGetSize(A, &numRows, NULL));
1869252a1336SBarry Smith     PetscCall(PetscLogEventBegin(DMPLEX_RebalGatherGraph, dm, 0, 0, 0));
1870252a1336SBarry Smith     PetscCall(MatMPIAdjToSeqRankZero(A, &As));
1871252a1336SBarry Smith     PetscCall(PetscLogEventEnd(DMPLEX_RebalGatherGraph, dm, 0, 0, 0));
1872252a1336SBarry Smith 
18739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &numExclusivelyOwnedAll));
187441525646SFlorian Wechsung     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
18759566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, numExclusivelyOwnedAll, 1, MPIU_INT, comm));
1876cb87ef4cSFlorian Wechsung 
18779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRows, &partGlobal));
1878252a1336SBarry Smith     PetscCall(PetscLogEventBegin(DMPLEX_RebalPartition, 0, 0, 0, 0));
1879dd400576SPatrick Sanan     if (rank == 0) {
1880252a1336SBarry Smith       PetscInt *vtxwgt_g, numRows_g;
188141525646SFlorian Wechsung 
1882252a1336SBarry Smith       PetscCall(MatGetRowIJ(As, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows_g, &xadj, &adjncy, &done));
1883252a1336SBarry Smith       PetscCall(PetscMalloc1(2 * numRows_g, &vtxwgt_g));
188441525646SFlorian Wechsung       for (i = 0; i < size; i++) {
188541525646SFlorian Wechsung         vtxwgt_g[ncon * cumSumVertices[i]] = numExclusivelyOwnedAll[i];
188641525646SFlorian Wechsung         if (ncon > 1) vtxwgt_g[ncon * cumSumVertices[i] + 1] = 1;
188741525646SFlorian Wechsung         for (j = cumSumVertices[i] + 1; j < cumSumVertices[i + 1]; j++) {
188841525646SFlorian Wechsung           vtxwgt_g[ncon * j] = 1;
188941525646SFlorian Wechsung           if (ncon > 1) vtxwgt_g[2 * j + 1] = 0;
189041525646SFlorian Wechsung         }
189141525646SFlorian Wechsung       }
1892252a1336SBarry Smith 
18939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(64, &options));
189441525646SFlorian Wechsung       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
18955f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
189641525646SFlorian Wechsung       options[METIS_OPTION_CONTIG] = 1;
1897792fecdfSBarry Smith       PetscStackPushExternal("METIS_PartGraphKway");
1898252a1336SBarry Smith       ierr = METIS_PartGraphKway(&numRows_g, &ncon, (idx_t *)xadj, (idx_t *)adjncy, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
189941525646SFlorian Wechsung       PetscStackPop;
19005f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
19019566063dSJacob Faibussowitsch       PetscCall(PetscFree(options));
19029566063dSJacob Faibussowitsch       PetscCall(PetscFree(vtxwgt_g));
1903252a1336SBarry Smith       PetscCall(MatRestoreRowIJ(As, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows_g, &xadj, &adjncy, &done));
1904252a1336SBarry Smith       PetscCall(MatDestroy(&As));
190541525646SFlorian Wechsung     }
1906252a1336SBarry Smith     PetscCall(PetscBarrier((PetscObject)dm));
1907252a1336SBarry Smith     PetscCall(PetscLogEventEnd(DMPLEX_RebalPartition, 0, 0, 0, 0));
19089566063dSJacob Faibussowitsch     PetscCall(PetscFree(numExclusivelyOwnedAll));
190941525646SFlorian Wechsung 
1910252a1336SBarry Smith     /* scatter the partitioning information to ranks */
1911252a1336SBarry Smith     PetscCall(PetscLogEventBegin(DMPLEX_RebalScatterPart, 0, 0, 0, 0));
19129566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &counts));
19139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size + 1, &mpiCumSumVertices));
191448a46eb9SPierre Jolivet     for (i = 0; i < size; i++) PetscCall(PetscMPIIntCast(cumSumVertices[i + 1] - cumSumVertices[i], &(counts[i])));
191548a46eb9SPierre Jolivet     for (i = 0; i <= size; i++) PetscCall(PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i])));
19169566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm));
19179566063dSJacob Faibussowitsch     PetscCall(PetscFree(counts));
19189566063dSJacob Faibussowitsch     PetscCall(PetscFree(mpiCumSumVertices));
19199566063dSJacob Faibussowitsch     PetscCall(PetscFree(partGlobal));
1920252a1336SBarry Smith     PetscCall(PetscLogEventEnd(DMPLEX_RebalScatterPart, 0, 0, 0, 0));
192141525646SFlorian Wechsung   }
19229566063dSJacob Faibussowitsch   PetscCall(PetscFree(ubvec));
19239566063dSJacob Faibussowitsch   PetscCall(PetscFree(tpwgts));
1924cb87ef4cSFlorian Wechsung 
1925252a1336SBarry Smith   /* Rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
1926252a1336SBarry Smith   PetscCall(PetscMalloc2(size, &firstVertices, size, &renumbering));
1927cb87ef4cSFlorian Wechsung   firstVertices[rank] = part[0];
19289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, firstVertices, 1, MPIU_INT, comm));
1929ad540459SPierre Jolivet   for (i = 0; i < size; i++) renumbering[firstVertices[i]] = i;
1930ad540459SPierre Jolivet   for (i = 0; i < cumSumVertices[rank + 1] - cumSumVertices[rank]; i++) part[i] = renumbering[part[i]];
1931252a1336SBarry Smith   PetscCall(PetscFree2(firstVertices, renumbering));
1932252a1336SBarry Smith 
1933cb87ef4cSFlorian Wechsung   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
1934cb87ef4cSFlorian Wechsung   failed = (PetscInt)(part[0] != rank);
19359566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm));
1936cb87ef4cSFlorian Wechsung   if (failedGlobal > 0) {
1937252a1336SBarry Smith     PetscCheck(failedGlobal <= 0, comm, PETSC_ERR_LIB, "Metis/Parmetis returned a bad partion");
19389566063dSJacob Faibussowitsch     PetscCall(PetscFree(vtxwgt));
19399566063dSJacob Faibussowitsch     PetscCall(PetscFree(toBalance));
19409566063dSJacob Faibussowitsch     PetscCall(PetscFree(isLeaf));
19419566063dSJacob Faibussowitsch     PetscCall(PetscFree(isNonExclusivelyOwned));
19429566063dSJacob Faibussowitsch     PetscCall(PetscFree(isExclusivelyOwned));
1943252a1336SBarry Smith     if (usematpartitioning) {
1944252a1336SBarry Smith       PetscCall(ISRestoreIndices(ispart, (const PetscInt **)&part));
1945252a1336SBarry Smith       PetscCall(ISDestroy(&ispart));
1946252a1336SBarry Smith     } else PetscCall(PetscFree(part));
19477f57c1a4SFlorian Wechsung     if (viewer) {
19489566063dSJacob Faibussowitsch       PetscCall(PetscViewerPopFormat(viewer));
19499566063dSJacob Faibussowitsch       PetscCall(PetscViewerDestroy(&viewer));
19507f57c1a4SFlorian Wechsung     }
19519566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
19528b879b41SFlorian Wechsung     PetscFunctionReturn(0);
1953cb87ef4cSFlorian Wechsung   }
1954cb87ef4cSFlorian Wechsung 
1955252a1336SBarry Smith   /* Check how well we did distributing points*/
19565dc86ac1SFlorian Wechsung   if (viewer) {
1957252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "Number of owned entities of depth %" PetscInt_FMT ".\n", entityDepth));
1958252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "Initial      "));
19599566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank + 1] - cumSumVertices[rank], ncon, vtxwgt, NULL, viewer));
1960252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "Rebalanced   "));
19619566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank + 1] - cumSumVertices[rank], ncon, vtxwgt, part, viewer));
19627407ba93SFlorian Wechsung   }
19637407ba93SFlorian Wechsung 
1964252a1336SBarry Smith   /* Check that every vertex is owned by a process that it is actually connected to. */
1965252a1336SBarry Smith   PetscCall(MatGetRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
196641525646SFlorian Wechsung   for (i = 1; i <= numNonExclusivelyOwned; i++) {
1967cb87ef4cSFlorian Wechsung     PetscInt loc = 0;
19689566063dSJacob Faibussowitsch     PetscCall(PetscFindInt(cumSumVertices[part[i]], xadj[i + 1] - xadj[i], &adjncy[xadj[i]], &loc));
19697407ba93SFlorian Wechsung     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
1970ad540459SPierre Jolivet     if (loc < 0) part[i] = rank;
1971cb87ef4cSFlorian Wechsung   }
1972252a1336SBarry Smith   PetscCall(MatRestoreRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
1973252a1336SBarry Smith   PetscCall(MatDestroy(&A));
1974cb87ef4cSFlorian Wechsung 
1975252a1336SBarry Smith   /* See how significant the influences of the previous fixing up step was.*/
19765dc86ac1SFlorian Wechsung   if (viewer) {
1977252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "After fix    "));
19789566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank + 1] - cumSumVertices[rank], ncon, vtxwgt, part, viewer));
19797407ba93SFlorian Wechsung   }
1980252a1336SBarry Smith   if (!usematpartitioning) PetscCall(PetscFree(vtxwgt));
1981252a1336SBarry Smith   else PetscCall(MatPartitioningDestroy(&mp));
19827407ba93SFlorian Wechsung 
19839566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
1984cb87ef4cSFlorian Wechsung 
1985252a1336SBarry Smith   PetscCall(PetscLogEventBegin(DMPLEX_RebalRewriteSF, dm, 0, 0, 0));
1986252a1336SBarry Smith   /* Rewrite the SF to reflect the new ownership. */
19879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite));
19887f57c1a4SFlorian Wechsung   counter = 0;
1989cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1990cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
1991cb87ef4cSFlorian Wechsung       if (isNonExclusivelyOwned[i]) {
19927f57c1a4SFlorian Wechsung         pointsToRewrite[counter] = i + pStart;
1993cb87ef4cSFlorian Wechsung         counter++;
1994cb87ef4cSFlorian Wechsung       }
1995cb87ef4cSFlorian Wechsung     }
1996cb87ef4cSFlorian Wechsung   }
19979566063dSJacob Faibussowitsch   PetscCall(DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part + 1, degrees));
19989566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointsToRewrite));
1999252a1336SBarry Smith   PetscCall(PetscLogEventEnd(DMPLEX_RebalRewriteSF, dm, 0, 0, 0));
2000cb87ef4cSFlorian Wechsung 
20019566063dSJacob Faibussowitsch   PetscCall(PetscFree(toBalance));
20029566063dSJacob Faibussowitsch   PetscCall(PetscFree(isLeaf));
20039566063dSJacob Faibussowitsch   PetscCall(PetscFree(isNonExclusivelyOwned));
20049566063dSJacob Faibussowitsch   PetscCall(PetscFree(isExclusivelyOwned));
2005252a1336SBarry Smith   if (usematpartitioning) {
2006252a1336SBarry Smith     PetscCall(ISRestoreIndices(ispart, (const PetscInt **)&part));
2007252a1336SBarry Smith     PetscCall(ISDestroy(&ispart));
2008252a1336SBarry Smith   } else PetscCall(PetscFree(part));
20095dc86ac1SFlorian Wechsung   if (viewer) {
20109566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
20119566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
20127d197802SFlorian Wechsung   }
20138b879b41SFlorian Wechsung   if (success) *success = PETSC_TRUE;
20149566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
2015b458e8f1SJose E. Roman   PetscFunctionReturn(0);
2016240408d3SFlorian Wechsung #else
20175f441e9bSFlorian Wechsung   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
201841525646SFlorian Wechsung #endif
2019cb87ef4cSFlorian Wechsung }
2020