xref: /petsc/src/dm/impls/plex/plexpartition.c (revision e2b8d0fc37c770dc1e8c6fc3c68925307d037a77)
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 
7d71ae5a4SJacob Faibussowitsch static inline PetscInt DMPlex_GlobalID(PetscInt point)
8d71ae5a4SJacob Faibussowitsch {
99371c9d4SSatish Balay   return point >= 0 ? point : -(point + 1);
109371c9d4SSatish Balay }
110134a67bSLisandro Dalcin 
12d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreatePartitionerGraph_Overlap(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
13d71ae5a4SJacob 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 */
32*e2b8d0fcSMatthew G. Knepley     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering(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");
403ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
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));
1083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1095a107427SMatthew G. Knepley }
1105a107427SMatthew G. Knepley 
111d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
112d71ae5a4SJacob 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 */
134*e2b8d0fcSMatthew G. Knepley     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering(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");
1423ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
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     }
271f4f49eeaSPierre Jolivet     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));
294f4f49eeaSPierre 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));
3133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
314532c4e7dSMichael Lange }
315532c4e7dSMichael Lange 
316d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
317d71ae5a4SJacob 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 */
335*e2b8d0fcSMatthew G. Knepley     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering(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");
3433ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
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));
397712fec58SPierre Jolivet   PetscCall(MPIU_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));
4743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
475bbbc8e51SStefano Zampini }
476bbbc8e51SStefano Zampini 
477bbbc8e51SStefano Zampini /*@C
478bbbc8e51SStefano Zampini   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
479bbbc8e51SStefano Zampini 
48020f4b53cSBarry Smith   Collective
481a1cb98faSBarry Smith 
482bbbc8e51SStefano Zampini   Input Parameters:
483a1cb98faSBarry Smith + dm     - The mesh `DM`
484bbbc8e51SStefano Zampini - height - Height of the strata from which to construct the graph
485bbbc8e51SStefano Zampini 
486d8d19677SJose E. Roman   Output Parameters:
487bbbc8e51SStefano Zampini + numVertices     - Number of vertices in the graph
488bbbc8e51SStefano Zampini . offsets         - Point offsets in the graph
489bbbc8e51SStefano Zampini . adjacency       - Point connectivity in the graph
490bbbc8e51SStefano 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.
491bbbc8e51SStefano Zampini 
49220f4b53cSBarry Smith   Options Database Key:
4935a107427SMatthew G. Knepley . -dm_plex_csr_alg <mat,graph,overlap> - Choose the algorithm for computing the CSR graph
4945a107427SMatthew G. Knepley 
495bbbc8e51SStefano Zampini   Level: developer
496bbbc8e51SStefano Zampini 
497a1cb98faSBarry Smith   Note:
498a1cb98faSBarry Smith   The user can control the definition of adjacency for the mesh using `DMSetAdjacency()`. They should choose the combination appropriate for the function
499a1cb98faSBarry Smith   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
500a1cb98faSBarry Smith 
5011cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscPartitionerGetType()`, `PetscPartitionerCreate()`, `DMSetAdjacency()`
502bbbc8e51SStefano Zampini @*/
503d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
504d71ae5a4SJacob Faibussowitsch {
5055a107427SMatthew G. Knepley   DMPlexCSRAlgorithm alg = DM_PLEX_CSR_GRAPH;
506bbbc8e51SStefano Zampini 
507bbbc8e51SStefano Zampini   PetscFunctionBegin;
5089566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetEnum(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_csr_alg", DMPlexCSRAlgorithms, (PetscEnum *)&alg, NULL));
5095a107427SMatthew G. Knepley   switch (alg) {
510d71ae5a4SJacob Faibussowitsch   case DM_PLEX_CSR_MAT:
511d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering));
512d71ae5a4SJacob Faibussowitsch     break;
513d71ae5a4SJacob Faibussowitsch   case DM_PLEX_CSR_GRAPH:
514d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering));
515d71ae5a4SJacob Faibussowitsch     break;
516d71ae5a4SJacob Faibussowitsch   case DM_PLEX_CSR_OVERLAP:
517d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexCreatePartitionerGraph_Overlap(dm, height, numVertices, offsets, adjacency, globalNumbering));
518d71ae5a4SJacob Faibussowitsch     break;
519bbbc8e51SStefano Zampini   }
5203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
521bbbc8e51SStefano Zampini }
522bbbc8e51SStefano Zampini 
523d5577e40SMatthew G. Knepley /*@C
524d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
525d5577e40SMatthew G. Knepley 
52620f4b53cSBarry Smith   Collective
527d5577e40SMatthew G. Knepley 
5284165533cSJose E. Roman   Input Parameters:
529a1cb98faSBarry Smith + dm         - The `DMPLEX`
530d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
531d5577e40SMatthew G. Knepley 
5324165533cSJose E. Roman   Output Parameters:
533d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
534d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
535d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
536d5577e40SMatthew G. Knepley 
537d5577e40SMatthew G. Knepley   Level: advanced
538d5577e40SMatthew G. Knepley 
539a1cb98faSBarry Smith   Note:
540a1cb98faSBarry Smith   This is suitable for input to a mesh partitioner like ParMetis.
541a1cb98faSBarry Smith 
5421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`
543d5577e40SMatthew G. Knepley @*/
544d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
545d71ae5a4SJacob Faibussowitsch {
54670034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
54770034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
54870034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
54970034214SMatthew G. Knepley   PetscInt      *off, *adj;
55070034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
55170034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
55270034214SMatthew G. Knepley 
55370034214SMatthew G. Knepley   PetscFunctionBegin;
55470034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
5559566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
55670034214SMatthew G. Knepley   cellDim = dim - cellHeight;
5579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
5589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
55970034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
56070034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
56170034214SMatthew G. Knepley     if (offsets) *offsets = NULL;
56270034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
5633ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
56470034214SMatthew G. Knepley   }
56570034214SMatthew G. Knepley   numCells  = cEnd - cStart;
56670034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
56770034214SMatthew G. Knepley   if (dim == depth) {
56870034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
56970034214SMatthew G. Knepley 
5709566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(numCells + 1, &off));
57170034214SMatthew G. Knepley     /* Count neighboring cells */
5729566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, cellHeight + 1, &fStart, &fEnd));
57370034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
57470034214SMatthew G. Knepley       const PetscInt *support;
57570034214SMatthew G. Knepley       PetscInt        supportSize;
5769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
5779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, f, &support));
57870034214SMatthew G. Knepley       if (supportSize == 2) {
5799ffc88e4SToby Isaac         PetscInt numChildren;
5809ffc88e4SToby Isaac 
5819566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
5829ffc88e4SToby Isaac         if (!numChildren) {
58370034214SMatthew G. Knepley           ++off[support[0] - cStart + 1];
58470034214SMatthew G. Knepley           ++off[support[1] - cStart + 1];
58570034214SMatthew G. Knepley         }
58670034214SMatthew G. Knepley       }
5879ffc88e4SToby Isaac     }
58870034214SMatthew G. Knepley     /* Prefix sum */
58970034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c - 1];
59070034214SMatthew G. Knepley     if (adjacency) {
59170034214SMatthew G. Knepley       PetscInt *tmp;
59270034214SMatthew G. Knepley 
5939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(off[numCells], &adj));
5949566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numCells + 1, &tmp));
5959566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(tmp, off, numCells + 1));
59670034214SMatthew G. Knepley       /* Get neighboring cells */
59770034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
59870034214SMatthew G. Knepley         const PetscInt *support;
59970034214SMatthew G. Knepley         PetscInt        supportSize;
6009566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
6019566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, f, &support));
60270034214SMatthew G. Knepley         if (supportSize == 2) {
6039ffc88e4SToby Isaac           PetscInt numChildren;
6049ffc88e4SToby Isaac 
6059566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, NULL));
6069ffc88e4SToby Isaac           if (!numChildren) {
60770034214SMatthew G. Knepley             adj[tmp[support[0] - cStart]++] = support[1];
60870034214SMatthew G. Knepley             adj[tmp[support[1] - cStart]++] = support[0];
60970034214SMatthew G. Knepley           }
61070034214SMatthew G. Knepley         }
6119ffc88e4SToby Isaac       }
61263a3b9bcSJacob 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);
6139566063dSJacob Faibussowitsch       PetscCall(PetscFree(tmp));
61470034214SMatthew G. Knepley     }
61570034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
61670034214SMatthew G. Knepley     if (offsets) *offsets = off;
61770034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
6183ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
61970034214SMatthew G. Knepley   }
62070034214SMatthew G. Knepley   /* Setup face recognition */
62170034214SMatthew G. Knepley   if (faceDepth == 1) {
62270034214SMatthew 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 */
62370034214SMatthew G. Knepley 
62470034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
62570034214SMatthew G. Knepley       PetscInt corners;
62670034214SMatthew G. Knepley 
6279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, c, &corners));
62870034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
62970034214SMatthew G. Knepley         PetscInt nFV;
63070034214SMatthew G. Knepley 
6315f80ce2aSJacob Faibussowitsch         PetscCheck(numFaceCases < maxFaceCases, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
63270034214SMatthew G. Knepley         cornersSeen[corners] = 1;
63370034214SMatthew G. Knepley 
6349566063dSJacob Faibussowitsch         PetscCall(DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV));
63570034214SMatthew G. Knepley 
63670034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
63770034214SMatthew G. Knepley       }
63870034214SMatthew G. Knepley     }
63970034214SMatthew G. Knepley   }
6409566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numCells + 1, &off));
64170034214SMatthew G. Knepley   /* Count neighboring cells */
64270034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
64370034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
64470034214SMatthew G. Knepley 
6459566063dSJacob Faibussowitsch     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
64670034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
64770034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
64870034214SMatthew G. Knepley       PetscInt        cellPair[2];
64970034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
65070034214SMatthew G. Knepley       PetscInt        meetSize = 0;
65170034214SMatthew G. Knepley       const PetscInt *meet     = NULL;
65270034214SMatthew G. Knepley 
6539371c9d4SSatish Balay       cellPair[0] = cell;
6549371c9d4SSatish Balay       cellPair[1] = neighborCells[n];
65570034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
65670034214SMatthew G. Knepley       if (!found) {
6579566063dSJacob Faibussowitsch         PetscCall(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
65870034214SMatthew G. Knepley         if (meetSize) {
65970034214SMatthew G. Knepley           PetscInt f;
66070034214SMatthew G. Knepley 
66170034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
66270034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
66370034214SMatthew G. Knepley               found = PETSC_TRUE;
66470034214SMatthew G. Knepley               break;
66570034214SMatthew G. Knepley             }
66670034214SMatthew G. Knepley           }
66770034214SMatthew G. Knepley         }
6689566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
66970034214SMatthew G. Knepley       }
67070034214SMatthew G. Knepley       if (found) ++off[cell - cStart + 1];
67170034214SMatthew G. Knepley     }
67270034214SMatthew G. Knepley   }
67370034214SMatthew G. Knepley   /* Prefix sum */
67470034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell - 1];
67570034214SMatthew G. Knepley 
67670034214SMatthew G. Knepley   if (adjacency) {
6779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(off[numCells], &adj));
67870034214SMatthew G. Knepley     /* Get neighboring cells */
67970034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
68070034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
68170034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
68270034214SMatthew G. Knepley 
6839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
68470034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
68570034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
68670034214SMatthew G. Knepley         PetscInt        cellPair[2];
68770034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
68870034214SMatthew G. Knepley         PetscInt        meetSize = 0;
68970034214SMatthew G. Knepley         const PetscInt *meet     = NULL;
69070034214SMatthew G. Knepley 
6919371c9d4SSatish Balay         cellPair[0] = cell;
6929371c9d4SSatish Balay         cellPair[1] = neighborCells[n];
69370034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
69470034214SMatthew G. Knepley         if (!found) {
6959566063dSJacob Faibussowitsch           PetscCall(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
69670034214SMatthew G. Knepley           if (meetSize) {
69770034214SMatthew G. Knepley             PetscInt f;
69870034214SMatthew G. Knepley 
69970034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
70070034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
70170034214SMatthew G. Knepley                 found = PETSC_TRUE;
70270034214SMatthew G. Knepley                 break;
70370034214SMatthew G. Knepley               }
70470034214SMatthew G. Knepley             }
70570034214SMatthew G. Knepley           }
7069566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
70770034214SMatthew G. Knepley         }
70870034214SMatthew G. Knepley         if (found) {
70970034214SMatthew G. Knepley           adj[off[cell - cStart] + cellOffset] = neighborCells[n];
71070034214SMatthew G. Knepley           ++cellOffset;
71170034214SMatthew G. Knepley         }
71270034214SMatthew G. Knepley       }
71370034214SMatthew G. Knepley     }
71470034214SMatthew G. Knepley   }
7159566063dSJacob Faibussowitsch   PetscCall(PetscFree(neighborCells));
71670034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
71770034214SMatthew G. Knepley   if (offsets) *offsets = off;
71870034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
7193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
72070034214SMatthew G. Knepley }
72170034214SMatthew G. Knepley 
72277623264SMatthew G. Knepley /*@
7233c41b853SStefano Zampini   PetscPartitionerDMPlexPartition - Create a non-overlapping partition of the cells in the mesh
72477623264SMatthew G. Knepley 
72520f4b53cSBarry Smith   Collective
72677623264SMatthew G. Knepley 
72777623264SMatthew G. Knepley   Input Parameters:
728a1cb98faSBarry Smith + part          - The `PetscPartitioner`
72920f4b53cSBarry Smith . targetSection - The `PetscSection` describing the absolute weight of each partition (can be `NULL`)
730a1cb98faSBarry Smith - dm            - The mesh `DM`
73177623264SMatthew G. Knepley 
73277623264SMatthew G. Knepley   Output Parameters:
733a1cb98faSBarry Smith + partSection - The `PetscSection` giving the division of points by partition
734f8987ae8SMichael Lange - partition   - The list of points by partition
73577623264SMatthew G. Knepley 
73677623264SMatthew G. Knepley   Level: developer
73777623264SMatthew G. Knepley 
738a1cb98faSBarry Smith   Note:
739a1cb98faSBarry Smith   If the `DM` has a local section associated, each point to be partitioned will be weighted by the total number of dofs identified
740a1cb98faSBarry Smith   by the section in the transitive closure of the point.
741a1cb98faSBarry Smith 
7421cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscPartitioner`, `PetscSection`, `DMPlexDistribute()`, `PetscPartitionerCreate()`, `PetscSectionCreate()`,
743a1cb98faSBarry Smith          `PetscSectionSetChart()`, `PetscPartitionerPartition()`
7444b15ede2SMatthew G. Knepley @*/
745d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPartitionerDMPlexPartition(PetscPartitioner part, DM dm, PetscSection targetSection, PetscSection partSection, IS *partition)
746d71ae5a4SJacob Faibussowitsch {
74777623264SMatthew G. Knepley   PetscMPIInt  size;
7483c41b853SStefano Zampini   PetscBool    isplex;
74921c92275SMatthew G. Knepley   PetscSection vertSection = NULL, edgeSection = NULL;
75077623264SMatthew G. Knepley 
75177623264SMatthew G. Knepley   PetscFunctionBegin;
75277623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
75377623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
7543c41b853SStefano Zampini   if (targetSection) PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 3);
75577623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
7564f572ea9SToby Isaac   PetscAssertPointer(partition, 5);
7579566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isplex));
7585f80ce2aSJacob Faibussowitsch   PetscCheck(isplex, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not for type %s", ((PetscObject)dm)->type_name);
7599566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)part), &size));
76077623264SMatthew G. Knepley   if (size == 1) {
76177623264SMatthew G. Knepley     PetscInt *points;
76277623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
76377623264SMatthew G. Knepley 
7649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
7659566063dSJacob Faibussowitsch     PetscCall(PetscSectionReset(partSection));
7669566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(partSection, 0, size));
7679566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(partSection, 0, cEnd - cStart));
7689566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(partSection));
7699566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cEnd - cStart, &points));
77077623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
7719566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)part), cEnd - cStart, points, PETSC_OWN_POINTER, partition));
7723ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
77377623264SMatthew G. Knepley   }
77477623264SMatthew G. Knepley   if (part->height == 0) {
775074d466cSStefano Zampini     PetscInt  numVertices = 0;
77677623264SMatthew G. Knepley     PetscInt *start       = NULL;
77777623264SMatthew G. Knepley     PetscInt *adjacency   = NULL;
7783fa7752dSToby Isaac     IS        globalNumbering;
77977623264SMatthew G. Knepley 
780074d466cSStefano Zampini     if (!part->noGraph || part->viewGraph) {
7819566063dSJacob Faibussowitsch       PetscCall(DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering));
78213911537SStefano Zampini     } else { /* only compute the number of owned local vertices */
783074d466cSStefano Zampini       const PetscInt *idxs;
784074d466cSStefano Zampini       PetscInt        p, pStart, pEnd;
785074d466cSStefano Zampini 
7869566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
7879566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering));
7889566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(globalNumbering, &idxs));
789074d466cSStefano Zampini       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
7909566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(globalNumbering, &idxs));
791074d466cSStefano Zampini     }
7923c41b853SStefano Zampini     if (part->usevwgt) {
7933c41b853SStefano Zampini       PetscSection    section = dm->localSection, clSection = NULL;
7943c41b853SStefano Zampini       IS              clPoints = NULL;
7953c41b853SStefano Zampini       const PetscInt *gid, *clIdx;
7963c41b853SStefano Zampini       PetscInt        v, p, pStart, pEnd;
7970358368aSMatthew G. Knepley 
7983c41b853SStefano 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) */
7993c41b853SStefano Zampini       /* We do this only if the local section has been set */
8003c41b853SStefano Zampini       if (section) {
8019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, NULL));
80248a46eb9SPierre Jolivet         if (!clSection) PetscCall(DMPlexCreateClosureIndex(dm, NULL));
8039566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, &clPoints));
8049566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(clPoints, &clIdx));
8053c41b853SStefano Zampini       }
8069566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
8079566063dSJacob Faibussowitsch       PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &vertSection));
8089566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetChart(vertSection, 0, numVertices));
8093c41b853SStefano Zampini       if (globalNumbering) {
8109566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(globalNumbering, &gid));
8113c41b853SStefano Zampini       } else gid = NULL;
8123c41b853SStefano Zampini       for (p = pStart, v = 0; p < pEnd; ++p) {
8133c41b853SStefano Zampini         PetscInt dof = 1;
8140358368aSMatthew G. Knepley 
8153c41b853SStefano Zampini         /* skip cells in the overlap */
8163c41b853SStefano Zampini         if (gid && gid[p - pStart] < 0) continue;
8173c41b853SStefano Zampini 
8183c41b853SStefano Zampini         if (section) {
8193c41b853SStefano Zampini           PetscInt cl, clSize, clOff;
8203c41b853SStefano Zampini 
8213c41b853SStefano Zampini           dof = 0;
8229566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(clSection, p, &clSize));
8239566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(clSection, p, &clOff));
8243c41b853SStefano Zampini           for (cl = 0; cl < clSize; cl += 2) {
8253c41b853SStefano Zampini             PetscInt clDof, clPoint = clIdx[clOff + cl]; /* odd indices are reserved for orientations */
8263c41b853SStefano Zampini 
8279566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetDof(section, clPoint, &clDof));
8283c41b853SStefano Zampini             dof += clDof;
8290358368aSMatthew G. Knepley           }
8300358368aSMatthew G. Knepley         }
83163a3b9bcSJacob Faibussowitsch         PetscCheck(dof, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of dofs for point %" PetscInt_FMT " in the local section should be positive", p);
8329566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(vertSection, v, dof));
8333c41b853SStefano Zampini         v++;
8343c41b853SStefano Zampini       }
83548a46eb9SPierre Jolivet       if (globalNumbering) PetscCall(ISRestoreIndices(globalNumbering, &gid));
83648a46eb9SPierre Jolivet       if (clPoints) PetscCall(ISRestoreIndices(clPoints, &clIdx));
8379566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetUp(vertSection));
8383c41b853SStefano Zampini     }
83921c92275SMatthew G. Knepley     if (part->useewgt) {
84021c92275SMatthew G. Knepley       const PetscInt numEdges = start[numVertices];
84121c92275SMatthew G. Knepley 
84221c92275SMatthew G. Knepley       PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &edgeSection));
84321c92275SMatthew G. Knepley       PetscCall(PetscSectionSetChart(edgeSection, 0, numEdges));
84421c92275SMatthew G. Knepley       for (PetscInt e = 0; e < start[numVertices]; ++e) PetscCall(PetscSectionSetDof(edgeSection, e, 1));
84521c92275SMatthew G. Knepley       for (PetscInt v = 0; v < numVertices; ++v) {
84621c92275SMatthew G. Knepley         DMPolytopeType ct;
84721c92275SMatthew G. Knepley 
84821c92275SMatthew G. Knepley         // Assume v is the cell number
84921c92275SMatthew G. Knepley         PetscCall(DMPlexGetCellType(dm, v, &ct));
85021c92275SMatthew G. Knepley         if (ct != DM_POLYTOPE_POINT_PRISM_TENSOR && ct != DM_POLYTOPE_SEG_PRISM_TENSOR && ct != DM_POLYTOPE_TRI_PRISM_TENSOR && ct != DM_POLYTOPE_QUAD_PRISM_TENSOR) continue;
85121c92275SMatthew G. Knepley 
85221c92275SMatthew G. Knepley         for (PetscInt e = start[v]; e < start[v + 1]; ++e) PetscCall(PetscSectionSetDof(edgeSection, e, 3));
85321c92275SMatthew G. Knepley       }
85421c92275SMatthew G. Knepley       PetscCall(PetscSectionSetUp(edgeSection));
85521c92275SMatthew G. Knepley     }
85621c92275SMatthew G. Knepley     PetscCall(PetscPartitionerPartition(part, size, numVertices, start, adjacency, vertSection, edgeSection, targetSection, partSection, partition));
8579566063dSJacob Faibussowitsch     PetscCall(PetscFree(start));
8589566063dSJacob Faibussowitsch     PetscCall(PetscFree(adjacency));
8593fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
8603fa7752dSToby Isaac       const PetscInt *globalNum;
8613fa7752dSToby Isaac       const PetscInt *partIdx;
8623fa7752dSToby Isaac       PetscInt       *map, cStart, cEnd;
8633fa7752dSToby Isaac       PetscInt       *adjusted, i, localSize, offset;
8643fa7752dSToby Isaac       IS              newPartition;
8653fa7752dSToby Isaac 
8669566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(*partition, &localSize));
8679566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localSize, &adjusted));
8689566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(globalNumbering, &globalNum));
8699566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(*partition, &partIdx));
8709566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localSize, &map));
8719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
8723fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
8733fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
8743fa7752dSToby Isaac       }
875ad540459SPierre Jolivet       for (i = 0; i < localSize; i++) adjusted[i] = map[partIdx[i]];
8769566063dSJacob Faibussowitsch       PetscCall(PetscFree(map));
8779566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(*partition, &partIdx));
8789566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(globalNumbering, &globalNum));
8799566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, localSize, adjusted, PETSC_OWN_POINTER, &newPartition));
8809566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&globalNumbering));
8819566063dSJacob Faibussowitsch       PetscCall(ISDestroy(partition));
8823fa7752dSToby Isaac       *partition = newPartition;
8833fa7752dSToby Isaac     }
88463a3b9bcSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %" PetscInt_FMT " for points to partition", part->height);
8859566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&vertSection));
88621c92275SMatthew G. Knepley   PetscCall(PetscSectionDestroy(&edgeSection));
8873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
88877623264SMatthew G. Knepley }
88977623264SMatthew G. Knepley 
8905680f57bSMatthew G. Knepley /*@
8915680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
8925680f57bSMatthew G. Knepley 
89320f4b53cSBarry Smith   Not Collective
8945680f57bSMatthew G. Knepley 
8955680f57bSMatthew G. Knepley   Input Parameter:
896a1cb98faSBarry Smith . dm - The `DM`
8975680f57bSMatthew G. Knepley 
8985680f57bSMatthew G. Knepley   Output Parameter:
899a1cb98faSBarry Smith . part - The `PetscPartitioner`
9005680f57bSMatthew G. Knepley 
9015680f57bSMatthew G. Knepley   Level: developer
9025680f57bSMatthew G. Knepley 
903a1cb98faSBarry Smith   Note:
904a1cb98faSBarry Smith   This gets a borrowed reference, so the user should not destroy this `PetscPartitioner`.
90598599a47SLawrence Mitchell 
9061cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscPartitioner`, `PetscSection`, `DMPlexDistribute()`, `DMPlexSetPartitioner()`, `PetscPartitionerDMPlexPartition()`, `PetscPartitionerCreate()`
9075680f57bSMatthew G. Knepley @*/
908d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
909d71ae5a4SJacob Faibussowitsch {
9105680f57bSMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
9115680f57bSMatthew G. Knepley 
9125680f57bSMatthew G. Knepley   PetscFunctionBegin;
9135680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9144f572ea9SToby Isaac   PetscAssertPointer(part, 2);
9155680f57bSMatthew G. Knepley   *part = mesh->partitioner;
9163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9175680f57bSMatthew G. Knepley }
9185680f57bSMatthew G. Knepley 
91971bb2955SLawrence Mitchell /*@
92071bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
92171bb2955SLawrence Mitchell 
92220f4b53cSBarry Smith   logically Collective
92371bb2955SLawrence Mitchell 
92471bb2955SLawrence Mitchell   Input Parameters:
925a1cb98faSBarry Smith + dm   - The `DM`
92671bb2955SLawrence Mitchell - part - The partitioner
92771bb2955SLawrence Mitchell 
92871bb2955SLawrence Mitchell   Level: developer
92971bb2955SLawrence Mitchell 
930a1cb98faSBarry Smith   Note:
931a1cb98faSBarry Smith   Any existing `PetscPartitioner` will be destroyed.
93271bb2955SLawrence Mitchell 
9331cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscPartitioner`,`DMPlexDistribute()`, `DMPlexGetPartitioner()`, `PetscPartitionerCreate()`
93471bb2955SLawrence Mitchell @*/
935d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
936d71ae5a4SJacob Faibussowitsch {
93771bb2955SLawrence Mitchell   DM_Plex *mesh = (DM_Plex *)dm->data;
93871bb2955SLawrence Mitchell 
93971bb2955SLawrence Mitchell   PetscFunctionBegin;
94071bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
94171bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
9429566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)part));
9439566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
94471bb2955SLawrence Mitchell   mesh->partitioner = part;
9453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
94671bb2955SLawrence Mitchell }
94771bb2955SLawrence Mitchell 
948d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point)
949d71ae5a4SJacob Faibussowitsch {
9508e330a33SStefano Zampini   const PetscInt *cone;
9518e330a33SStefano Zampini   PetscInt        coneSize, c;
9528e330a33SStefano Zampini   PetscBool       missing;
9538e330a33SStefano Zampini 
9548e330a33SStefano Zampini   PetscFunctionBeginHot;
9559566063dSJacob Faibussowitsch   PetscCall(PetscHSetIQueryAdd(ht, point, &missing));
9568e330a33SStefano Zampini   if (missing) {
9579566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, point, &cone));
9589566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
95948a46eb9SPierre Jolivet     for (c = 0; c < coneSize; c++) PetscCall(DMPlexAddClosure_Private(dm, ht, cone[c]));
9608e330a33SStefano Zampini   }
9613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9628e330a33SStefano Zampini }
9638e330a33SStefano Zampini 
964d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
965d71ae5a4SJacob Faibussowitsch {
966270bba0cSToby Isaac   PetscFunctionBegin;
9676a5a2ffdSToby Isaac   if (up) {
9686a5a2ffdSToby Isaac     PetscInt parent;
9696a5a2ffdSToby Isaac 
9709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
9716a5a2ffdSToby Isaac     if (parent != point) {
9726a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
9736a5a2ffdSToby Isaac 
9749566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
975270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
976270bba0cSToby Isaac         PetscInt cpoint = closure[2 * i];
977270bba0cSToby Isaac 
9789566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(ht, cpoint));
9799566063dSJacob Faibussowitsch         PetscCall(DMPlexAddClosure_Tree(dm, ht, cpoint, PETSC_TRUE, PETSC_FALSE));
980270bba0cSToby Isaac       }
9819566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, parent, PETSC_TRUE, &closureSize, &closure));
9826a5a2ffdSToby Isaac     }
9836a5a2ffdSToby Isaac   }
9846a5a2ffdSToby Isaac   if (down) {
9856a5a2ffdSToby Isaac     PetscInt        numChildren;
9866a5a2ffdSToby Isaac     const PetscInt *children;
9876a5a2ffdSToby Isaac 
9889566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
9896a5a2ffdSToby Isaac     if (numChildren) {
9906a5a2ffdSToby Isaac       PetscInt i;
9916a5a2ffdSToby Isaac 
9926a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
9936a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
9946a5a2ffdSToby Isaac 
9959566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(ht, cpoint));
9969566063dSJacob Faibussowitsch         PetscCall(DMPlexAddClosure_Tree(dm, ht, cpoint, PETSC_FALSE, PETSC_TRUE));
9976a5a2ffdSToby Isaac       }
9986a5a2ffdSToby Isaac     }
9996a5a2ffdSToby Isaac   }
10003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1001270bba0cSToby Isaac }
1002270bba0cSToby Isaac 
1003d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point)
1004d71ae5a4SJacob Faibussowitsch {
10058e330a33SStefano Zampini   PetscInt parent;
1006825f8a23SLisandro Dalcin 
10078e330a33SStefano Zampini   PetscFunctionBeginHot;
10089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTreeParent(dm, point, &parent, NULL));
10098e330a33SStefano Zampini   if (point != parent) {
10108e330a33SStefano Zampini     const PetscInt *cone;
10118e330a33SStefano Zampini     PetscInt        coneSize, c;
10128e330a33SStefano Zampini 
10139566063dSJacob Faibussowitsch     PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, parent));
10149566063dSJacob Faibussowitsch     PetscCall(DMPlexAddClosure_Private(dm, ht, parent));
10159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, parent, &cone));
10169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
10178e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
10188e330a33SStefano Zampini       const PetscInt cp = cone[c];
10198e330a33SStefano Zampini 
10209566063dSJacob Faibussowitsch       PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, cp));
10218e330a33SStefano Zampini     }
10228e330a33SStefano Zampini   }
10233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10248e330a33SStefano Zampini }
10258e330a33SStefano Zampini 
1026d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point)
1027d71ae5a4SJacob Faibussowitsch {
10288e330a33SStefano Zampini   PetscInt        i, numChildren;
10298e330a33SStefano Zampini   const PetscInt *children;
10308e330a33SStefano Zampini 
10318e330a33SStefano Zampini   PetscFunctionBeginHot;
10329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
103348a46eb9SPierre Jolivet   for (i = 0; i < numChildren; i++) PetscCall(PetscHSetIAdd(ht, children[i]));
10343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10358e330a33SStefano Zampini }
10368e330a33SStefano Zampini 
1037d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point)
1038d71ae5a4SJacob Faibussowitsch {
10398e330a33SStefano Zampini   const PetscInt *cone;
10408e330a33SStefano Zampini   PetscInt        coneSize, c;
10418e330a33SStefano Zampini 
10428e330a33SStefano Zampini   PetscFunctionBeginHot;
10439566063dSJacob Faibussowitsch   PetscCall(PetscHSetIAdd(ht, point));
10449566063dSJacob Faibussowitsch   PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, point));
10459566063dSJacob Faibussowitsch   PetscCall(DMPlexAddClosureTree_Down_Private(dm, ht, point));
10469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCone(dm, point, &cone));
10479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
104848a46eb9SPierre Jolivet   for (c = 0; c < coneSize; c++) PetscCall(DMPlexAddClosureTree_Private(dm, ht, cone[c]));
10493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10508e330a33SStefano Zampini }
10518e330a33SStefano Zampini 
1052d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS)
1053d71ae5a4SJacob Faibussowitsch {
1054825f8a23SLisandro Dalcin   DM_Plex        *mesh    = (DM_Plex *)dm->data;
10558e330a33SStefano Zampini   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
10568e330a33SStefano Zampini   PetscInt        nelems, *elems, off = 0, p;
105727104ee2SJacob Faibussowitsch   PetscHSetI      ht = NULL;
1058825f8a23SLisandro Dalcin 
1059825f8a23SLisandro Dalcin   PetscFunctionBegin;
10609566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
10619566063dSJacob Faibussowitsch   PetscCall(PetscHSetIResize(ht, numPoints * 16));
10628e330a33SStefano Zampini   if (!hasTree) {
106348a46eb9SPierre Jolivet     for (p = 0; p < numPoints; ++p) PetscCall(DMPlexAddClosure_Private(dm, ht, points[p]));
10648e330a33SStefano Zampini   } else {
10658e330a33SStefano Zampini #if 1
106648a46eb9SPierre Jolivet     for (p = 0; p < numPoints; ++p) PetscCall(DMPlexAddClosureTree_Private(dm, ht, points[p]));
10678e330a33SStefano Zampini #else
10688e330a33SStefano Zampini     PetscInt *closure = NULL, closureSize, c;
1069825f8a23SLisandro Dalcin     for (p = 0; p < numPoints; ++p) {
10709566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure));
1071825f8a23SLisandro Dalcin       for (c = 0; c < closureSize * 2; c += 2) {
10729566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(ht, closure[c]));
10739566063dSJacob Faibussowitsch         if (hasTree) PetscCall(DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE));
1074825f8a23SLisandro Dalcin       }
1075825f8a23SLisandro Dalcin     }
10769566063dSJacob Faibussowitsch     if (closure) PetscCall(DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure));
10778e330a33SStefano Zampini #endif
10788e330a33SStefano Zampini   }
10799566063dSJacob Faibussowitsch   PetscCall(PetscHSetIGetSize(ht, &nelems));
10809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nelems, &elems));
10819566063dSJacob Faibussowitsch   PetscCall(PetscHSetIGetElems(ht, &off, elems));
10829566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
10839566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(nelems, elems));
10849566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS));
10853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1086825f8a23SLisandro Dalcin }
1087825f8a23SLisandro Dalcin 
10885abbe4feSMichael Lange /*@
10895abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
10905abbe4feSMichael Lange 
10915abbe4feSMichael Lange   Input Parameters:
1092a1cb98faSBarry Smith + dm    - The `DM`
1093a1cb98faSBarry Smith - label - `DMLabel` assigning ranks to remote roots
10945abbe4feSMichael Lange 
10955abbe4feSMichael Lange   Level: developer
10965abbe4feSMichael Lange 
10971cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
10985abbe4feSMichael Lange @*/
1099d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
1100d71ae5a4SJacob Faibussowitsch {
1101825f8a23SLisandro Dalcin   IS              rankIS, pointIS, closureIS;
11025abbe4feSMichael Lange   const PetscInt *ranks, *points;
1103825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
11049ffc88e4SToby Isaac 
11059ffc88e4SToby Isaac   PetscFunctionBegin;
11069566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &rankIS));
11079566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
11089566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
11095abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
11105abbe4feSMichael Lange     const PetscInt rank = ranks[r];
11119566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &pointIS));
11129566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
11139566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
11149566063dSJacob Faibussowitsch     PetscCall(DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS));
11159566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
11169566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
11179566063dSJacob Faibussowitsch     PetscCall(DMLabelSetStratumIS(label, rank, closureIS));
11189566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&closureIS));
11199ffc88e4SToby Isaac   }
11209566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11219566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11239ffc88e4SToby Isaac }
11249ffc88e4SToby Isaac 
112524d039d7SMichael Lange /*@
112624d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
112724d039d7SMichael Lange 
112824d039d7SMichael Lange   Input Parameters:
1129a1cb98faSBarry Smith + dm    - The `DM`
1130a1cb98faSBarry Smith - label - `DMLabel` assigning ranks to remote roots
113124d039d7SMichael Lange 
113224d039d7SMichael Lange   Level: developer
113324d039d7SMichael Lange 
11341cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
113524d039d7SMichael Lange @*/
1136d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
1137d71ae5a4SJacob Faibussowitsch {
113824d039d7SMichael Lange   IS              rankIS, pointIS;
113924d039d7SMichael Lange   const PetscInt *ranks, *points;
114024d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
114124d039d7SMichael Lange   PetscInt       *adj = NULL;
114270034214SMatthew G. Knepley 
114370034214SMatthew G. Knepley   PetscFunctionBegin;
11449566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &rankIS));
11459566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
11469566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
114724d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
114824d039d7SMichael Lange     const PetscInt rank = ranks[r];
114970034214SMatthew G. Knepley 
11509566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, rank, &pointIS));
11519566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
11529566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
115370034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
115424d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
11559566063dSJacob Faibussowitsch       PetscCall(DMPlexGetAdjacency(dm, points[p], &adjSize, &adj));
11569566063dSJacob Faibussowitsch       for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(label, adj[a], rank));
115770034214SMatthew G. Knepley     }
11589566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
11599566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
116070034214SMatthew G. Knepley   }
11619566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
11629566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
11639566063dSJacob Faibussowitsch   PetscCall(PetscFree(adj));
11643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
116570034214SMatthew G. Knepley }
116670034214SMatthew G. Knepley 
1167be200f8dSMichael Lange /*@
1168a1cb98faSBarry Smith   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point `PetscSF`
1169be200f8dSMichael Lange 
1170be200f8dSMichael Lange   Input Parameters:
1171a1cb98faSBarry Smith + dm    - The `DM`
1172a1cb98faSBarry Smith - label - `DMLabel` assigning ranks to remote roots
1173be200f8dSMichael Lange 
1174be200f8dSMichael Lange   Level: developer
1175be200f8dSMichael Lange 
1176a1cb98faSBarry Smith   Note:
1177a1cb98faSBarry Smith   This is required when generating multi-level overlaps to capture
1178be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
1179be200f8dSMichael Lange 
11801cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1181be200f8dSMichael Lange @*/
1182d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
1183d71ae5a4SJacob Faibussowitsch {
1184be200f8dSMichael Lange   MPI_Comm        comm;
1185be200f8dSMichael Lange   PetscMPIInt     rank;
1186be200f8dSMichael Lange   PetscSF         sfPoint;
11875d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
1188be200f8dSMichael Lange   IS              rankIS, pointIS;
1189be200f8dSMichael Lange   const PetscInt *ranks;
1190be200f8dSMichael Lange   PetscInt        numRanks, r;
1191be200f8dSMichael Lange 
1192be200f8dSMichael Lange   PetscFunctionBegin;
11939566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
11949566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
11959566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
11965d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
11979566063dSJacob Faibussowitsch   PetscCall(DMLabelGather(label, sfPoint, &lblLeaves));
11989566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(lblLeaves, &rankIS));
11999566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
12009566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
12015d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
12025d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
12035d04f6ebSMichael Lange     if (remoteRank == rank) continue;
12049566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS));
12059566063dSJacob Faibussowitsch     PetscCall(DMLabelInsertIS(label, pointIS, remoteRank));
12069566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
12075d04f6ebSMichael Lange   }
12089566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
12099566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
12109566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lblLeaves));
1211be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
12129566063dSJacob Faibussowitsch   PetscCall(DMLabelDistribute(label, sfPoint, &lblRoots));
12139566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(lblRoots, &rankIS));
12149566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(rankIS, &numRanks));
12159566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(rankIS, &ranks));
1216be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
1217be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
1218be200f8dSMichael Lange     if (remoteRank == rank) continue;
12199566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS));
12209566063dSJacob Faibussowitsch     PetscCall(DMLabelInsertIS(label, pointIS, remoteRank));
12219566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
1222be200f8dSMichael Lange   }
12239566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(rankIS, &ranks));
12249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&rankIS));
12259566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&lblRoots));
12263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1227be200f8dSMichael Lange }
1228be200f8dSMichael Lange 
12291fd9873aSMichael Lange /*@
12301fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
12311fd9873aSMichael Lange 
12321fd9873aSMichael Lange   Input Parameters:
1233a1cb98faSBarry Smith + dm        - The `DM`
1234a1cb98faSBarry Smith . rootLabel - `DMLabel` assigning ranks to local roots
1235fe2efc57SMark - processSF - A star forest mapping into the local index on each remote rank
12361fd9873aSMichael Lange 
12371fd9873aSMichael Lange   Output Parameter:
1238a1cb98faSBarry Smith . leafLabel - `DMLabel` assigning ranks to remote roots
12391fd9873aSMichael Lange 
12401fd9873aSMichael Lange   Level: developer
12411fd9873aSMichael Lange 
1242a1cb98faSBarry Smith   Note:
1243a1cb98faSBarry Smith   The rootLabel defines a send pattern by mapping local points to remote target ranks. The
1244a1cb98faSBarry Smith   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
1245a1cb98faSBarry Smith 
12461cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
12471fd9873aSMichael Lange @*/
1248d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
1249d71ae5a4SJacob Faibussowitsch {
12501fd9873aSMichael Lange   MPI_Comm           comm;
1251874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
1252874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
12531fd9873aSMichael Lange   PetscSF            sfPoint;
1254874ddda9SLisandro Dalcin   PetscSection       rootSection;
12551fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
12561fd9873aSMichael Lange   const PetscSFNode *remote;
12571fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
12581fd9873aSMichael Lange   IS                 valueIS;
1259874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
12601fd9873aSMichael Lange 
12611fd9873aSMichael Lange   PetscFunctionBegin;
12629566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_PartLabelInvert, dm, 0, 0, 0));
12639566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
12649566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
12659566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
12669566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sfPoint));
12671fd9873aSMichael Lange 
12681fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
12699566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(comm, &rootSection));
12709566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(rootSection, 0, size));
12719566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(rootLabel, &valueIS));
12729566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(valueIS, &numNeighbors));
12739566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(valueIS, &neighbors));
12741fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
12759566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints));
12769566063dSJacob Faibussowitsch     PetscCall(PetscSectionAddDof(rootSection, neighbors[n], numPoints));
12771fd9873aSMichael Lange   }
12789566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(rootSection));
12799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(rootSection, &rootSize));
12809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rootSize, &rootPoints));
12819566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote));
12821fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
12831fd9873aSMichael Lange     IS              pointIS;
12841fd9873aSMichael Lange     const PetscInt *points;
12851fd9873aSMichael Lange 
12869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(rootSection, neighbors[n], &off));
12879566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS));
12889566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numPoints));
12899566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
12901fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
12919566063dSJacob Faibussowitsch       if (local) PetscCall(PetscFindInt(points[p], nleaves, local, &l));
1292ad540459SPierre Jolivet       else l = -1;
12939371c9d4SSatish Balay       if (l >= 0) {
12949371c9d4SSatish Balay         rootPoints[off + p] = remote[l];
12959371c9d4SSatish Balay       } else {
12969371c9d4SSatish Balay         rootPoints[off + p].index = points[p];
12979371c9d4SSatish Balay         rootPoints[off + p].rank  = rank;
12989371c9d4SSatish Balay       }
12991fd9873aSMichael Lange     }
13009566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
13019566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
13021fd9873aSMichael Lange   }
1303874ddda9SLisandro Dalcin 
1304874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
1305874ddda9SLisandro Dalcin   if (!processSF) {
1306874ddda9SLisandro Dalcin     PetscInt64   counter     = 0;
1307874ddda9SLisandro Dalcin     PetscBool    locOverflow = PETSC_FALSE;
1308874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
1309874ddda9SLisandro Dalcin 
13109566063dSJacob Faibussowitsch     PetscCall(PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls));
1311874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
13129566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(rootSection, neighbors[n], &dof));
13139566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(rootSection, neighbors[n], &off));
1314874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
13159371c9d4SSatish Balay       if (dof > PETSC_MPI_INT_MAX) {
13169371c9d4SSatish Balay         locOverflow = PETSC_TRUE;
13179371c9d4SSatish Balay         break;
13189371c9d4SSatish Balay       }
13199371c9d4SSatish Balay       if (off > PETSC_MPI_INT_MAX) {
13209371c9d4SSatish Balay         locOverflow = PETSC_TRUE;
13219371c9d4SSatish Balay         break;
13229371c9d4SSatish Balay       }
1323874ddda9SLisandro Dalcin #endif
1324874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt)dof;
1325874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt)off;
1326874ddda9SLisandro Dalcin     }
13279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm));
13289371c9d4SSatish Balay     for (r = 0; r < size; ++r) {
13299371c9d4SSatish Balay       rdispls[r] = (int)counter;
13309371c9d4SSatish Balay       counter += rcounts[r];
13319371c9d4SSatish Balay     }
1332874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
1333712fec58SPierre Jolivet     PetscCall(MPIU_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm));
1334874ddda9SLisandro Dalcin     if (!mpiOverflow) {
13359566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Using Alltoallv for mesh distribution\n"));
1336874ddda9SLisandro Dalcin       leafSize = (PetscInt)counter;
13379566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(leafSize, &leafPoints));
13389566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm));
1339874ddda9SLisandro Dalcin     }
13409566063dSJacob Faibussowitsch     PetscCall(PetscFree4(scounts, sdispls, rcounts, rdispls));
1341874ddda9SLisandro Dalcin   }
1342874ddda9SLisandro Dalcin 
1343874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
1344874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
1345874ddda9SLisandro Dalcin     PetscSF      procSF;
1346874ddda9SLisandro Dalcin     PetscSection leafSection;
1347874ddda9SLisandro Dalcin 
1348874ddda9SLisandro Dalcin     if (processSF) {
13499566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Using processSF for mesh distribution\n"));
13509566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)processSF));
1351874ddda9SLisandro Dalcin       procSF = processSF;
1352874ddda9SLisandro Dalcin     } else {
13539566063dSJacob Faibussowitsch       PetscCall(PetscInfo(dm, "Using processSF for mesh distribution (MPI overflow)\n"));
13549566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, &procSF));
13559566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphWithPattern(procSF, NULL, PETSCSF_PATTERN_ALLTOALL));
1356874ddda9SLisandro Dalcin     }
1357874ddda9SLisandro Dalcin 
13589566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection));
13599566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeData(dm, procSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void **)&leafPoints));
13609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(leafSection, &leafSize));
13619566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
13629566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&procSF));
1363874ddda9SLisandro Dalcin   }
1364874ddda9SLisandro Dalcin 
136548a46eb9SPierre Jolivet   for (p = 0; p < leafSize; p++) PetscCall(DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank));
1366874ddda9SLisandro Dalcin 
13679566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(valueIS, &neighbors));
13689566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&valueIS));
13699566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&rootSection));
13709566063dSJacob Faibussowitsch   PetscCall(PetscFree(rootPoints));
13719566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafPoints));
13729566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_PartLabelInvert, dm, 0, 0, 0));
13733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13741fd9873aSMichael Lange }
13751fd9873aSMichael Lange 
1376aa3148a8SMichael Lange /*@
1377aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
1378aa3148a8SMichael Lange 
1379aa3148a8SMichael Lange   Input Parameters:
1380a1cb98faSBarry Smith + dm        - The `DM`
13813ac0285dSStefano Zampini . label     - `DMLabel` assigning ranks to remote roots
13823ac0285dSStefano Zampini - sortRanks - Whether or not to sort the SF leaves by rank
1383aa3148a8SMichael Lange 
1384aa3148a8SMichael Lange   Output Parameter:
1385fe2efc57SMark . sf - The star forest communication context encapsulating the defined mapping
1386aa3148a8SMichael Lange 
1387aa3148a8SMichael Lange   Level: developer
1388aa3148a8SMichael Lange 
1389a1cb98faSBarry Smith   Note:
1390a1cb98faSBarry Smith   The incoming label is a receiver mapping of remote points to their parent rank.
1391a1cb98faSBarry Smith 
13921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabel`, `PetscSF`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1393aa3148a8SMichael Lange @*/
13943ac0285dSStefano Zampini PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscBool sortRanks, PetscSF *sf)
1395d71ae5a4SJacob Faibussowitsch {
13966e203dd9SStefano Zampini   PetscMPIInt     rank;
13976e203dd9SStefano Zampini   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
1398aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
13996e203dd9SStefano Zampini   IS              remoteRootIS, neighborsIS;
14006e203dd9SStefano Zampini   const PetscInt *remoteRoots, *neighbors;
14013ac0285dSStefano Zampini   PetscMPIInt     myRank;
1402aa3148a8SMichael Lange 
1403aa3148a8SMichael Lange   PetscFunctionBegin;
14049566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_PartLabelCreateSF, dm, 0, 0, 0));
14059566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
14069566063dSJacob Faibussowitsch   PetscCall(DMLabelGetValueIS(label, &neighborsIS));
14073ac0285dSStefano Zampini 
14083ac0285dSStefano Zampini   if (sortRanks) {
14096e203dd9SStefano Zampini     IS is;
14103ac0285dSStefano Zampini 
14119566063dSJacob Faibussowitsch     PetscCall(ISDuplicate(neighborsIS, &is));
14129566063dSJacob Faibussowitsch     PetscCall(ISSort(is));
14139566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&neighborsIS));
14146e203dd9SStefano Zampini     neighborsIS = is;
14156e203dd9SStefano Zampini   }
14163ac0285dSStefano Zampini   myRank = sortRanks ? -1 : rank;
14173ac0285dSStefano Zampini 
14189566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(neighborsIS, &nNeighbors));
14199566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(neighborsIS, &neighbors));
14206e203dd9SStefano Zampini   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
14219566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(label, neighbors[n], &numPoints));
1422aa3148a8SMichael Lange     numRemote += numPoints;
1423aa3148a8SMichael Lange   }
14249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRemote, &remotePoints));
14253ac0285dSStefano Zampini 
14263ac0285dSStefano Zampini   /* Put owned points first if not sorting the ranks */
14273ac0285dSStefano Zampini   if (!sortRanks) {
14289566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(label, rank, &numPoints));
142943f7d02bSMichael Lange     if (numPoints > 0) {
14309566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(label, rank, &remoteRootIS));
14319566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(remoteRootIS, &remoteRoots));
143243f7d02bSMichael Lange       for (p = 0; p < numPoints; p++) {
143343f7d02bSMichael Lange         remotePoints[idx].index = remoteRoots[p];
143443f7d02bSMichael Lange         remotePoints[idx].rank  = rank;
143543f7d02bSMichael Lange         idx++;
143643f7d02bSMichael Lange       }
14379566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(remoteRootIS, &remoteRoots));
14389566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&remoteRootIS));
143943f7d02bSMichael Lange     }
14403ac0285dSStefano Zampini   }
14413ac0285dSStefano Zampini 
144243f7d02bSMichael Lange   /* Now add remote points */
14436e203dd9SStefano Zampini   for (n = 0; n < nNeighbors; ++n) {
14446e203dd9SStefano Zampini     const PetscInt nn = neighbors[n];
14456e203dd9SStefano Zampini 
14469566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumSize(label, nn, &numPoints));
14473ac0285dSStefano Zampini     if (nn == myRank || numPoints <= 0) continue;
14489566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, nn, &remoteRootIS));
14499566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(remoteRootIS, &remoteRoots));
1450aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
1451aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
14526e203dd9SStefano Zampini       remotePoints[idx].rank  = nn;
1453aa3148a8SMichael Lange       idx++;
1454aa3148a8SMichael Lange     }
14559566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(remoteRootIS, &remoteRoots));
14569566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&remoteRootIS));
1457aa3148a8SMichael Lange   }
14583ac0285dSStefano Zampini 
14599566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), sf));
14609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
14619566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, pEnd - pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER));
14629566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(*sf));
14639566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&neighborsIS));
14649566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_PartLabelCreateSF, dm, 0, 0, 0));
14653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
146670034214SMatthew G. Knepley }
1467cb87ef4cSFlorian Wechsung 
1468abe9303eSLisandro Dalcin #if defined(PETSC_HAVE_PARMETIS)
1469abe9303eSLisandro Dalcin   #include <parmetis.h>
1470abe9303eSLisandro Dalcin #endif
1471abe9303eSLisandro Dalcin 
14726a3739e5SFlorian Wechsung /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
14736a3739e5SFlorian Wechsung  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
14746a3739e5SFlorian Wechsung  * them out in that case. */
14756a3739e5SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
1476a4e35b19SJacob Faibussowitsch /*
1477a1cb98faSBarry Smith   DMPlexRewriteSF - Rewrites the ownership of the `PetsSF` of a `DM` (in place).
14787f57c1a4SFlorian Wechsung 
14797f57c1a4SFlorian Wechsung   Input parameters:
1480a1cb98faSBarry Smith + dm                - The `DMPLEX` object.
1481fe2efc57SMark . n                 - The number of points.
1482a1cb98faSBarry Smith . pointsToRewrite   - The points in the `PetscSF` whose ownership will change.
1483fe2efc57SMark . targetOwners      - New owner for each element in pointsToRewrite.
1484a1cb98faSBarry Smith - degrees           - Degrees of the points in the `PetscSF` as obtained by `PetscSFComputeDegreeBegin()`/`PetscSFComputeDegreeEnd()`.
14857f57c1a4SFlorian Wechsung 
14867f57c1a4SFlorian Wechsung   Level: developer
14877f57c1a4SFlorian Wechsung 
14881cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabel`, `PetscSF`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1489a4e35b19SJacob Faibussowitsch */
1490d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
1491d71ae5a4SJacob Faibussowitsch {
14925f80ce2aSJacob Faibussowitsch   PetscInt           pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
14937f57c1a4SFlorian Wechsung   PetscInt          *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
14947f57c1a4SFlorian Wechsung   PetscSFNode       *leafLocationsNew;
14957f57c1a4SFlorian Wechsung   const PetscSFNode *iremote;
14967f57c1a4SFlorian Wechsung   const PetscInt    *ilocal;
14977f57c1a4SFlorian Wechsung   PetscBool         *isLeaf;
14987f57c1a4SFlorian Wechsung   PetscSF            sf;
14997f57c1a4SFlorian Wechsung   MPI_Comm           comm;
15005a30b08bSFlorian Wechsung   PetscMPIInt        rank, size;
15017f57c1a4SFlorian Wechsung 
15027f57c1a4SFlorian Wechsung   PetscFunctionBegin;
15039566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
15049566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
15059566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
15069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
15077f57c1a4SFlorian Wechsung 
15089566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
15099566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
15109566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isLeaf));
1511ad540459SPierre Jolivet   for (i = 0; i < pEnd - pStart; i++) isLeaf[i] = PETSC_FALSE;
1512ad540459SPierre Jolivet   for (i = 0; i < nleafs; i++) isLeaf[ilocal[i] - pStart] = PETSC_TRUE;
15137f57c1a4SFlorian Wechsung 
15149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart + 1, &cumSumDegrees));
15157f57c1a4SFlorian Wechsung   cumSumDegrees[0] = 0;
1516ad540459SPierre Jolivet   for (i = 1; i <= pEnd - pStart; i++) cumSumDegrees[i] = cumSumDegrees[i - 1] + degrees[i - 1];
15177f57c1a4SFlorian Wechsung   sumDegrees = cumSumDegrees[pEnd - pStart];
15187f57c1a4SFlorian Wechsung   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
15197f57c1a4SFlorian Wechsung 
15209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(sumDegrees, &locationsOfLeafs));
15219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &rankOnLeafs));
1522ad540459SPierre Jolivet   for (i = 0; i < pEnd - pStart; i++) rankOnLeafs[i] = rank;
15239566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
15249566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
15259566063dSJacob Faibussowitsch   PetscCall(PetscFree(rankOnLeafs));
15267f57c1a4SFlorian Wechsung 
15277f57c1a4SFlorian Wechsung   /* get the remote local points of my leaves */
15289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs));
15299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &points));
1530ad540459SPierre Jolivet   for (i = 0; i < pEnd - pStart; i++) points[i] = pStart + i;
15319566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
15329566063dSJacob Faibussowitsch   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
15339566063dSJacob Faibussowitsch   PetscCall(PetscFree(points));
15347f57c1a4SFlorian Wechsung   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
15359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &newOwners));
15369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &newNumbers));
15377f57c1a4SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
15387f57c1a4SFlorian Wechsung     newOwners[i]  = -1;
15397f57c1a4SFlorian Wechsung     newNumbers[i] = -1;
15407f57c1a4SFlorian Wechsung   }
15417f57c1a4SFlorian Wechsung   {
15427f57c1a4SFlorian Wechsung     PetscInt oldNumber, newNumber, oldOwner, newOwner;
15437f57c1a4SFlorian Wechsung     for (i = 0; i < n; i++) {
15447f57c1a4SFlorian Wechsung       oldNumber = pointsToRewrite[i];
15457f57c1a4SFlorian Wechsung       newNumber = -1;
15467f57c1a4SFlorian Wechsung       oldOwner  = rank;
15477f57c1a4SFlorian Wechsung       newOwner  = targetOwners[i];
15487f57c1a4SFlorian Wechsung       if (oldOwner == newOwner) {
15497f57c1a4SFlorian Wechsung         newNumber = oldNumber;
15507f57c1a4SFlorian Wechsung       } else {
15517f57c1a4SFlorian Wechsung         for (j = 0; j < degrees[oldNumber]; j++) {
15527f57c1a4SFlorian Wechsung           if (locationsOfLeafs[cumSumDegrees[oldNumber] + j] == newOwner) {
15537f57c1a4SFlorian Wechsung             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber] + j];
15547f57c1a4SFlorian Wechsung             break;
15557f57c1a4SFlorian Wechsung           }
15567f57c1a4SFlorian Wechsung         }
15577f57c1a4SFlorian Wechsung       }
15585f80ce2aSJacob Faibussowitsch       PetscCheck(newNumber != -1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
15597f57c1a4SFlorian Wechsung 
15607f57c1a4SFlorian Wechsung       newOwners[oldNumber]  = newOwner;
15617f57c1a4SFlorian Wechsung       newNumbers[oldNumber] = newNumber;
15627f57c1a4SFlorian Wechsung     }
15637f57c1a4SFlorian Wechsung   }
15649566063dSJacob Faibussowitsch   PetscCall(PetscFree(cumSumDegrees));
15659566063dSJacob Faibussowitsch   PetscCall(PetscFree(locationsOfLeafs));
15669566063dSJacob Faibussowitsch   PetscCall(PetscFree(remoteLocalPointOfLeafs));
15677f57c1a4SFlorian Wechsung 
15689566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners, MPI_REPLACE));
15699566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners, MPI_REPLACE));
15709566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers, MPI_REPLACE));
15719566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers, MPI_REPLACE));
15727f57c1a4SFlorian Wechsung 
15737f57c1a4SFlorian Wechsung   /* Now count how many leafs we have on each processor. */
15747f57c1a4SFlorian Wechsung   leafCounter = 0;
15757f57c1a4SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
15767f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
1577ad540459SPierre Jolivet       if (newOwners[i] != rank) leafCounter++;
15787f57c1a4SFlorian Wechsung     } else {
1579ad540459SPierre Jolivet       if (isLeaf[i]) leafCounter++;
15807f57c1a4SFlorian Wechsung     }
15817f57c1a4SFlorian Wechsung   }
15827f57c1a4SFlorian Wechsung 
15837f57c1a4SFlorian Wechsung   /* Now set up the new sf by creating the leaf arrays */
15849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(leafCounter, &leafsNew));
15859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(leafCounter, &leafLocationsNew));
15867f57c1a4SFlorian Wechsung 
15877f57c1a4SFlorian Wechsung   leafCounter = 0;
15887f57c1a4SFlorian Wechsung   counter     = 0;
15897f57c1a4SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
15907f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
15917f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
15927f57c1a4SFlorian Wechsung         leafsNew[leafCounter]               = i;
15937f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank  = newOwners[i];
15947f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = newNumbers[i];
15957f57c1a4SFlorian Wechsung         leafCounter++;
15967f57c1a4SFlorian Wechsung       }
15977f57c1a4SFlorian Wechsung     } else {
15987f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
15997f57c1a4SFlorian Wechsung         leafsNew[leafCounter]               = i;
16007f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank  = iremote[counter].rank;
16017f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = iremote[counter].index;
16027f57c1a4SFlorian Wechsung         leafCounter++;
16037f57c1a4SFlorian Wechsung       }
16047f57c1a4SFlorian Wechsung     }
1605ad540459SPierre Jolivet     if (isLeaf[i]) counter++;
16067f57c1a4SFlorian Wechsung   }
16077f57c1a4SFlorian Wechsung 
16089566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER));
16099566063dSJacob Faibussowitsch   PetscCall(PetscFree(newOwners));
16109566063dSJacob Faibussowitsch   PetscCall(PetscFree(newNumbers));
16119566063dSJacob Faibussowitsch   PetscCall(PetscFree(isLeaf));
16123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16137f57c1a4SFlorian Wechsung }
16147f57c1a4SFlorian Wechsung 
1615d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
1616d71ae5a4SJacob Faibussowitsch {
16175f80ce2aSJacob Faibussowitsch   PetscInt   *distribution, min, max, sum;
16185a30b08bSFlorian Wechsung   PetscMPIInt rank, size;
16195f80ce2aSJacob Faibussowitsch 
1620125d2a8fSFlorian Wechsung   PetscFunctionBegin;
16219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
16229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
16239566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(size, &distribution));
16245f80ce2aSJacob Faibussowitsch   for (PetscInt i = 0; i < n; i++) {
1625125d2a8fSFlorian Wechsung     if (part) distribution[part[i]] += vtxwgt[skip * i];
1626125d2a8fSFlorian Wechsung     else distribution[rank] += vtxwgt[skip * i];
1627125d2a8fSFlorian Wechsung   }
1628712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm));
1629125d2a8fSFlorian Wechsung   min = distribution[0];
1630125d2a8fSFlorian Wechsung   max = distribution[0];
1631125d2a8fSFlorian Wechsung   sum = distribution[0];
16325f80ce2aSJacob Faibussowitsch   for (PetscInt i = 1; i < size; i++) {
1633125d2a8fSFlorian Wechsung     if (distribution[i] < min) min = distribution[i];
1634125d2a8fSFlorian Wechsung     if (distribution[i] > max) max = distribution[i];
1635125d2a8fSFlorian Wechsung     sum += distribution[i];
1636125d2a8fSFlorian Wechsung   }
163763a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "Min: %" PetscInt_FMT ", Avg: %" PetscInt_FMT ", Max: %" PetscInt_FMT ", Balance: %f\n", min, sum / size, max, (max * 1. * size) / sum));
16389566063dSJacob Faibussowitsch   PetscCall(PetscFree(distribution));
16393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1640125d2a8fSFlorian Wechsung }
1641125d2a8fSFlorian Wechsung 
16426a3739e5SFlorian Wechsung #endif
16436a3739e5SFlorian Wechsung 
1644cb87ef4cSFlorian Wechsung /*@
1645a1cb98faSBarry Smith   DMPlexRebalanceSharedPoints - Redistribute points in the plex that are shared in order to achieve better balancing. This routine updates the `PointSF` of the `DM` inplace.
1646cb87ef4cSFlorian Wechsung 
164760225df5SJacob Faibussowitsch   Input Parameters:
1648a1cb98faSBarry Smith + dm              - The `DMPLEX` object.
1649fe2efc57SMark . entityDepth     - depth of the entity to balance (0 -> balance vertices).
1650fe2efc57SMark . useInitialGuess - whether to use the current distribution as initial guess (only used by ParMETIS).
1651fe2efc57SMark - parallel        - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.
1652cb87ef4cSFlorian Wechsung 
165360225df5SJacob Faibussowitsch   Output Parameter:
1654252a1336SBarry Smith . success - whether the graph partitioning was successful or not, optional. Unsuccessful simply means no change to the partitioning
1655252a1336SBarry Smith 
1656a1cb98faSBarry Smith   Options Database Keys:
1657252a1336SBarry Smith + -dm_plex_rebalance_shared_points_parmetis             - Use ParMetis instead of Metis for the partitioner
1658252a1336SBarry Smith . -dm_plex_rebalance_shared_points_use_initial_guess    - Use current partition to bootstrap ParMetis partition
1659252a1336SBarry 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_
1660252a1336SBarry Smith - -dm_plex_rebalance_shared_points_monitor              - Monitor the shared points rebalance process
1661252a1336SBarry Smith 
166290ea27d8SSatish Balay   Level: intermediate
1663a1cb98faSBarry Smith 
16641cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1665cb87ef4cSFlorian Wechsung @*/
1666d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
1667d71ae5a4SJacob Faibussowitsch {
166841525646SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
1669cb87ef4cSFlorian Wechsung   PetscSF            sf;
16700faf6628SFlorian Wechsung   PetscInt           ierr, i, j, idx, jdx;
16717f57c1a4SFlorian Wechsung   PetscInt           eBegin, eEnd, nroots, nleafs, pStart, pEnd;
16727f57c1a4SFlorian Wechsung   const PetscInt    *degrees, *ilocal;
16737f57c1a4SFlorian Wechsung   const PetscSFNode *iremote;
1674cb87ef4cSFlorian Wechsung   PetscBool         *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
1675cf818975SFlorian Wechsung   PetscInt           numExclusivelyOwned, numNonExclusivelyOwned;
1676cb87ef4cSFlorian Wechsung   PetscMPIInt        rank, size;
16777f57c1a4SFlorian Wechsung   PetscInt          *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
16785dc86ac1SFlorian Wechsung   const PetscInt    *cumSumVertices;
1679cb87ef4cSFlorian Wechsung   PetscInt           offset, counter;
1680252a1336SBarry Smith   PetscInt          *vtxwgt;
1681252a1336SBarry Smith   const PetscInt    *xadj, *adjncy;
1682cb87ef4cSFlorian Wechsung   PetscInt          *part, *options;
1683cf818975SFlorian Wechsung   PetscInt           nparts, wgtflag, numflag, ncon, edgecut;
1684cb87ef4cSFlorian Wechsung   real_t            *ubvec;
1685cb87ef4cSFlorian Wechsung   PetscInt          *firstVertices, *renumbering;
1686cb87ef4cSFlorian Wechsung   PetscInt           failed, failedGlobal;
1687cb87ef4cSFlorian Wechsung   MPI_Comm           comm;
1688252a1336SBarry Smith   Mat                A;
16897d197802SFlorian Wechsung   PetscViewer        viewer;
16907d197802SFlorian Wechsung   PetscViewerFormat  format;
16915a30b08bSFlorian Wechsung   PetscLayout        layout;
1692252a1336SBarry Smith   real_t            *tpwgts;
1693252a1336SBarry Smith   PetscMPIInt       *counts, *mpiCumSumVertices;
1694252a1336SBarry Smith   PetscInt          *pointsToRewrite;
1695252a1336SBarry Smith   PetscInt           numRows;
1696252a1336SBarry Smith   PetscBool          done, usematpartitioning = PETSC_FALSE;
1697252a1336SBarry Smith   IS                 ispart = NULL;
1698252a1336SBarry Smith   MatPartitioning    mp;
1699252a1336SBarry Smith   const char        *prefix;
170012617df9SFlorian Wechsung 
170112617df9SFlorian Wechsung   PetscFunctionBegin;
17029566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
17039566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
1704252a1336SBarry Smith   if (size == 1) {
1705252a1336SBarry Smith     if (success) *success = PETSC_TRUE;
17063ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1707252a1336SBarry Smith   }
1708252a1336SBarry Smith   if (success) *success = PETSC_FALSE;
1709252a1336SBarry Smith   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1710252a1336SBarry Smith 
1711252a1336SBarry Smith   parallel        = PETSC_FALSE;
1712252a1336SBarry Smith   useInitialGuess = PETSC_FALSE;
1713252a1336SBarry Smith   PetscObjectOptionsBegin((PetscObject)dm);
1714252a1336SBarry Smith   PetscCall(PetscOptionsName("-dm_plex_rebalance_shared_points_parmetis", "Use ParMetis instead of Metis for the partitioner", "DMPlexRebalanceSharedPoints", &parallel));
1715252a1336SBarry Smith   PetscCall(PetscOptionsBool("-dm_plex_rebalance_shared_points_use_initial_guess", "Use current partition to bootstrap ParMetis partition", "DMPlexRebalanceSharedPoints", useInitialGuess, &useInitialGuess, NULL));
1716252a1336SBarry Smith   PetscCall(PetscOptionsBool("-dm_plex_rebalance_shared_points_use_mat_partitioning", "Use the MatPartitioning object to partition", "DMPlexRebalanceSharedPoints", usematpartitioning, &usematpartitioning, NULL));
1717252a1336SBarry Smith   PetscCall(PetscOptionsViewer("-dm_plex_rebalance_shared_points_monitor", "Monitor the shared points rebalance process", "DMPlexRebalanceSharedPoints", &viewer, &format, NULL));
1718252a1336SBarry Smith   PetscOptionsEnd();
1719252a1336SBarry Smith   if (viewer) PetscCall(PetscViewerPushFormat(viewer, format));
17207f57c1a4SFlorian Wechsung 
17219566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
172241525646SFlorian Wechsung 
1723252a1336SBarry Smith   PetscCall(DMGetOptionsPrefix(dm, &prefix));
1724648c30bcSBarry Smith   PetscCall(PetscOptionsCreateViewer(comm, ((PetscObject)dm)->options, prefix, "-dm_rebalance_partition_view", &viewer, &format, NULL));
17251baa6e33SBarry Smith   if (viewer) PetscCall(PetscViewerPushFormat(viewer, format));
17267d197802SFlorian Wechsung 
1727ed44d270SFlorian Wechsung   /* Figure out all points in the plex that we are interested in balancing. */
17289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd));
17299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
17309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &toBalance));
1731ad540459SPierre Jolivet   for (i = 0; i < pEnd - pStart; i++) toBalance[i] = (PetscBool)(i >= eBegin && i < eEnd);
1732cb87ef4cSFlorian Wechsung 
1733cf818975SFlorian Wechsung   /* There are three types of points:
1734cf818975SFlorian Wechsung    * exclusivelyOwned: points that are owned by this process and only seen by this process
1735cf818975SFlorian Wechsung    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
1736cf818975SFlorian Wechsung    * leaf: a point that is seen by this process but owned by a different process
1737cf818975SFlorian Wechsung    */
17389566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
17399566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
17409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isLeaf));
17419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isNonExclusivelyOwned));
17429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &isExclusivelyOwned));
1743cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1744cb87ef4cSFlorian Wechsung     isNonExclusivelyOwned[i] = PETSC_FALSE;
1745cb87ef4cSFlorian Wechsung     isExclusivelyOwned[i]    = PETSC_FALSE;
1746cf818975SFlorian Wechsung     isLeaf[i]                = PETSC_FALSE;
1747cb87ef4cSFlorian Wechsung   }
1748cf818975SFlorian Wechsung 
1749252a1336SBarry Smith   /* mark all the leafs */
1750ad540459SPierre Jolivet   for (i = 0; i < nleafs; i++) isLeaf[ilocal[i] - pStart] = PETSC_TRUE;
1751cb87ef4cSFlorian Wechsung 
1752cf818975SFlorian Wechsung   /* for an owned point, we can figure out whether another processor sees it or
1753cf818975SFlorian Wechsung    * not by calculating its degree */
17549566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeBegin(sf, &degrees));
17559566063dSJacob Faibussowitsch   PetscCall(PetscSFComputeDegreeEnd(sf, &degrees));
1756cb87ef4cSFlorian Wechsung   numExclusivelyOwned    = 0;
1757cb87ef4cSFlorian Wechsung   numNonExclusivelyOwned = 0;
1758cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1759cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
17607f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1761cb87ef4cSFlorian Wechsung         isNonExclusivelyOwned[i] = PETSC_TRUE;
1762cb87ef4cSFlorian Wechsung         numNonExclusivelyOwned += 1;
1763cb87ef4cSFlorian Wechsung       } else {
1764cb87ef4cSFlorian Wechsung         if (!isLeaf[i]) {
1765cb87ef4cSFlorian Wechsung           isExclusivelyOwned[i] = PETSC_TRUE;
1766cb87ef4cSFlorian Wechsung           numExclusivelyOwned += 1;
1767cb87ef4cSFlorian Wechsung         }
1768cb87ef4cSFlorian Wechsung       }
1769cb87ef4cSFlorian Wechsung     }
1770cb87ef4cSFlorian Wechsung   }
1771cb87ef4cSFlorian Wechsung 
1772252a1336SBarry Smith   /* Build a graph with one vertex per core representing the
1773cf818975SFlorian Wechsung    * exclusively owned points and then one vertex per nonExclusively owned
1774cf818975SFlorian Wechsung    * point. */
17759566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &layout));
17769566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned));
17779566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
17789566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRanges(layout, &cumSumVertices));
17799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &globalNumbersOfLocalOwnedVertices));
1780ad540459SPierre Jolivet   for (i = 0; i < pEnd - pStart; i++) globalNumbersOfLocalOwnedVertices[i] = pStart - 1;
1781cb87ef4cSFlorian Wechsung   offset  = cumSumVertices[rank];
1782cb87ef4cSFlorian Wechsung   counter = 0;
1783cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
1784cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
17857f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
1786cb87ef4cSFlorian Wechsung         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
1787cb87ef4cSFlorian Wechsung         counter++;
1788cb87ef4cSFlorian Wechsung       }
1789cb87ef4cSFlorian Wechsung     }
1790cb87ef4cSFlorian Wechsung   }
1791cb87ef4cSFlorian Wechsung 
1792cb87ef4cSFlorian Wechsung   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
17939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &leafGlobalNumbers));
17949566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers, MPI_REPLACE));
17959566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers, MPI_REPLACE));
1796cb87ef4cSFlorian Wechsung 
1797252a1336SBarry Smith   /* Build the graph for partitioning */
1798252a1336SBarry Smith   numRows = 1 + numNonExclusivelyOwned;
1799252a1336SBarry Smith   PetscCall(PetscLogEventBegin(DMPLEX_RebalBuildGraph, dm, 0, 0, 0));
18009566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &A));
1801252a1336SBarry Smith   PetscCall(MatSetType(A, MATMPIADJ));
1802252a1336SBarry Smith   PetscCall(MatSetSizes(A, numRows, numRows, cumSumVertices[size], cumSumVertices[size]));
1803252a1336SBarry Smith   idx = cumSumVertices[rank];
18044baf1206SFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
18054baf1206SFlorian Wechsung     if (toBalance[i]) {
18060faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
18070faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
18080faf6628SFlorian Wechsung       else continue;
18099566063dSJacob Faibussowitsch       PetscCall(MatSetValue(A, idx, jdx, 1, INSERT_VALUES));
18109566063dSJacob Faibussowitsch       PetscCall(MatSetValue(A, jdx, idx, 1, INSERT_VALUES));
18110941debbSFlorian Wechsung     }
18120941debbSFlorian Wechsung   }
1813252a1336SBarry Smith   PetscCall(PetscFree(globalNumbersOfLocalOwnedVertices));
1814252a1336SBarry Smith   PetscCall(PetscFree(leafGlobalNumbers));
18159566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
18169566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1817252a1336SBarry Smith   PetscCall(PetscLogEventEnd(DMPLEX_RebalBuildGraph, dm, 0, 0, 0));
18184baf1206SFlorian Wechsung 
181941525646SFlorian Wechsung   nparts = size;
1820252a1336SBarry Smith   ncon   = 1;
18219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon * nparts, &tpwgts));
1822ad540459SPierre Jolivet   for (i = 0; i < ncon * nparts; i++) tpwgts[i] = 1. / (nparts);
18239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon, &ubvec));
18246f2c871aSStefano Zampini   for (i = 0; i < ncon; i++) ubvec[i] = 1.05;
18258c9a1619SFlorian Wechsung 
18269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ncon * (1 + numNonExclusivelyOwned), &vtxwgt));
1827252a1336SBarry Smith   if (ncon == 2) {
182841525646SFlorian Wechsung     vtxwgt[0] = numExclusivelyOwned;
1829252a1336SBarry Smith     vtxwgt[1] = 1;
183041525646SFlorian Wechsung     for (i = 0; i < numNonExclusivelyOwned; i++) {
183141525646SFlorian Wechsung       vtxwgt[ncon * (i + 1)]     = 1;
1832252a1336SBarry Smith       vtxwgt[ncon * (i + 1) + 1] = 0;
1833252a1336SBarry Smith     }
1834252a1336SBarry Smith   } else {
1835252a1336SBarry Smith     PetscInt base, ms;
1836a5a714f4SStefano Zampini     PetscCall(MPIU_Allreduce(&numExclusivelyOwned, &base, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
1837252a1336SBarry Smith     PetscCall(MatGetSize(A, &ms, NULL));
1838252a1336SBarry Smith     ms -= size;
1839252a1336SBarry Smith     base      = PetscMax(base, ms);
1840252a1336SBarry Smith     vtxwgt[0] = base + numExclusivelyOwned;
1841ad540459SPierre Jolivet     for (i = 0; i < numNonExclusivelyOwned; i++) vtxwgt[i + 1] = 1;
184241525646SFlorian Wechsung   }
18438c9a1619SFlorian Wechsung 
18445dc86ac1SFlorian Wechsung   if (viewer) {
184563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %" PetscInt_FMT " on interface of mesh distribution.\n", entityDepth));
184663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %" PetscInt_FMT "\n", cumSumVertices[size]));
184712617df9SFlorian Wechsung   }
1848252a1336SBarry Smith   /* TODO: Drop the parallel/sequential choice here and just use MatPartioner for much more flexibility */
1849252a1336SBarry Smith   if (usematpartitioning) {
1850252a1336SBarry Smith     const char *prefix;
1851252a1336SBarry Smith 
1852252a1336SBarry Smith     PetscCall(MatPartitioningCreate(PetscObjectComm((PetscObject)dm), &mp));
1853252a1336SBarry Smith     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mp, "dm_plex_rebalance_shared_points_"));
1854252a1336SBarry Smith     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
1855252a1336SBarry Smith     PetscCall(PetscObjectPrependOptionsPrefix((PetscObject)mp, prefix));
1856252a1336SBarry Smith     PetscCall(MatPartitioningSetAdjacency(mp, A));
1857252a1336SBarry Smith     PetscCall(MatPartitioningSetNumberVertexWeights(mp, ncon));
1858252a1336SBarry Smith     PetscCall(MatPartitioningSetVertexWeights(mp, vtxwgt));
1859252a1336SBarry Smith     PetscCall(MatPartitioningSetFromOptions(mp));
1860252a1336SBarry Smith     PetscCall(MatPartitioningApply(mp, &ispart));
1861252a1336SBarry Smith     PetscCall(ISGetIndices(ispart, (const PetscInt **)&part));
1862252a1336SBarry Smith   } else if (parallel) {
1863252a1336SBarry Smith     if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n"));
1864252a1336SBarry Smith     PetscCall(PetscMalloc1(cumSumVertices[rank + 1] - cumSumVertices[rank], &part));
1865252a1336SBarry Smith     PetscCall(MatGetRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, &xadj, &adjncy, &done));
1866252a1336SBarry Smith     PetscCheck(done, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Could not get adjacency information");
18679566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(4, &options));
18685a30b08bSFlorian Wechsung     options[0] = 1;
18695a30b08bSFlorian Wechsung     options[1] = 0; /* Verbosity */
1870252a1336SBarry Smith     if (viewer) options[1] = 1;
18715a30b08bSFlorian Wechsung     options[2] = 0;                    /* Seed */
18725a30b08bSFlorian Wechsung     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
1873252a1336SBarry Smith     wgtflag    = 2;
1874252a1336SBarry Smith     numflag    = 0;
18758c9a1619SFlorian Wechsung     if (useInitialGuess) {
1876252a1336SBarry Smith       PetscCall(PetscViewerASCIIPrintf(viewer, "THIS DOES NOT WORK! I don't know why. Using current distribution of points as initial guess.\n"));
1877252a1336SBarry Smith       for (i = 0; i < numRows; i++) part[i] = rank;
18789566063dSJacob Faibussowitsch       if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n"));
1879792fecdfSBarry Smith       PetscStackPushExternal("ParMETIS_V3_RefineKway");
1880252a1336SBarry Smith       PetscCall(PetscLogEventBegin(DMPLEX_RebalPartition, 0, 0, 0, 0));
1881252a1336SBarry 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);
1882252a1336SBarry Smith       PetscCall(PetscLogEventEnd(DMPLEX_RebalPartition, 0, 0, 0, 0));
18838c9a1619SFlorian Wechsung       PetscStackPop;
1884252a1336SBarry Smith       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
18858c9a1619SFlorian Wechsung     } else {
1886792fecdfSBarry Smith       PetscStackPushExternal("ParMETIS_V3_PartKway");
1887252a1336SBarry Smith       PetscCall(PetscLogEventBegin(DMPLEX_RebalPartition, 0, 0, 0, 0));
1888252a1336SBarry 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);
1889252a1336SBarry Smith       PetscCall(PetscLogEventEnd(DMPLEX_RebalPartition, 0, 0, 0, 0));
18908c9a1619SFlorian Wechsung       PetscStackPop;
18915f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
18928c9a1619SFlorian Wechsung     }
1893252a1336SBarry Smith     PetscCall(MatRestoreRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, &xadj, &adjncy, &done));
18949566063dSJacob Faibussowitsch     PetscCall(PetscFree(options));
189541525646SFlorian Wechsung   } else {
18969566063dSJacob Faibussowitsch     if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n"));
189741525646SFlorian Wechsung     Mat       As;
189841525646SFlorian Wechsung     PetscInt *partGlobal;
189941525646SFlorian Wechsung     PetscInt *numExclusivelyOwnedAll;
1900252a1336SBarry Smith 
1901252a1336SBarry Smith     PetscCall(PetscMalloc1(cumSumVertices[rank + 1] - cumSumVertices[rank], &part));
1902252a1336SBarry Smith     PetscCall(MatGetSize(A, &numRows, NULL));
1903252a1336SBarry Smith     PetscCall(PetscLogEventBegin(DMPLEX_RebalGatherGraph, dm, 0, 0, 0));
1904252a1336SBarry Smith     PetscCall(MatMPIAdjToSeqRankZero(A, &As));
1905252a1336SBarry Smith     PetscCall(PetscLogEventEnd(DMPLEX_RebalGatherGraph, dm, 0, 0, 0));
1906252a1336SBarry Smith 
19079566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &numExclusivelyOwnedAll));
190841525646SFlorian Wechsung     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
19099566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, numExclusivelyOwnedAll, 1, MPIU_INT, comm));
1910cb87ef4cSFlorian Wechsung 
19119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRows, &partGlobal));
1912252a1336SBarry Smith     PetscCall(PetscLogEventBegin(DMPLEX_RebalPartition, 0, 0, 0, 0));
1913dd400576SPatrick Sanan     if (rank == 0) {
1914252a1336SBarry Smith       PetscInt *vtxwgt_g, numRows_g;
191541525646SFlorian Wechsung 
1916252a1336SBarry Smith       PetscCall(MatGetRowIJ(As, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows_g, &xadj, &adjncy, &done));
1917252a1336SBarry Smith       PetscCall(PetscMalloc1(2 * numRows_g, &vtxwgt_g));
191841525646SFlorian Wechsung       for (i = 0; i < size; i++) {
191941525646SFlorian Wechsung         vtxwgt_g[ncon * cumSumVertices[i]] = numExclusivelyOwnedAll[i];
192041525646SFlorian Wechsung         if (ncon > 1) vtxwgt_g[ncon * cumSumVertices[i] + 1] = 1;
192141525646SFlorian Wechsung         for (j = cumSumVertices[i] + 1; j < cumSumVertices[i + 1]; j++) {
192241525646SFlorian Wechsung           vtxwgt_g[ncon * j] = 1;
192341525646SFlorian Wechsung           if (ncon > 1) vtxwgt_g[2 * j + 1] = 0;
192441525646SFlorian Wechsung         }
192541525646SFlorian Wechsung       }
1926252a1336SBarry Smith 
19279566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(64, &options));
192841525646SFlorian Wechsung       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
19295f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
193041525646SFlorian Wechsung       options[METIS_OPTION_CONTIG] = 1;
1931792fecdfSBarry Smith       PetscStackPushExternal("METIS_PartGraphKway");
1932252a1336SBarry Smith       ierr = METIS_PartGraphKway(&numRows_g, &ncon, (idx_t *)xadj, (idx_t *)adjncy, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
193341525646SFlorian Wechsung       PetscStackPop;
19345f80ce2aSJacob Faibussowitsch       PetscCheck(ierr == METIS_OK, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
19359566063dSJacob Faibussowitsch       PetscCall(PetscFree(options));
19369566063dSJacob Faibussowitsch       PetscCall(PetscFree(vtxwgt_g));
1937252a1336SBarry Smith       PetscCall(MatRestoreRowIJ(As, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows_g, &xadj, &adjncy, &done));
1938252a1336SBarry Smith       PetscCall(MatDestroy(&As));
193941525646SFlorian Wechsung     }
1940252a1336SBarry Smith     PetscCall(PetscBarrier((PetscObject)dm));
1941252a1336SBarry Smith     PetscCall(PetscLogEventEnd(DMPLEX_RebalPartition, 0, 0, 0, 0));
19429566063dSJacob Faibussowitsch     PetscCall(PetscFree(numExclusivelyOwnedAll));
194341525646SFlorian Wechsung 
1944252a1336SBarry Smith     /* scatter the partitioning information to ranks */
1945252a1336SBarry Smith     PetscCall(PetscLogEventBegin(DMPLEX_RebalScatterPart, 0, 0, 0, 0));
19469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &counts));
19479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size + 1, &mpiCumSumVertices));
1948f4f49eeaSPierre Jolivet     for (i = 0; i < size; i++) PetscCall(PetscMPIIntCast(cumSumVertices[i + 1] - cumSumVertices[i], &counts[i]));
1949f4f49eeaSPierre Jolivet     for (i = 0; i <= size; i++) PetscCall(PetscMPIIntCast(cumSumVertices[i], &mpiCumSumVertices[i]));
19509566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm));
19519566063dSJacob Faibussowitsch     PetscCall(PetscFree(counts));
19529566063dSJacob Faibussowitsch     PetscCall(PetscFree(mpiCumSumVertices));
19539566063dSJacob Faibussowitsch     PetscCall(PetscFree(partGlobal));
1954252a1336SBarry Smith     PetscCall(PetscLogEventEnd(DMPLEX_RebalScatterPart, 0, 0, 0, 0));
195541525646SFlorian Wechsung   }
19569566063dSJacob Faibussowitsch   PetscCall(PetscFree(ubvec));
19579566063dSJacob Faibussowitsch   PetscCall(PetscFree(tpwgts));
1958cb87ef4cSFlorian Wechsung 
1959252a1336SBarry Smith   /* Rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
1960252a1336SBarry Smith   PetscCall(PetscMalloc2(size, &firstVertices, size, &renumbering));
1961cb87ef4cSFlorian Wechsung   firstVertices[rank] = part[0];
19629566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, firstVertices, 1, MPIU_INT, comm));
1963ad540459SPierre Jolivet   for (i = 0; i < size; i++) renumbering[firstVertices[i]] = i;
1964ad540459SPierre Jolivet   for (i = 0; i < cumSumVertices[rank + 1] - cumSumVertices[rank]; i++) part[i] = renumbering[part[i]];
1965252a1336SBarry Smith   PetscCall(PetscFree2(firstVertices, renumbering));
1966252a1336SBarry Smith 
1967cb87ef4cSFlorian Wechsung   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
1968cb87ef4cSFlorian Wechsung   failed = (PetscInt)(part[0] != rank);
1969712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm));
1970cb87ef4cSFlorian Wechsung   if (failedGlobal > 0) {
1971aaa8cc7dSPierre Jolivet     PetscCheck(failedGlobal <= 0, comm, PETSC_ERR_LIB, "Metis/Parmetis returned a bad partition");
19729566063dSJacob Faibussowitsch     PetscCall(PetscFree(vtxwgt));
19739566063dSJacob Faibussowitsch     PetscCall(PetscFree(toBalance));
19749566063dSJacob Faibussowitsch     PetscCall(PetscFree(isLeaf));
19759566063dSJacob Faibussowitsch     PetscCall(PetscFree(isNonExclusivelyOwned));
19769566063dSJacob Faibussowitsch     PetscCall(PetscFree(isExclusivelyOwned));
1977252a1336SBarry Smith     if (usematpartitioning) {
1978252a1336SBarry Smith       PetscCall(ISRestoreIndices(ispart, (const PetscInt **)&part));
1979252a1336SBarry Smith       PetscCall(ISDestroy(&ispart));
1980252a1336SBarry Smith     } else PetscCall(PetscFree(part));
19817f57c1a4SFlorian Wechsung     if (viewer) {
19829566063dSJacob Faibussowitsch       PetscCall(PetscViewerPopFormat(viewer));
1983648c30bcSBarry Smith       PetscCall(PetscViewerDestroy(&viewer));
19847f57c1a4SFlorian Wechsung     }
19859566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
19863ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1987cb87ef4cSFlorian Wechsung   }
1988cb87ef4cSFlorian Wechsung 
1989252a1336SBarry Smith   /* Check how well we did distributing points*/
19905dc86ac1SFlorian Wechsung   if (viewer) {
1991252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "Number of owned entities of depth %" PetscInt_FMT ".\n", entityDepth));
1992252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "Initial      "));
19939566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank + 1] - cumSumVertices[rank], ncon, vtxwgt, NULL, viewer));
1994252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "Rebalanced   "));
19959566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank + 1] - cumSumVertices[rank], ncon, vtxwgt, part, viewer));
19967407ba93SFlorian Wechsung   }
19977407ba93SFlorian Wechsung 
1998252a1336SBarry Smith   /* Check that every vertex is owned by a process that it is actually connected to. */
1999252a1336SBarry Smith   PetscCall(MatGetRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
200041525646SFlorian Wechsung   for (i = 1; i <= numNonExclusivelyOwned; i++) {
2001cb87ef4cSFlorian Wechsung     PetscInt loc = 0;
20029566063dSJacob Faibussowitsch     PetscCall(PetscFindInt(cumSumVertices[part[i]], xadj[i + 1] - xadj[i], &adjncy[xadj[i]], &loc));
20037407ba93SFlorian Wechsung     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
2004ad540459SPierre Jolivet     if (loc < 0) part[i] = rank;
2005cb87ef4cSFlorian Wechsung   }
2006252a1336SBarry Smith   PetscCall(MatRestoreRowIJ(A, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &numRows, (const PetscInt **)&xadj, (const PetscInt **)&adjncy, &done));
2007252a1336SBarry Smith   PetscCall(MatDestroy(&A));
2008cb87ef4cSFlorian Wechsung 
2009252a1336SBarry Smith   /* See how significant the influences of the previous fixing up step was.*/
20105dc86ac1SFlorian Wechsung   if (viewer) {
2011252a1336SBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "After fix    "));
20129566063dSJacob Faibussowitsch     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank + 1] - cumSumVertices[rank], ncon, vtxwgt, part, viewer));
20137407ba93SFlorian Wechsung   }
2014252a1336SBarry Smith   if (!usematpartitioning) PetscCall(PetscFree(vtxwgt));
2015252a1336SBarry Smith   else PetscCall(MatPartitioningDestroy(&mp));
20167407ba93SFlorian Wechsung 
20179566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
2018cb87ef4cSFlorian Wechsung 
2019252a1336SBarry Smith   PetscCall(PetscLogEventBegin(DMPLEX_RebalRewriteSF, dm, 0, 0, 0));
2020252a1336SBarry Smith   /* Rewrite the SF to reflect the new ownership. */
20219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite));
20227f57c1a4SFlorian Wechsung   counter = 0;
2023cb87ef4cSFlorian Wechsung   for (i = 0; i < pEnd - pStart; i++) {
2024cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
2025cb87ef4cSFlorian Wechsung       if (isNonExclusivelyOwned[i]) {
20267f57c1a4SFlorian Wechsung         pointsToRewrite[counter] = i + pStart;
2027cb87ef4cSFlorian Wechsung         counter++;
2028cb87ef4cSFlorian Wechsung       }
2029cb87ef4cSFlorian Wechsung     }
2030cb87ef4cSFlorian Wechsung   }
20319566063dSJacob Faibussowitsch   PetscCall(DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part + 1, degrees));
20329566063dSJacob Faibussowitsch   PetscCall(PetscFree(pointsToRewrite));
2033252a1336SBarry Smith   PetscCall(PetscLogEventEnd(DMPLEX_RebalRewriteSF, dm, 0, 0, 0));
2034cb87ef4cSFlorian Wechsung 
20359566063dSJacob Faibussowitsch   PetscCall(PetscFree(toBalance));
20369566063dSJacob Faibussowitsch   PetscCall(PetscFree(isLeaf));
20379566063dSJacob Faibussowitsch   PetscCall(PetscFree(isNonExclusivelyOwned));
20389566063dSJacob Faibussowitsch   PetscCall(PetscFree(isExclusivelyOwned));
2039252a1336SBarry Smith   if (usematpartitioning) {
2040252a1336SBarry Smith     PetscCall(ISRestoreIndices(ispart, (const PetscInt **)&part));
2041252a1336SBarry Smith     PetscCall(ISDestroy(&ispart));
2042252a1336SBarry Smith   } else PetscCall(PetscFree(part));
20435dc86ac1SFlorian Wechsung   if (viewer) {
20449566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
20459566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
20467d197802SFlorian Wechsung   }
20478b879b41SFlorian Wechsung   if (success) *success = PETSC_TRUE;
20489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
20493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2050240408d3SFlorian Wechsung #else
20515f441e9bSFlorian Wechsung   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
205241525646SFlorian Wechsung #endif
2053cb87ef4cSFlorian Wechsung }
2054