xref: /petsc/src/dm/impls/plex/plexpartition.c (revision c3e4dd79e17d3f0a51a524340fae4661630fd09e)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/partitionerimpl.h>
3 #include <petsc/private/hashseti.h>
4 
5 const char * const DMPlexCSRAlgorithms[] = {"mat", "graph", "overlap", "DMPlexCSRAlgorithm", "DM_PLEX_CSR_",NULL};
6 
7 static inline PetscInt DMPlex_GlobalID(PetscInt point) { return point >= 0 ? point : -(point+1); }
8 
9 static PetscErrorCode DMPlexCreatePartitionerGraph_Overlap(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
10 {
11   DM              ovdm;
12   PetscSF         sfPoint;
13   IS              cellNumbering;
14   const PetscInt *cellNum;
15   PetscInt       *adj = NULL, *vOffsets = NULL, *vAdj = NULL;
16   PetscBool       useCone, useClosure;
17   PetscInt        dim, depth, overlap, cStart, cEnd, c, v;
18   PetscMPIInt     rank, size;
19 
20   PetscFunctionBegin;
21   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
22   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size));
23   PetscCall(DMGetDimension(dm, &dim));
24   PetscCall(DMPlexGetDepth(dm, &depth));
25   if (dim != depth) {
26     /* We do not handle the uninterpolated case here */
27     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
28     /* DMPlexCreateNeighborCSR does not make a numbering */
29     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
30     /* Different behavior for empty graphs */
31     if (!*numVertices) {
32       PetscCall(PetscMalloc1(1, offsets));
33       (*offsets)[0] = 0;
34     }
35     /* Broken in parallel */
36     if (rank) PetscCheck(!*numVertices,PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
37     PetscFunctionReturn(0);
38   }
39   /* Always use FVM adjacency to create partitioner graph */
40   PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
41   PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
42   /* Need overlap >= 1 */
43   PetscCall(DMPlexGetOverlap(dm, &overlap));
44   if (size && overlap < 1) {
45     PetscCall(DMPlexDistributeOverlap(dm, 1, NULL, &ovdm));
46   } else {
47     PetscCall(PetscObjectReference((PetscObject) dm));
48     ovdm = dm;
49   }
50   PetscCall(DMGetPointSF(ovdm, &sfPoint));
51   PetscCall(DMPlexGetHeightStratum(ovdm, height, &cStart, &cEnd));
52   PetscCall(DMPlexCreateNumbering_Plex(ovdm, cStart, cEnd, 0, NULL, sfPoint, &cellNumbering));
53   if (globalNumbering) {
54     PetscCall(PetscObjectReference((PetscObject) cellNumbering));
55     *globalNumbering = cellNumbering;
56   }
57   PetscCall(ISGetIndices(cellNumbering, &cellNum));
58   /* Determine sizes */
59   for (*numVertices = 0, c = cStart; c < cEnd; ++c) {
60     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
61     if (cellNum[c-cStart] < 0) continue;
62     (*numVertices)++;
63   }
64   PetscCall(PetscCalloc1(*numVertices+1, &vOffsets));
65   for (c = cStart, v = 0; c < cEnd; ++c) {
66     PetscInt adjSize = PETSC_DETERMINE, a, vsize = 0;
67 
68     if (cellNum[c-cStart] < 0) continue;
69     PetscCall(DMPlexGetAdjacency(ovdm, c, &adjSize, &adj));
70     for (a = 0; a < adjSize; ++a) {
71       const PetscInt point = adj[a];
72       if (point != c && cStart <= point && point < cEnd) ++vsize;
73     }
74     vOffsets[v+1] = vOffsets[v] + vsize;
75     ++v;
76   }
77   /* Determine adjacency */
78   PetscCall(PetscMalloc1(vOffsets[*numVertices], &vAdj));
79   for (c = cStart, v = 0; c < cEnd; ++c) {
80     PetscInt adjSize = PETSC_DETERMINE, a, off = vOffsets[v];
81 
82     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
83     if (cellNum[c-cStart] < 0) continue;
84     PetscCall(DMPlexGetAdjacency(ovdm, c, &adjSize, &adj));
85     for (a = 0; a < adjSize; ++a) {
86       const PetscInt point = adj[a];
87       if (point != c && cStart <= point && point < cEnd) {
88         vAdj[off++] = DMPlex_GlobalID(cellNum[point-cStart]);
89       }
90     }
91     PetscCheck(off == vOffsets[v+1],PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Offsets %" PetscInt_FMT " should be %" PetscInt_FMT, off, vOffsets[v+1]);
92     /* Sort adjacencies (not strictly necessary) */
93     PetscCall(PetscSortInt(off-vOffsets[v], &vAdj[vOffsets[v]]));
94     ++v;
95   }
96   PetscCall(PetscFree(adj));
97   PetscCall(ISRestoreIndices(cellNumbering, &cellNum));
98   PetscCall(ISDestroy(&cellNumbering));
99   PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
100   PetscCall(DMDestroy(&ovdm));
101   if (offsets)   {*offsets = vOffsets;}
102   else           PetscCall(PetscFree(vOffsets));
103   if (adjacency) {*adjacency = vAdj;}
104   else           PetscCall(PetscFree(vAdj));
105   PetscFunctionReturn(0);
106 }
107 
108 static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
109 {
110   PetscInt       dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
111   PetscInt      *adj = NULL, *vOffsets = NULL, *graph = NULL;
112   IS             cellNumbering;
113   const PetscInt *cellNum;
114   PetscBool      useCone, useClosure;
115   PetscSection   section;
116   PetscSegBuffer adjBuffer;
117   PetscSF        sfPoint;
118   PetscInt       *adjCells = NULL, *remoteCells = NULL;
119   const PetscInt *local;
120   PetscInt       nroots, nleaves, l;
121   PetscMPIInt    rank;
122 
123   PetscFunctionBegin;
124   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
125   PetscCall(DMGetDimension(dm, &dim));
126   PetscCall(DMPlexGetDepth(dm, &depth));
127   if (dim != depth) {
128     /* We do not handle the uninterpolated case here */
129     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
130     /* DMPlexCreateNeighborCSR does not make a numbering */
131     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
132     /* Different behavior for empty graphs */
133     if (!*numVertices) {
134       PetscCall(PetscMalloc1(1, offsets));
135       (*offsets)[0] = 0;
136     }
137     /* Broken in parallel */
138     if (rank) PetscCheck(!*numVertices,PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
139     PetscFunctionReturn(0);
140   }
141   PetscCall(DMGetPointSF(dm, &sfPoint));
142   PetscCall(DMPlexGetHeightStratum(dm, height, &pStart, &pEnd));
143   /* Build adjacency graph via a section/segbuffer */
144   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &section));
145   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
146   PetscCall(PetscSegBufferCreate(sizeof(PetscInt),1000,&adjBuffer));
147   /* Always use FVM adjacency to create partitioner graph */
148   PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
149   PetscCall(DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE));
150   PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, sfPoint, &cellNumbering));
151   if (globalNumbering) {
152     PetscCall(PetscObjectReference((PetscObject)cellNumbering));
153     *globalNumbering = cellNumbering;
154   }
155   PetscCall(ISGetIndices(cellNumbering, &cellNum));
156   /* For all boundary faces (including faces adjacent to a ghost cell), record the local cell in adjCells
157      Broadcast adjCells to remoteCells (to get cells from roots) and Reduce adjCells to remoteCells (to get cells from leaves)
158    */
159   PetscCall(PetscSFGetGraph(sfPoint, &nroots, &nleaves, &local, NULL));
160   if (nroots >= 0) {
161     PetscInt fStart, fEnd, f;
162 
163     PetscCall(PetscCalloc2(nroots, &adjCells, nroots, &remoteCells));
164     PetscCall(DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd));
165     for (l = 0; l < nroots; ++l) adjCells[l] = -3;
166     for (f = fStart; f < fEnd; ++f) {
167       const PetscInt *support;
168       PetscInt        supportSize;
169 
170       PetscCall(DMPlexGetSupport(dm, f, &support));
171       PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
172       if (supportSize == 1) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]-pStart]);
173       else if (supportSize == 2) {
174         PetscCall(PetscFindInt(support[0], nleaves, local, &p));
175         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1]-pStart]);
176         PetscCall(PetscFindInt(support[1], nleaves, local, &p));
177         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]-pStart]);
178       }
179       /* Handle non-conforming meshes */
180       if (supportSize > 2) {
181         PetscInt        numChildren, i;
182         const PetscInt *children;
183 
184         PetscCall(DMPlexGetTreeChildren(dm, f, &numChildren, &children));
185         for (i = 0; i < numChildren; ++i) {
186           const PetscInt child = children[i];
187           if (fStart <= child && child < fEnd) {
188             PetscCall(DMPlexGetSupport(dm, child, &support));
189             PetscCall(DMPlexGetSupportSize(dm, child, &supportSize));
190             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]-pStart]);
191             else if (supportSize == 2) {
192               PetscCall(PetscFindInt(support[0], nleaves, local, &p));
193               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1]-pStart]);
194               PetscCall(PetscFindInt(support[1], nleaves, local, &p));
195               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]-pStart]);
196             }
197           }
198         }
199       }
200     }
201     for (l = 0; l < nroots; ++l) remoteCells[l] = -1;
202     PetscCall(PetscSFBcastBegin(dm->sf, MPIU_INT, adjCells, remoteCells,MPI_REPLACE));
203     PetscCall(PetscSFBcastEnd(dm->sf, MPIU_INT, adjCells, remoteCells,MPI_REPLACE));
204     PetscCall(PetscSFReduceBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX));
205     PetscCall(PetscSFReduceEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX));
206   }
207   /* Combine local and global adjacencies */
208   for (*numVertices = 0, p = pStart; p < pEnd; p++) {
209     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
210     if (nroots > 0) {if (cellNum[p-pStart] < 0) continue;}
211     /* Add remote cells */
212     if (remoteCells) {
213       const PetscInt gp = DMPlex_GlobalID(cellNum[p-pStart]);
214       PetscInt       coneSize, numChildren, c, i;
215       const PetscInt *cone, *children;
216 
217       PetscCall(DMPlexGetCone(dm, p, &cone));
218       PetscCall(DMPlexGetConeSize(dm, p, &coneSize));
219       for (c = 0; c < coneSize; ++c) {
220         const PetscInt point = cone[c];
221         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
222           PetscInt *PETSC_RESTRICT pBuf;
223           PetscCall(PetscSectionAddDof(section, p, 1));
224           PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
225           *pBuf = remoteCells[point];
226         }
227         /* Handle non-conforming meshes */
228         PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
229         for (i = 0; i < numChildren; ++i) {
230           const PetscInt child = children[i];
231           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
232             PetscInt *PETSC_RESTRICT pBuf;
233             PetscCall(PetscSectionAddDof(section, p, 1));
234             PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
235             *pBuf = remoteCells[child];
236           }
237         }
238       }
239     }
240     /* Add local cells */
241     adjSize = PETSC_DETERMINE;
242     PetscCall(DMPlexGetAdjacency(dm, p, &adjSize, &adj));
243     for (a = 0; a < adjSize; ++a) {
244       const PetscInt point = adj[a];
245       if (point != p && pStart <= point && point < pEnd) {
246         PetscInt *PETSC_RESTRICT pBuf;
247         PetscCall(PetscSectionAddDof(section, p, 1));
248         PetscCall(PetscSegBufferGetInts(adjBuffer, 1, &pBuf));
249         *pBuf = DMPlex_GlobalID(cellNum[point-pStart]);
250       }
251     }
252     (*numVertices)++;
253   }
254   PetscCall(PetscFree(adj));
255   PetscCall(PetscFree2(adjCells, remoteCells));
256   PetscCall(DMSetBasicAdjacency(dm, useCone, useClosure));
257 
258   /* Derive CSR graph from section/segbuffer */
259   PetscCall(PetscSectionSetUp(section));
260   PetscCall(PetscSectionGetStorageSize(section, &size));
261   PetscCall(PetscMalloc1(*numVertices+1, &vOffsets));
262   for (idx = 0, p = pStart; p < pEnd; p++) {
263     if (nroots > 0) {if (cellNum[p-pStart] < 0) continue;}
264     PetscCall(PetscSectionGetOffset(section, p, &(vOffsets[idx++])));
265   }
266   vOffsets[*numVertices] = size;
267   PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &graph));
268 
269   if (nroots >= 0) {
270     /* Filter out duplicate edges using section/segbuffer */
271     PetscCall(PetscSectionReset(section));
272     PetscCall(PetscSectionSetChart(section, 0, *numVertices));
273     for (p = 0; p < *numVertices; p++) {
274       PetscInt start = vOffsets[p], end = vOffsets[p+1];
275       PetscInt numEdges = end-start, *PETSC_RESTRICT edges;
276       PetscCall(PetscSortRemoveDupsInt(&numEdges, &graph[start]));
277       PetscCall(PetscSectionSetDof(section, p, numEdges));
278       PetscCall(PetscSegBufferGetInts(adjBuffer, numEdges, &edges));
279       PetscCall(PetscArraycpy(edges, &graph[start], numEdges));
280     }
281     PetscCall(PetscFree(vOffsets));
282     PetscCall(PetscFree(graph));
283     /* Derive CSR graph from section/segbuffer */
284     PetscCall(PetscSectionSetUp(section));
285     PetscCall(PetscSectionGetStorageSize(section, &size));
286     PetscCall(PetscMalloc1(*numVertices+1, &vOffsets));
287     for (idx = 0, p = 0; p < *numVertices; p++) {
288       PetscCall(PetscSectionGetOffset(section, p, &(vOffsets[idx++])));
289     }
290     vOffsets[*numVertices] = size;
291     PetscCall(PetscSegBufferExtractAlloc(adjBuffer, &graph));
292   } else {
293     /* Sort adjacencies (not strictly necessary) */
294     for (p = 0; p < *numVertices; p++) {
295       PetscInt start = vOffsets[p], end = vOffsets[p+1];
296       PetscCall(PetscSortInt(end-start, &graph[start]));
297     }
298   }
299 
300   if (offsets) *offsets = vOffsets;
301   if (adjacency) *adjacency = graph;
302 
303   /* Cleanup */
304   PetscCall(PetscSegBufferDestroy(&adjBuffer));
305   PetscCall(PetscSectionDestroy(&section));
306   PetscCall(ISRestoreIndices(cellNumbering, &cellNum));
307   PetscCall(ISDestroy(&cellNumbering));
308   PetscFunctionReturn(0);
309 }
310 
311 static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
312 {
313   Mat            conn, CSR;
314   IS             fis, cis, cis_own;
315   PetscSF        sfPoint;
316   const PetscInt *rows, *cols, *ii, *jj;
317   PetscInt       *idxs,*idxs2;
318   PetscInt       dim, depth, floc, cloc, i, M, N, c, lm, m, cStart, cEnd, fStart, fEnd;
319   PetscMPIInt    rank;
320   PetscBool      flg;
321 
322   PetscFunctionBegin;
323   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
324   PetscCall(DMGetDimension(dm, &dim));
325   PetscCall(DMPlexGetDepth(dm, &depth));
326   if (dim != depth) {
327     /* We do not handle the uninterpolated case here */
328     PetscCall(DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency));
329     /* DMPlexCreateNeighborCSR does not make a numbering */
330     if (globalNumbering) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering));
331     /* Different behavior for empty graphs */
332     if (!*numVertices) {
333       PetscCall(PetscMalloc1(1, offsets));
334       (*offsets)[0] = 0;
335     }
336     /* Broken in parallel */
337     if (rank) PetscCheck(!*numVertices,PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
338     PetscFunctionReturn(0);
339   }
340   /* Interpolated and parallel case */
341 
342   /* numbering */
343   PetscCall(DMGetPointSF(dm, &sfPoint));
344   PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd));
345   PetscCall(DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd));
346   PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, &N, sfPoint, &cis));
347   PetscCall(DMPlexCreateNumbering_Plex(dm, fStart, fEnd, 0, &M, sfPoint, &fis));
348   if (globalNumbering) PetscCall(ISDuplicate(cis, globalNumbering));
349 
350   /* get positive global ids and local sizes for facets and cells */
351   PetscCall(ISGetLocalSize(fis, &m));
352   PetscCall(ISGetIndices(fis, &rows));
353   PetscCall(PetscMalloc1(m, &idxs));
354   for (i = 0, floc = 0; i < m; i++) {
355     const PetscInt p = rows[i];
356 
357     if (p < 0) {
358       idxs[i] = -(p+1);
359     } else {
360       idxs[i] = p;
361       floc   += 1;
362     }
363   }
364   PetscCall(ISRestoreIndices(fis, &rows));
365   PetscCall(ISDestroy(&fis));
366   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis));
367 
368   PetscCall(ISGetLocalSize(cis, &m));
369   PetscCall(ISGetIndices(cis, &cols));
370   PetscCall(PetscMalloc1(m, &idxs));
371   PetscCall(PetscMalloc1(m, &idxs2));
372   for (i = 0, cloc = 0; i < m; i++) {
373     const PetscInt p = cols[i];
374 
375     if (p < 0) {
376       idxs[i] = -(p+1);
377     } else {
378       idxs[i]       = p;
379       idxs2[cloc++] = p;
380     }
381   }
382   PetscCall(ISRestoreIndices(cis, &cols));
383   PetscCall(ISDestroy(&cis));
384   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis));
385   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own));
386 
387   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
388   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), &conn));
389   PetscCall(MatSetSizes(conn, floc, cloc, M, N));
390   PetscCall(MatSetType(conn, MATMPIAIJ));
391   PetscCall(DMPlexGetMaxSizes(dm, NULL, &lm));
392   PetscCallMPI(MPI_Allreduce(&lm, &m, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm)));
393   PetscCall(MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL));
394 
395   /* Assemble matrix */
396   PetscCall(ISGetIndices(fis, &rows));
397   PetscCall(ISGetIndices(cis, &cols));
398   for (c = cStart; c < cEnd; c++) {
399     const PetscInt *cone;
400     PetscInt        coneSize, row, col, f;
401 
402     col  = cols[c-cStart];
403     PetscCall(DMPlexGetCone(dm, c, &cone));
404     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
405     for (f = 0; f < coneSize; f++) {
406       const PetscScalar v = 1.0;
407       const PetscInt *children;
408       PetscInt        numChildren, ch;
409 
410       row  = rows[cone[f]-fStart];
411       PetscCall(MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES));
412 
413       /* non-conforming meshes */
414       PetscCall(DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children));
415       for (ch = 0; ch < numChildren; ch++) {
416         const PetscInt child = children[ch];
417 
418         if (child < fStart || child >= fEnd) continue;
419         row  = rows[child-fStart];
420         PetscCall(MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES));
421       }
422     }
423   }
424   PetscCall(ISRestoreIndices(fis, &rows));
425   PetscCall(ISRestoreIndices(cis, &cols));
426   PetscCall(ISDestroy(&fis));
427   PetscCall(ISDestroy(&cis));
428   PetscCall(MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY));
429   PetscCall(MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY));
430 
431   /* Get parallel CSR by doing conn^T * conn */
432   PetscCall(MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR));
433   PetscCall(MatDestroy(&conn));
434 
435   /* extract local part of the CSR */
436   PetscCall(MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn));
437   PetscCall(MatDestroy(&CSR));
438   PetscCall(MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
439   PetscCheck(flg,PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
440 
441   /* get back requested output */
442   if (numVertices) *numVertices = m;
443   if (offsets) {
444     PetscCall(PetscCalloc1(m+1, &idxs));
445     for (i = 1; i < m+1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
446     *offsets = idxs;
447   }
448   if (adjacency) {
449     PetscCall(PetscMalloc1(ii[m] - m, &idxs));
450     PetscCall(ISGetIndices(cis_own, &rows));
451     for (i = 0, c = 0; i < m; i++) {
452       PetscInt j, g = rows[i];
453 
454       for (j = ii[i]; j < ii[i+1]; j++) {
455         if (jj[j] == g) continue; /* again, self-connectivity */
456         idxs[c++] = jj[j];
457       }
458     }
459     PetscCheck(c == ii[m] - m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,c,ii[m]-m);
460     PetscCall(ISRestoreIndices(cis_own, &rows));
461     *adjacency = idxs;
462   }
463 
464   /* cleanup */
465   PetscCall(ISDestroy(&cis_own));
466   PetscCall(MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg));
467   PetscCheck(flg,PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
468   PetscCall(MatDestroy(&conn));
469   PetscFunctionReturn(0);
470 }
471 
472 /*@C
473   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
474 
475   Input Parameters:
476 + dm      - The mesh DM dm
477 - height  - Height of the strata from which to construct the graph
478 
479   Output Parameters:
480 + numVertices     - Number of vertices in the graph
481 . offsets         - Point offsets in the graph
482 . adjacency       - Point connectivity in the graph
483 - 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.
484 
485   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
486   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
487 
488   Options Database Keys:
489 . -dm_plex_csr_alg <mat,graph,overlap> - Choose the algorithm for computing the CSR graph
490 
491   Level: developer
492 
493 .seealso: `PetscPartitionerGetType()`, `PetscPartitionerCreate()`, `DMSetAdjacency()`
494 @*/
495 PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
496 {
497   DMPlexCSRAlgorithm alg = DM_PLEX_CSR_GRAPH;
498 
499   PetscFunctionBegin;
500   PetscCall(PetscOptionsGetEnum(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_csr_alg", DMPlexCSRAlgorithms, (PetscEnum *) &alg, NULL));
501   switch (alg) {
502     case DM_PLEX_CSR_MAT:
503       PetscCall(DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering));break;
504     case DM_PLEX_CSR_GRAPH:
505       PetscCall(DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering));break;
506     case DM_PLEX_CSR_OVERLAP:
507       PetscCall(DMPlexCreatePartitionerGraph_Overlap(dm, height, numVertices, offsets, adjacency, globalNumbering));break;
508   }
509   PetscFunctionReturn(0);
510 }
511 
512 /*@C
513   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
514 
515   Collective on DM
516 
517   Input Parameters:
518 + dm - The DMPlex
519 - cellHeight - The height of mesh points to treat as cells (default should be 0)
520 
521   Output Parameters:
522 + numVertices - The number of local vertices in the graph, or cells in the mesh.
523 . offsets     - The offset to the adjacency list for each cell
524 - adjacency   - The adjacency list for all cells
525 
526   Note: This is suitable for input to a mesh partitioner like ParMetis.
527 
528   Level: advanced
529 
530 .seealso: `DMPlexCreate()`
531 @*/
532 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
533 {
534   const PetscInt maxFaceCases = 30;
535   PetscInt       numFaceCases = 0;
536   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
537   PetscInt      *off, *adj;
538   PetscInt      *neighborCells = NULL;
539   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
540 
541   PetscFunctionBegin;
542   /* For parallel partitioning, I think you have to communicate supports */
543   PetscCall(DMGetDimension(dm, &dim));
544   cellDim = dim - cellHeight;
545   PetscCall(DMPlexGetDepth(dm, &depth));
546   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
547   if (cEnd - cStart == 0) {
548     if (numVertices) *numVertices = 0;
549     if (offsets)   *offsets   = NULL;
550     if (adjacency) *adjacency = NULL;
551     PetscFunctionReturn(0);
552   }
553   numCells  = cEnd - cStart;
554   faceDepth = depth - cellHeight;
555   if (dim == depth) {
556     PetscInt f, fStart, fEnd;
557 
558     PetscCall(PetscCalloc1(numCells+1, &off));
559     /* Count neighboring cells */
560     PetscCall(DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd));
561     for (f = fStart; f < fEnd; ++f) {
562       const PetscInt *support;
563       PetscInt        supportSize;
564       PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
565       PetscCall(DMPlexGetSupport(dm, f, &support));
566       if (supportSize == 2) {
567         PetscInt numChildren;
568 
569         PetscCall(DMPlexGetTreeChildren(dm,f,&numChildren,NULL));
570         if (!numChildren) {
571           ++off[support[0]-cStart+1];
572           ++off[support[1]-cStart+1];
573         }
574       }
575     }
576     /* Prefix sum */
577     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
578     if (adjacency) {
579       PetscInt *tmp;
580 
581       PetscCall(PetscMalloc1(off[numCells], &adj));
582       PetscCall(PetscMalloc1(numCells+1, &tmp));
583       PetscCall(PetscArraycpy(tmp, off, numCells+1));
584       /* Get neighboring cells */
585       for (f = fStart; f < fEnd; ++f) {
586         const PetscInt *support;
587         PetscInt        supportSize;
588         PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
589         PetscCall(DMPlexGetSupport(dm, f, &support));
590         if (supportSize == 2) {
591           PetscInt numChildren;
592 
593           PetscCall(DMPlexGetTreeChildren(dm,f,&numChildren,NULL));
594           if (!numChildren) {
595             adj[tmp[support[0]-cStart]++] = support[1];
596             adj[tmp[support[1]-cStart]++] = support[0];
597           }
598         }
599       }
600       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);
601       PetscCall(PetscFree(tmp));
602     }
603     if (numVertices) *numVertices = numCells;
604     if (offsets)   *offsets   = off;
605     if (adjacency) *adjacency = adj;
606     PetscFunctionReturn(0);
607   }
608   /* Setup face recognition */
609   if (faceDepth == 1) {
610     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 */
611 
612     for (c = cStart; c < cEnd; ++c) {
613       PetscInt corners;
614 
615       PetscCall(DMPlexGetConeSize(dm, c, &corners));
616       if (!cornersSeen[corners]) {
617         PetscInt nFV;
618 
619         PetscCheck(numFaceCases < maxFaceCases,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
620         cornersSeen[corners] = 1;
621 
622         PetscCall(DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV));
623 
624         numFaceVertices[numFaceCases++] = nFV;
625       }
626     }
627   }
628   PetscCall(PetscCalloc1(numCells+1, &off));
629   /* Count neighboring cells */
630   for (cell = cStart; cell < cEnd; ++cell) {
631     PetscInt numNeighbors = PETSC_DETERMINE, n;
632 
633     PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
634     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
635     for (n = 0; n < numNeighbors; ++n) {
636       PetscInt        cellPair[2];
637       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
638       PetscInt        meetSize = 0;
639       const PetscInt *meet    = NULL;
640 
641       cellPair[0] = cell; cellPair[1] = neighborCells[n];
642       if (cellPair[0] == cellPair[1]) continue;
643       if (!found) {
644         PetscCall(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
645         if (meetSize) {
646           PetscInt f;
647 
648           for (f = 0; f < numFaceCases; ++f) {
649             if (numFaceVertices[f] == meetSize) {
650               found = PETSC_TRUE;
651               break;
652             }
653           }
654         }
655         PetscCall(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
656       }
657       if (found) ++off[cell-cStart+1];
658     }
659   }
660   /* Prefix sum */
661   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
662 
663   if (adjacency) {
664     PetscCall(PetscMalloc1(off[numCells], &adj));
665     /* Get neighboring cells */
666     for (cell = cStart; cell < cEnd; ++cell) {
667       PetscInt numNeighbors = PETSC_DETERMINE, n;
668       PetscInt cellOffset   = 0;
669 
670       PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells));
671       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
672       for (n = 0; n < numNeighbors; ++n) {
673         PetscInt        cellPair[2];
674         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
675         PetscInt        meetSize = 0;
676         const PetscInt *meet    = NULL;
677 
678         cellPair[0] = cell; cellPair[1] = neighborCells[n];
679         if (cellPair[0] == cellPair[1]) continue;
680         if (!found) {
681           PetscCall(DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet));
682           if (meetSize) {
683             PetscInt f;
684 
685             for (f = 0; f < numFaceCases; ++f) {
686               if (numFaceVertices[f] == meetSize) {
687                 found = PETSC_TRUE;
688                 break;
689               }
690             }
691           }
692           PetscCall(DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet));
693         }
694         if (found) {
695           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
696           ++cellOffset;
697         }
698       }
699     }
700   }
701   PetscCall(PetscFree(neighborCells));
702   if (numVertices) *numVertices = numCells;
703   if (offsets)   *offsets   = off;
704   if (adjacency) *adjacency = adj;
705   PetscFunctionReturn(0);
706 }
707 
708 /*@
709   PetscPartitionerDMPlexPartition - Create a non-overlapping partition of the cells in the mesh
710 
711   Collective on PetscPartitioner
712 
713   Input Parameters:
714 + part    - The PetscPartitioner
715 . targetSection - The PetscSection describing the absolute weight of each partition (can be NULL)
716 - dm      - The mesh DM
717 
718   Output Parameters:
719 + partSection     - The PetscSection giving the division of points by partition
720 - partition       - The list of points by partition
721 
722   Notes:
723     If the DM has a local section associated, each point to be partitioned will be weighted by the total number of dofs identified
724     by the section in the transitive closure of the point.
725 
726   Level: developer
727 
728 .seealso `DMPlexDistribute()`, `PetscPartitionerCreate()`, `PetscSectionCreate()`, `PetscSectionSetChart()`, `PetscPartitionerPartition()`
729 @*/
730 PetscErrorCode PetscPartitionerDMPlexPartition(PetscPartitioner part, DM dm, PetscSection targetSection, PetscSection partSection, IS *partition)
731 {
732   PetscMPIInt    size;
733   PetscBool      isplex;
734   PetscSection   vertSection = NULL;
735 
736   PetscFunctionBegin;
737   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
738   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
739   if (targetSection) PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 3);
740   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
741   PetscValidPointer(partition, 5);
742   PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isplex));
743   PetscCheck(isplex,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Not for type %s",((PetscObject)dm)->type_name);
744   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject) part), &size));
745   if (size == 1) {
746     PetscInt *points;
747     PetscInt  cStart, cEnd, c;
748 
749     PetscCall(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
750     PetscCall(PetscSectionReset(partSection));
751     PetscCall(PetscSectionSetChart(partSection, 0, size));
752     PetscCall(PetscSectionSetDof(partSection, 0, cEnd-cStart));
753     PetscCall(PetscSectionSetUp(partSection));
754     PetscCall(PetscMalloc1(cEnd-cStart, &points));
755     for (c = cStart; c < cEnd; ++c) points[c] = c;
756     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition));
757     PetscFunctionReturn(0);
758   }
759   if (part->height == 0) {
760     PetscInt numVertices = 0;
761     PetscInt *start     = NULL;
762     PetscInt *adjacency = NULL;
763     IS       globalNumbering;
764 
765     if (!part->noGraph || part->viewGraph) {
766       PetscCall(DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering));
767     } else { /* only compute the number of owned local vertices */
768       const PetscInt *idxs;
769       PetscInt       p, pStart, pEnd;
770 
771       PetscCall(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
772       PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering));
773       PetscCall(ISGetIndices(globalNumbering, &idxs));
774       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
775       PetscCall(ISRestoreIndices(globalNumbering, &idxs));
776     }
777     if (part->usevwgt) {
778       PetscSection   section = dm->localSection, clSection = NULL;
779       IS             clPoints = NULL;
780       const PetscInt *gid,*clIdx;
781       PetscInt       v, p, pStart, pEnd;
782 
783       /* 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) */
784       /* We do this only if the local section has been set */
785       if (section) {
786         PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, NULL));
787         if (!clSection) {
788           PetscCall(DMPlexCreateClosureIndex(dm,NULL));
789         }
790         PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, &clPoints));
791         PetscCall(ISGetIndices(clPoints,&clIdx));
792       }
793       PetscCall(DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd));
794       PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &vertSection));
795       PetscCall(PetscSectionSetChart(vertSection, 0, numVertices));
796       if (globalNumbering) {
797         PetscCall(ISGetIndices(globalNumbering,&gid));
798       } else gid = NULL;
799       for (p = pStart, v = 0; p < pEnd; ++p) {
800         PetscInt dof = 1;
801 
802         /* skip cells in the overlap */
803         if (gid && gid[p-pStart] < 0) continue;
804 
805         if (section) {
806           PetscInt cl, clSize, clOff;
807 
808           dof  = 0;
809           PetscCall(PetscSectionGetDof(clSection, p, &clSize));
810           PetscCall(PetscSectionGetOffset(clSection, p, &clOff));
811           for (cl = 0; cl < clSize; cl+=2) {
812             PetscInt clDof, clPoint = clIdx[clOff + cl]; /* odd indices are reserved for orientations */
813 
814             PetscCall(PetscSectionGetDof(section, clPoint, &clDof));
815             dof += clDof;
816           }
817         }
818         PetscCheck(dof,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of dofs for point %" PetscInt_FMT " in the local section should be positive",p);
819         PetscCall(PetscSectionSetDof(vertSection, v, dof));
820         v++;
821       }
822       if (globalNumbering) {
823         PetscCall(ISRestoreIndices(globalNumbering,&gid));
824       }
825       if (clPoints) {
826         PetscCall(ISRestoreIndices(clPoints,&clIdx));
827       }
828       PetscCall(PetscSectionSetUp(vertSection));
829     }
830     PetscCall(PetscPartitionerPartition(part, size, numVertices, start, adjacency, vertSection, targetSection, partSection, partition));
831     PetscCall(PetscFree(start));
832     PetscCall(PetscFree(adjacency));
833     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
834       const PetscInt *globalNum;
835       const PetscInt *partIdx;
836       PetscInt       *map, cStart, cEnd;
837       PetscInt       *adjusted, i, localSize, offset;
838       IS             newPartition;
839 
840       PetscCall(ISGetLocalSize(*partition,&localSize));
841       PetscCall(PetscMalloc1(localSize,&adjusted));
842       PetscCall(ISGetIndices(globalNumbering,&globalNum));
843       PetscCall(ISGetIndices(*partition,&partIdx));
844       PetscCall(PetscMalloc1(localSize,&map));
845       PetscCall(DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd));
846       for (i = cStart, offset = 0; i < cEnd; i++) {
847         if (globalNum[i - cStart] >= 0) map[offset++] = i;
848       }
849       for (i = 0; i < localSize; i++) {
850         adjusted[i] = map[partIdx[i]];
851       }
852       PetscCall(PetscFree(map));
853       PetscCall(ISRestoreIndices(*partition,&partIdx));
854       PetscCall(ISRestoreIndices(globalNumbering,&globalNum));
855       PetscCall(ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition));
856       PetscCall(ISDestroy(&globalNumbering));
857       PetscCall(ISDestroy(partition));
858       *partition = newPartition;
859     }
860   } else SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %" PetscInt_FMT " for points to partition", part->height);
861   PetscCall(PetscSectionDestroy(&vertSection));
862   PetscFunctionReturn(0);
863 }
864 
865 /*@
866   DMPlexGetPartitioner - Get the mesh partitioner
867 
868   Not collective
869 
870   Input Parameter:
871 . dm - The DM
872 
873   Output Parameter:
874 . part - The PetscPartitioner
875 
876   Level: developer
877 
878   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
879 
880 .seealso `DMPlexDistribute()`, `DMPlexSetPartitioner()`, `PetscPartitionerDMPlexPartition()`, `PetscPartitionerCreate()`
881 @*/
882 PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
883 {
884   DM_Plex       *mesh = (DM_Plex *) dm->data;
885 
886   PetscFunctionBegin;
887   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
888   PetscValidPointer(part, 2);
889   *part = mesh->partitioner;
890   PetscFunctionReturn(0);
891 }
892 
893 /*@
894   DMPlexSetPartitioner - Set the mesh partitioner
895 
896   logically collective on DM
897 
898   Input Parameters:
899 + dm - The DM
900 - part - The partitioner
901 
902   Level: developer
903 
904   Note: Any existing PetscPartitioner will be destroyed.
905 
906 .seealso `DMPlexDistribute()`, `DMPlexGetPartitioner()`, `PetscPartitionerCreate()`
907 @*/
908 PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
909 {
910   DM_Plex       *mesh = (DM_Plex *) dm->data;
911 
912   PetscFunctionBegin;
913   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
914   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
915   PetscCall(PetscObjectReference((PetscObject)part));
916   PetscCall(PetscPartitionerDestroy(&mesh->partitioner));
917   mesh->partitioner = part;
918   PetscFunctionReturn(0);
919 }
920 
921 static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point)
922 {
923   const PetscInt *cone;
924   PetscInt       coneSize, c;
925   PetscBool      missing;
926 
927   PetscFunctionBeginHot;
928   PetscCall(PetscHSetIQueryAdd(ht, point, &missing));
929   if (missing) {
930     PetscCall(DMPlexGetCone(dm, point, &cone));
931     PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
932     for (c = 0; c < coneSize; c++) {
933       PetscCall(DMPlexAddClosure_Private(dm, ht, cone[c]));
934     }
935   }
936   PetscFunctionReturn(0);
937 }
938 
939 PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
940 {
941   PetscFunctionBegin;
942   if (up) {
943     PetscInt parent;
944 
945     PetscCall(DMPlexGetTreeParent(dm,point,&parent,NULL));
946     if (parent != point) {
947       PetscInt closureSize, *closure = NULL, i;
948 
949       PetscCall(DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
950       for (i = 0; i < closureSize; i++) {
951         PetscInt cpoint = closure[2*i];
952 
953         PetscCall(PetscHSetIAdd(ht, cpoint));
954         PetscCall(DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE));
955       }
956       PetscCall(DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure));
957     }
958   }
959   if (down) {
960     PetscInt numChildren;
961     const PetscInt *children;
962 
963     PetscCall(DMPlexGetTreeChildren(dm,point,&numChildren,&children));
964     if (numChildren) {
965       PetscInt i;
966 
967       for (i = 0; i < numChildren; i++) {
968         PetscInt cpoint = children[i];
969 
970         PetscCall(PetscHSetIAdd(ht, cpoint));
971         PetscCall(DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE));
972       }
973     }
974   }
975   PetscFunctionReturn(0);
976 }
977 
978 static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point)
979 {
980   PetscInt       parent;
981 
982   PetscFunctionBeginHot;
983   PetscCall(DMPlexGetTreeParent(dm, point, &parent,NULL));
984   if (point != parent) {
985     const PetscInt *cone;
986     PetscInt       coneSize, c;
987 
988     PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, parent));
989     PetscCall(DMPlexAddClosure_Private(dm, ht, parent));
990     PetscCall(DMPlexGetCone(dm, parent, &cone));
991     PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
992     for (c = 0; c < coneSize; c++) {
993       const PetscInt cp = cone[c];
994 
995       PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, cp));
996     }
997   }
998   PetscFunctionReturn(0);
999 }
1000 
1001 static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point)
1002 {
1003   PetscInt       i, numChildren;
1004   const PetscInt *children;
1005 
1006   PetscFunctionBeginHot;
1007   PetscCall(DMPlexGetTreeChildren(dm, point, &numChildren, &children));
1008   for (i = 0; i < numChildren; i++) {
1009     PetscCall(PetscHSetIAdd(ht, children[i]));
1010   }
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point)
1015 {
1016   const PetscInt *cone;
1017   PetscInt       coneSize, c;
1018 
1019   PetscFunctionBeginHot;
1020   PetscCall(PetscHSetIAdd(ht, point));
1021   PetscCall(DMPlexAddClosureTree_Up_Private(dm, ht, point));
1022   PetscCall(DMPlexAddClosureTree_Down_Private(dm, ht, point));
1023   PetscCall(DMPlexGetCone(dm, point, &cone));
1024   PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
1025   for (c = 0; c < coneSize; c++) {
1026     PetscCall(DMPlexAddClosureTree_Private(dm, ht, cone[c]));
1027   }
1028   PetscFunctionReturn(0);
1029 }
1030 
1031 PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS)
1032 {
1033   DM_Plex         *mesh = (DM_Plex *)dm->data;
1034   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
1035   PetscInt        nelems, *elems, off = 0, p;
1036   PetscHSetI      ht = NULL;
1037 
1038   PetscFunctionBegin;
1039   PetscCall(PetscHSetICreate(&ht));
1040   PetscCall(PetscHSetIResize(ht, numPoints*16));
1041   if (!hasTree) {
1042     for (p = 0; p < numPoints; ++p) {
1043       PetscCall(DMPlexAddClosure_Private(dm, ht, points[p]));
1044     }
1045   } else {
1046 #if 1
1047     for (p = 0; p < numPoints; ++p) {
1048       PetscCall(DMPlexAddClosureTree_Private(dm, ht, points[p]));
1049     }
1050 #else
1051     PetscInt  *closure = NULL, closureSize, c;
1052     for (p = 0; p < numPoints; ++p) {
1053       PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure));
1054       for (c = 0; c < closureSize*2; c += 2) {
1055         PetscCall(PetscHSetIAdd(ht, closure[c]));
1056         if (hasTree) PetscCall(DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE));
1057       }
1058     }
1059     if (closure) PetscCall(DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure));
1060 #endif
1061   }
1062   PetscCall(PetscHSetIGetSize(ht, &nelems));
1063   PetscCall(PetscMalloc1(nelems, &elems));
1064   PetscCall(PetscHSetIGetElems(ht, &off, elems));
1065   PetscCall(PetscHSetIDestroy(&ht));
1066   PetscCall(PetscSortInt(nelems, elems));
1067   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS));
1068   PetscFunctionReturn(0);
1069 }
1070 
1071 /*@
1072   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
1073 
1074   Input Parameters:
1075 + dm     - The DM
1076 - label  - DMLabel assigning ranks to remote roots
1077 
1078   Level: developer
1079 
1080 .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1081 @*/
1082 PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
1083 {
1084   IS              rankIS,   pointIS, closureIS;
1085   const PetscInt *ranks,   *points;
1086   PetscInt        numRanks, numPoints, r;
1087 
1088   PetscFunctionBegin;
1089   PetscCall(DMLabelGetValueIS(label, &rankIS));
1090   PetscCall(ISGetLocalSize(rankIS, &numRanks));
1091   PetscCall(ISGetIndices(rankIS, &ranks));
1092   for (r = 0; r < numRanks; ++r) {
1093     const PetscInt rank = ranks[r];
1094     PetscCall(DMLabelGetStratumIS(label, rank, &pointIS));
1095     PetscCall(ISGetLocalSize(pointIS, &numPoints));
1096     PetscCall(ISGetIndices(pointIS, &points));
1097     PetscCall(DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS));
1098     PetscCall(ISRestoreIndices(pointIS, &points));
1099     PetscCall(ISDestroy(&pointIS));
1100     PetscCall(DMLabelSetStratumIS(label, rank, closureIS));
1101     PetscCall(ISDestroy(&closureIS));
1102   }
1103   PetscCall(ISRestoreIndices(rankIS, &ranks));
1104   PetscCall(ISDestroy(&rankIS));
1105   PetscFunctionReturn(0);
1106 }
1107 
1108 /*@
1109   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
1110 
1111   Input Parameters:
1112 + dm     - The DM
1113 - label  - DMLabel assigning ranks to remote roots
1114 
1115   Level: developer
1116 
1117 .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1118 @*/
1119 PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
1120 {
1121   IS              rankIS,   pointIS;
1122   const PetscInt *ranks,   *points;
1123   PetscInt        numRanks, numPoints, r, p, a, adjSize;
1124   PetscInt       *adj = NULL;
1125 
1126   PetscFunctionBegin;
1127   PetscCall(DMLabelGetValueIS(label, &rankIS));
1128   PetscCall(ISGetLocalSize(rankIS, &numRanks));
1129   PetscCall(ISGetIndices(rankIS, &ranks));
1130   for (r = 0; r < numRanks; ++r) {
1131     const PetscInt rank = ranks[r];
1132 
1133     PetscCall(DMLabelGetStratumIS(label, rank, &pointIS));
1134     PetscCall(ISGetLocalSize(pointIS, &numPoints));
1135     PetscCall(ISGetIndices(pointIS, &points));
1136     for (p = 0; p < numPoints; ++p) {
1137       adjSize = PETSC_DETERMINE;
1138       PetscCall(DMPlexGetAdjacency(dm, points[p], &adjSize, &adj));
1139       for (a = 0; a < adjSize; ++a) PetscCall(DMLabelSetValue(label, adj[a], rank));
1140     }
1141     PetscCall(ISRestoreIndices(pointIS, &points));
1142     PetscCall(ISDestroy(&pointIS));
1143   }
1144   PetscCall(ISRestoreIndices(rankIS, &ranks));
1145   PetscCall(ISDestroy(&rankIS));
1146   PetscCall(PetscFree(adj));
1147   PetscFunctionReturn(0);
1148 }
1149 
1150 /*@
1151   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
1152 
1153   Input Parameters:
1154 + dm     - The DM
1155 - label  - DMLabel assigning ranks to remote roots
1156 
1157   Level: developer
1158 
1159   Note: This is required when generating multi-level overlaps to capture
1160   overlap points from non-neighbouring partitions.
1161 
1162 .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1163 @*/
1164 PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
1165 {
1166   MPI_Comm        comm;
1167   PetscMPIInt     rank;
1168   PetscSF         sfPoint;
1169   DMLabel         lblRoots, lblLeaves;
1170   IS              rankIS, pointIS;
1171   const PetscInt *ranks;
1172   PetscInt        numRanks, r;
1173 
1174   PetscFunctionBegin;
1175   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
1176   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1177   PetscCall(DMGetPointSF(dm, &sfPoint));
1178   /* Pull point contributions from remote leaves into local roots */
1179   PetscCall(DMLabelGather(label, sfPoint, &lblLeaves));
1180   PetscCall(DMLabelGetValueIS(lblLeaves, &rankIS));
1181   PetscCall(ISGetLocalSize(rankIS, &numRanks));
1182   PetscCall(ISGetIndices(rankIS, &ranks));
1183   for (r = 0; r < numRanks; ++r) {
1184     const PetscInt remoteRank = ranks[r];
1185     if (remoteRank == rank) continue;
1186     PetscCall(DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS));
1187     PetscCall(DMLabelInsertIS(label, pointIS, remoteRank));
1188     PetscCall(ISDestroy(&pointIS));
1189   }
1190   PetscCall(ISRestoreIndices(rankIS, &ranks));
1191   PetscCall(ISDestroy(&rankIS));
1192   PetscCall(DMLabelDestroy(&lblLeaves));
1193   /* Push point contributions from roots into remote leaves */
1194   PetscCall(DMLabelDistribute(label, sfPoint, &lblRoots));
1195   PetscCall(DMLabelGetValueIS(lblRoots, &rankIS));
1196   PetscCall(ISGetLocalSize(rankIS, &numRanks));
1197   PetscCall(ISGetIndices(rankIS, &ranks));
1198   for (r = 0; r < numRanks; ++r) {
1199     const PetscInt remoteRank = ranks[r];
1200     if (remoteRank == rank) continue;
1201     PetscCall(DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS));
1202     PetscCall(DMLabelInsertIS(label, pointIS, remoteRank));
1203     PetscCall(ISDestroy(&pointIS));
1204   }
1205   PetscCall(ISRestoreIndices(rankIS, &ranks));
1206   PetscCall(ISDestroy(&rankIS));
1207   PetscCall(DMLabelDestroy(&lblRoots));
1208   PetscFunctionReturn(0);
1209 }
1210 
1211 /*@
1212   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
1213 
1214   Input Parameters:
1215 + dm        - The DM
1216 . rootLabel - DMLabel assigning ranks to local roots
1217 - processSF - A star forest mapping into the local index on each remote rank
1218 
1219   Output Parameter:
1220 . leafLabel - DMLabel assigning ranks to remote roots
1221 
1222   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
1223   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
1224 
1225   Level: developer
1226 
1227 .seealso: `DMPlexPartitionLabelCreateSF()`, `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1228 @*/
1229 PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
1230 {
1231   MPI_Comm           comm;
1232   PetscMPIInt        rank, size, r;
1233   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
1234   PetscSF            sfPoint;
1235   PetscSection       rootSection;
1236   PetscSFNode       *rootPoints, *leafPoints;
1237   const PetscSFNode *remote;
1238   const PetscInt    *local, *neighbors;
1239   IS                 valueIS;
1240   PetscBool          mpiOverflow = PETSC_FALSE;
1241 
1242   PetscFunctionBegin;
1243   PetscCall(PetscLogEventBegin(DMPLEX_PartLabelInvert,dm,0,0,0));
1244   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
1245   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1246   PetscCallMPI(MPI_Comm_size(comm, &size));
1247   PetscCall(DMGetPointSF(dm, &sfPoint));
1248 
1249   /* Convert to (point, rank) and use actual owners */
1250   PetscCall(PetscSectionCreate(comm, &rootSection));
1251   PetscCall(PetscSectionSetChart(rootSection, 0, size));
1252   PetscCall(DMLabelGetValueIS(rootLabel, &valueIS));
1253   PetscCall(ISGetLocalSize(valueIS, &numNeighbors));
1254   PetscCall(ISGetIndices(valueIS, &neighbors));
1255   for (n = 0; n < numNeighbors; ++n) {
1256     PetscCall(DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints));
1257     PetscCall(PetscSectionAddDof(rootSection, neighbors[n], numPoints));
1258   }
1259   PetscCall(PetscSectionSetUp(rootSection));
1260   PetscCall(PetscSectionGetStorageSize(rootSection, &rootSize));
1261   PetscCall(PetscMalloc1(rootSize, &rootPoints));
1262   PetscCall(PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote));
1263   for (n = 0; n < numNeighbors; ++n) {
1264     IS              pointIS;
1265     const PetscInt *points;
1266 
1267     PetscCall(PetscSectionGetOffset(rootSection, neighbors[n], &off));
1268     PetscCall(DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS));
1269     PetscCall(ISGetLocalSize(pointIS, &numPoints));
1270     PetscCall(ISGetIndices(pointIS, &points));
1271     for (p = 0; p < numPoints; ++p) {
1272       if (local) PetscCall(PetscFindInt(points[p], nleaves, local, &l));
1273       else       {l = -1;}
1274       if (l >= 0) {rootPoints[off+p] = remote[l];}
1275       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
1276     }
1277     PetscCall(ISRestoreIndices(pointIS, &points));
1278     PetscCall(ISDestroy(&pointIS));
1279   }
1280 
1281   /* Try to communicate overlap using All-to-All */
1282   if (!processSF) {
1283     PetscInt64  counter = 0;
1284     PetscBool   locOverflow = PETSC_FALSE;
1285     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
1286 
1287     PetscCall(PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls));
1288     for (n = 0; n < numNeighbors; ++n) {
1289       PetscCall(PetscSectionGetDof(rootSection, neighbors[n], &dof));
1290       PetscCall(PetscSectionGetOffset(rootSection, neighbors[n], &off));
1291 #if defined(PETSC_USE_64BIT_INDICES)
1292       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
1293       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
1294 #endif
1295       scounts[neighbors[n]] = (PetscMPIInt) dof;
1296       sdispls[neighbors[n]] = (PetscMPIInt) off;
1297     }
1298     PetscCallMPI(MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm));
1299     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
1300     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
1301     PetscCallMPI(MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm));
1302     if (!mpiOverflow) {
1303       PetscCall(PetscInfo(dm,"Using Alltoallv for mesh distribution\n"));
1304       leafSize = (PetscInt) counter;
1305       PetscCall(PetscMalloc1(leafSize, &leafPoints));
1306       PetscCallMPI(MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm));
1307     }
1308     PetscCall(PetscFree4(scounts, sdispls, rcounts, rdispls));
1309   }
1310 
1311   /* Communicate overlap using process star forest */
1312   if (processSF || mpiOverflow) {
1313     PetscSF      procSF;
1314     PetscSection leafSection;
1315 
1316     if (processSF) {
1317       PetscCall(PetscInfo(dm,"Using processSF for mesh distribution\n"));
1318       PetscCall(PetscObjectReference((PetscObject)processSF));
1319       procSF = processSF;
1320     } else {
1321       PetscCall(PetscInfo(dm,"Using processSF for mesh distribution (MPI overflow)\n"));
1322       PetscCall(PetscSFCreate(comm,&procSF));
1323       PetscCall(PetscSFSetGraphWithPattern(procSF,NULL,PETSCSF_PATTERN_ALLTOALL));
1324     }
1325 
1326     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection));
1327     PetscCall(DMPlexDistributeData(dm, procSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints));
1328     PetscCall(PetscSectionGetStorageSize(leafSection, &leafSize));
1329     PetscCall(PetscSectionDestroy(&leafSection));
1330     PetscCall(PetscSFDestroy(&procSF));
1331   }
1332 
1333   for (p = 0; p < leafSize; p++) {
1334     PetscCall(DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank));
1335   }
1336 
1337   PetscCall(ISRestoreIndices(valueIS, &neighbors));
1338   PetscCall(ISDestroy(&valueIS));
1339   PetscCall(PetscSectionDestroy(&rootSection));
1340   PetscCall(PetscFree(rootPoints));
1341   PetscCall(PetscFree(leafPoints));
1342   PetscCall(PetscLogEventEnd(DMPLEX_PartLabelInvert,dm,0,0,0));
1343   PetscFunctionReturn(0);
1344 }
1345 
1346 /*@
1347   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
1348 
1349   Input Parameters:
1350 + dm    - The DM
1351 - label - DMLabel assigning ranks to remote roots
1352 
1353   Output Parameter:
1354 . sf    - The star forest communication context encapsulating the defined mapping
1355 
1356   Note: The incoming label is a receiver mapping of remote points to their parent rank.
1357 
1358   Level: developer
1359 
1360 .seealso: `DMPlexDistribute()`, `DMPlexCreateOverlap()`
1361 @*/
1362 PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
1363 {
1364   PetscMPIInt     rank;
1365   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
1366   PetscSFNode    *remotePoints;
1367   IS              remoteRootIS, neighborsIS;
1368   const PetscInt *remoteRoots, *neighbors;
1369 
1370   PetscFunctionBegin;
1371   PetscCall(PetscLogEventBegin(DMPLEX_PartLabelCreateSF,dm,0,0,0));
1372   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank));
1373 
1374   PetscCall(DMLabelGetValueIS(label, &neighborsIS));
1375 #if 0
1376   {
1377     IS is;
1378     PetscCall(ISDuplicate(neighborsIS, &is));
1379     PetscCall(ISSort(is));
1380     PetscCall(ISDestroy(&neighborsIS));
1381     neighborsIS = is;
1382   }
1383 #endif
1384   PetscCall(ISGetLocalSize(neighborsIS, &nNeighbors));
1385   PetscCall(ISGetIndices(neighborsIS, &neighbors));
1386   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
1387     PetscCall(DMLabelGetStratumSize(label, neighbors[n], &numPoints));
1388     numRemote += numPoints;
1389   }
1390   PetscCall(PetscMalloc1(numRemote, &remotePoints));
1391   /* Put owned points first */
1392   PetscCall(DMLabelGetStratumSize(label, rank, &numPoints));
1393   if (numPoints > 0) {
1394     PetscCall(DMLabelGetStratumIS(label, rank, &remoteRootIS));
1395     PetscCall(ISGetIndices(remoteRootIS, &remoteRoots));
1396     for (p = 0; p < numPoints; p++) {
1397       remotePoints[idx].index = remoteRoots[p];
1398       remotePoints[idx].rank = rank;
1399       idx++;
1400     }
1401     PetscCall(ISRestoreIndices(remoteRootIS, &remoteRoots));
1402     PetscCall(ISDestroy(&remoteRootIS));
1403   }
1404   /* Now add remote points */
1405   for (n = 0; n < nNeighbors; ++n) {
1406     const PetscInt nn = neighbors[n];
1407 
1408     PetscCall(DMLabelGetStratumSize(label, nn, &numPoints));
1409     if (nn == rank || numPoints <= 0) continue;
1410     PetscCall(DMLabelGetStratumIS(label, nn, &remoteRootIS));
1411     PetscCall(ISGetIndices(remoteRootIS, &remoteRoots));
1412     for (p = 0; p < numPoints; p++) {
1413       remotePoints[idx].index = remoteRoots[p];
1414       remotePoints[idx].rank = nn;
1415       idx++;
1416     }
1417     PetscCall(ISRestoreIndices(remoteRootIS, &remoteRoots));
1418     PetscCall(ISDestroy(&remoteRootIS));
1419   }
1420   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject) dm), sf));
1421   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1422   PetscCall(PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER));
1423   PetscCall(PetscSFSetUp(*sf));
1424   PetscCall(ISDestroy(&neighborsIS));
1425   PetscCall(PetscLogEventEnd(DMPLEX_PartLabelCreateSF,dm,0,0,0));
1426   PetscFunctionReturn(0);
1427 }
1428 
1429 #if defined(PETSC_HAVE_PARMETIS)
1430 #include <parmetis.h>
1431 #endif
1432 
1433 /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
1434  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
1435  * them out in that case. */
1436 #if defined(PETSC_HAVE_PARMETIS)
1437 /*@C
1438 
1439   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).
1440 
1441   Input parameters:
1442 + dm                - The DMPlex object.
1443 . n                 - The number of points.
1444 . pointsToRewrite   - The points in the SF whose ownership will change.
1445 . targetOwners      - New owner for each element in pointsToRewrite.
1446 - degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.
1447 
1448   Level: developer
1449 
1450 @*/
1451 static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
1452 {
1453   PetscInt      pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
1454   PetscInt     *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
1455   PetscSFNode  *leafLocationsNew;
1456   const         PetscSFNode *iremote;
1457   const         PetscInt *ilocal;
1458   PetscBool    *isLeaf;
1459   PetscSF       sf;
1460   MPI_Comm      comm;
1461   PetscMPIInt   rank, size;
1462 
1463   PetscFunctionBegin;
1464   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
1465   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1466   PetscCallMPI(MPI_Comm_size(comm, &size));
1467   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1468 
1469   PetscCall(DMGetPointSF(dm, &sf));
1470   PetscCall(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
1471   PetscCall(PetscMalloc1(pEnd-pStart, &isLeaf));
1472   for (i=0; i<pEnd-pStart; i++) {
1473     isLeaf[i] = PETSC_FALSE;
1474   }
1475   for (i=0; i<nleafs; i++) {
1476     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
1477   }
1478 
1479   PetscCall(PetscMalloc1(pEnd-pStart+1, &cumSumDegrees));
1480   cumSumDegrees[0] = 0;
1481   for (i=1; i<=pEnd-pStart; i++) {
1482     cumSumDegrees[i] = cumSumDegrees[i-1] + degrees[i-1];
1483   }
1484   sumDegrees = cumSumDegrees[pEnd-pStart];
1485   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
1486 
1487   PetscCall(PetscMalloc1(sumDegrees, &locationsOfLeafs));
1488   PetscCall(PetscMalloc1(pEnd-pStart, &rankOnLeafs));
1489   for (i=0; i<pEnd-pStart; i++) {
1490     rankOnLeafs[i] = rank;
1491   }
1492   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
1493   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs));
1494   PetscCall(PetscFree(rankOnLeafs));
1495 
1496   /* get the remote local points of my leaves */
1497   PetscCall(PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs));
1498   PetscCall(PetscMalloc1(pEnd-pStart, &points));
1499   for (i=0; i<pEnd-pStart; i++) {
1500     points[i] = pStart+i;
1501   }
1502   PetscCall(PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
1503   PetscCall(PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs));
1504   PetscCall(PetscFree(points));
1505   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
1506   PetscCall(PetscMalloc1(pEnd-pStart, &newOwners));
1507   PetscCall(PetscMalloc1(pEnd-pStart, &newNumbers));
1508   for (i=0; i<pEnd-pStart; i++) {
1509     newOwners[i] = -1;
1510     newNumbers[i] = -1;
1511   }
1512   {
1513     PetscInt oldNumber, newNumber, oldOwner, newOwner;
1514     for (i=0; i<n; i++) {
1515       oldNumber = pointsToRewrite[i];
1516       newNumber = -1;
1517       oldOwner = rank;
1518       newOwner = targetOwners[i];
1519       if (oldOwner == newOwner) {
1520         newNumber = oldNumber;
1521       } else {
1522         for (j=0; j<degrees[oldNumber]; j++) {
1523           if (locationsOfLeafs[cumSumDegrees[oldNumber]+j] == newOwner) {
1524             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber]+j];
1525             break;
1526           }
1527         }
1528       }
1529       PetscCheck(newNumber != -1,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
1530 
1531       newOwners[oldNumber] = newOwner;
1532       newNumbers[oldNumber] = newNumber;
1533     }
1534   }
1535   PetscCall(PetscFree(cumSumDegrees));
1536   PetscCall(PetscFree(locationsOfLeafs));
1537   PetscCall(PetscFree(remoteLocalPointOfLeafs));
1538 
1539   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners,MPI_REPLACE));
1540   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners,MPI_REPLACE));
1541   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers,MPI_REPLACE));
1542   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers,MPI_REPLACE));
1543 
1544   /* Now count how many leafs we have on each processor. */
1545   leafCounter=0;
1546   for (i=0; i<pEnd-pStart; i++) {
1547     if (newOwners[i] >= 0) {
1548       if (newOwners[i] != rank) {
1549         leafCounter++;
1550       }
1551     } else {
1552       if (isLeaf[i]) {
1553         leafCounter++;
1554       }
1555     }
1556   }
1557 
1558   /* Now set up the new sf by creating the leaf arrays */
1559   PetscCall(PetscMalloc1(leafCounter, &leafsNew));
1560   PetscCall(PetscMalloc1(leafCounter, &leafLocationsNew));
1561 
1562   leafCounter = 0;
1563   counter = 0;
1564   for (i=0; i<pEnd-pStart; i++) {
1565     if (newOwners[i] >= 0) {
1566       if (newOwners[i] != rank) {
1567         leafsNew[leafCounter] = i;
1568         leafLocationsNew[leafCounter].rank = newOwners[i];
1569         leafLocationsNew[leafCounter].index = newNumbers[i];
1570         leafCounter++;
1571       }
1572     } else {
1573       if (isLeaf[i]) {
1574         leafsNew[leafCounter] = i;
1575         leafLocationsNew[leafCounter].rank = iremote[counter].rank;
1576         leafLocationsNew[leafCounter].index = iremote[counter].index;
1577         leafCounter++;
1578       }
1579     }
1580     if (isLeaf[i]) {
1581       counter++;
1582     }
1583   }
1584 
1585   PetscCall(PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER));
1586   PetscCall(PetscFree(newOwners));
1587   PetscCall(PetscFree(newNumbers));
1588   PetscCall(PetscFree(isLeaf));
1589   PetscFunctionReturn(0);
1590 }
1591 
1592 static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
1593 {
1594   PetscInt    *distribution, min, max, sum;
1595   PetscMPIInt rank, size;
1596 
1597   PetscFunctionBegin;
1598   PetscCallMPI(MPI_Comm_size(comm, &size));
1599   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1600   PetscCall(PetscCalloc1(size, &distribution));
1601   for (PetscInt i=0; i<n; i++) {
1602     if (part) distribution[part[i]] += vtxwgt[skip*i];
1603     else distribution[rank] += vtxwgt[skip*i];
1604   }
1605   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm));
1606   min = distribution[0];
1607   max = distribution[0];
1608   sum = distribution[0];
1609   for (PetscInt i=1; i<size; i++) {
1610     if (distribution[i]<min) min=distribution[i];
1611     if (distribution[i]>max) max=distribution[i];
1612     sum += distribution[i];
1613   }
1614   PetscCall(PetscViewerASCIIPrintf(viewer, "Min: %" PetscInt_FMT ", Avg: %" PetscInt_FMT ", Max: %" PetscInt_FMT ", Balance: %f\n", min, sum/size, max, (max*1.*size)/sum));
1615   PetscCall(PetscFree(distribution));
1616   PetscFunctionReturn(0);
1617 }
1618 
1619 #endif
1620 
1621 /*@
1622   DMPlexRebalanceSharedPoints - Redistribute points in the plex that are shared in order to achieve better balancing. This routine updates the PointSF of the DM inplace.
1623 
1624   Input parameters:
1625 + dm               - The DMPlex object.
1626 . entityDepth      - depth of the entity to balance (0 -> balance vertices).
1627 . useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
1628 - parallel         - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.
1629 
1630   Output parameters:
1631 . success          - whether the graph partitioning was successful or not. If not, try useInitialGuess=True and parallel=True.
1632 
1633   Level: intermediate
1634 
1635 @*/
1636 
1637 PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
1638 {
1639 #if defined(PETSC_HAVE_PARMETIS)
1640   PetscSF     sf;
1641   PetscInt    ierr, i, j, idx, jdx;
1642   PetscInt    eBegin, eEnd, nroots, nleafs, pStart, pEnd;
1643   const       PetscInt *degrees, *ilocal;
1644   const       PetscSFNode *iremote;
1645   PetscBool   *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
1646   PetscInt    numExclusivelyOwned, numNonExclusivelyOwned;
1647   PetscMPIInt rank, size;
1648   PetscInt    *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
1649   const       PetscInt *cumSumVertices;
1650   PetscInt    offset, counter;
1651   PetscInt    lenadjncy;
1652   PetscInt    *xadj, *adjncy, *vtxwgt;
1653   PetscInt    lenxadj;
1654   PetscInt    *adjwgt = NULL;
1655   PetscInt    *part, *options;
1656   PetscInt    nparts, wgtflag, numflag, ncon, edgecut;
1657   real_t      *ubvec;
1658   PetscInt    *firstVertices, *renumbering;
1659   PetscInt    failed, failedGlobal;
1660   MPI_Comm    comm;
1661   Mat         A, Apre;
1662   const char *prefix = NULL;
1663   PetscViewer       viewer;
1664   PetscViewerFormat format;
1665   PetscLayout layout;
1666 
1667   PetscFunctionBegin;
1668   if (success) *success = PETSC_FALSE;
1669   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
1670   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1671   PetscCallMPI(MPI_Comm_size(comm, &size));
1672   if (size==1) PetscFunctionReturn(0);
1673 
1674   PetscCall(PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
1675 
1676   PetscCall(PetscOptionsGetViewer(comm,((PetscObject)dm)->options, prefix,"-dm_rebalance_partition_view",&viewer,&format,NULL));
1677   if (viewer) PetscCall(PetscViewerPushFormat(viewer,format));
1678 
1679   /* Figure out all points in the plex that we are interested in balancing. */
1680   PetscCall(DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd));
1681   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1682   PetscCall(PetscMalloc1(pEnd-pStart, &toBalance));
1683 
1684   for (i=0; i<pEnd-pStart; i++) {
1685     toBalance[i] = (PetscBool)(i-pStart>=eBegin && i-pStart<eEnd);
1686   }
1687 
1688   /* There are three types of points:
1689    * exclusivelyOwned: points that are owned by this process and only seen by this process
1690    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
1691    * leaf: a point that is seen by this process but owned by a different process
1692    */
1693   PetscCall(DMGetPointSF(dm, &sf));
1694   PetscCall(PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote));
1695   PetscCall(PetscMalloc1(pEnd-pStart, &isLeaf));
1696   PetscCall(PetscMalloc1(pEnd-pStart, &isNonExclusivelyOwned));
1697   PetscCall(PetscMalloc1(pEnd-pStart, &isExclusivelyOwned));
1698   for (i=0; i<pEnd-pStart; i++) {
1699     isNonExclusivelyOwned[i] = PETSC_FALSE;
1700     isExclusivelyOwned[i] = PETSC_FALSE;
1701     isLeaf[i] = PETSC_FALSE;
1702   }
1703 
1704   /* start by marking all the leafs */
1705   for (i=0; i<nleafs; i++) {
1706     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
1707   }
1708 
1709   /* for an owned point, we can figure out whether another processor sees it or
1710    * not by calculating its degree */
1711   PetscCall(PetscSFComputeDegreeBegin(sf, &degrees));
1712   PetscCall(PetscSFComputeDegreeEnd(sf, &degrees));
1713 
1714   numExclusivelyOwned = 0;
1715   numNonExclusivelyOwned = 0;
1716   for (i=0; i<pEnd-pStart; i++) {
1717     if (toBalance[i]) {
1718       if (degrees[i] > 0) {
1719         isNonExclusivelyOwned[i] = PETSC_TRUE;
1720         numNonExclusivelyOwned += 1;
1721       } else {
1722         if (!isLeaf[i]) {
1723           isExclusivelyOwned[i] = PETSC_TRUE;
1724           numExclusivelyOwned += 1;
1725         }
1726       }
1727     }
1728   }
1729 
1730   /* We are going to build a graph with one vertex per core representing the
1731    * exclusively owned points and then one vertex per nonExclusively owned
1732    * point. */
1733 
1734   PetscCall(PetscLayoutCreate(comm, &layout));
1735   PetscCall(PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned));
1736   PetscCall(PetscLayoutSetUp(layout));
1737   PetscCall(PetscLayoutGetRanges(layout, &cumSumVertices));
1738 
1739   PetscCall(PetscMalloc1(pEnd-pStart, &globalNumbersOfLocalOwnedVertices));
1740   for (i=0; i<pEnd-pStart; i++) {globalNumbersOfLocalOwnedVertices[i] = pStart - 1;}
1741   offset = cumSumVertices[rank];
1742   counter = 0;
1743   for (i=0; i<pEnd-pStart; i++) {
1744     if (toBalance[i]) {
1745       if (degrees[i] > 0) {
1746         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
1747         counter++;
1748       }
1749     }
1750   }
1751 
1752   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
1753   PetscCall(PetscMalloc1(pEnd-pStart, &leafGlobalNumbers));
1754   PetscCall(PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers,MPI_REPLACE));
1755   PetscCall(PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers,MPI_REPLACE));
1756 
1757   /* Now start building the data structure for ParMETIS */
1758 
1759   PetscCall(MatCreate(comm, &Apre));
1760   PetscCall(MatSetType(Apre, MATPREALLOCATOR));
1761   PetscCall(MatSetSizes(Apre, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]));
1762   PetscCall(MatSetUp(Apre));
1763 
1764   for (i=0; i<pEnd-pStart; i++) {
1765     if (toBalance[i]) {
1766       idx = cumSumVertices[rank];
1767       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
1768       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
1769       else continue;
1770       PetscCall(MatSetValue(Apre, idx, jdx, 1, INSERT_VALUES));
1771       PetscCall(MatSetValue(Apre, jdx, idx, 1, INSERT_VALUES));
1772     }
1773   }
1774 
1775   PetscCall(MatAssemblyBegin(Apre, MAT_FINAL_ASSEMBLY));
1776   PetscCall(MatAssemblyEnd(Apre, MAT_FINAL_ASSEMBLY));
1777 
1778   PetscCall(MatCreate(comm, &A));
1779   PetscCall(MatSetType(A, MATMPIAIJ));
1780   PetscCall(MatSetSizes(A, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]));
1781   PetscCall(MatPreallocatorPreallocate(Apre, PETSC_FALSE, A));
1782   PetscCall(MatDestroy(&Apre));
1783 
1784   for (i=0; i<pEnd-pStart; i++) {
1785     if (toBalance[i]) {
1786       idx = cumSumVertices[rank];
1787       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
1788       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
1789       else continue;
1790       PetscCall(MatSetValue(A, idx, jdx, 1, INSERT_VALUES));
1791       PetscCall(MatSetValue(A, jdx, idx, 1, INSERT_VALUES));
1792     }
1793   }
1794 
1795   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1796   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1797   PetscCall(PetscFree(leafGlobalNumbers));
1798   PetscCall(PetscFree(globalNumbersOfLocalOwnedVertices));
1799 
1800   nparts = size;
1801   wgtflag = 2;
1802   numflag = 0;
1803   ncon = 2;
1804   real_t *tpwgts;
1805   PetscCall(PetscMalloc1(ncon * nparts, &tpwgts));
1806   for (i=0; i<ncon*nparts; i++) {
1807     tpwgts[i] = 1./(nparts);
1808   }
1809 
1810   PetscCall(PetscMalloc1(ncon, &ubvec));
1811   ubvec[0] = 1.01;
1812   ubvec[1] = 1.01;
1813   lenadjncy = 0;
1814   for (i=0; i<1+numNonExclusivelyOwned; i++) {
1815     PetscInt temp=0;
1816     PetscCall(MatGetRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL));
1817     lenadjncy += temp;
1818     PetscCall(MatRestoreRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL));
1819   }
1820   PetscCall(PetscMalloc1(lenadjncy, &adjncy));
1821   lenxadj = 2 + numNonExclusivelyOwned;
1822   PetscCall(PetscMalloc1(lenxadj, &xadj));
1823   xadj[0] = 0;
1824   counter = 0;
1825   for (i=0; i<1+numNonExclusivelyOwned; i++) {
1826     PetscInt        temp=0;
1827     const PetscInt *cols;
1828     PetscCall(MatGetRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL));
1829     PetscCall(PetscArraycpy(&adjncy[counter], cols, temp));
1830     counter += temp;
1831     xadj[i+1] = counter;
1832     PetscCall(MatRestoreRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL));
1833   }
1834 
1835   PetscCall(PetscMalloc1(cumSumVertices[rank+1]-cumSumVertices[rank], &part));
1836   PetscCall(PetscMalloc1(ncon*(1 + numNonExclusivelyOwned), &vtxwgt));
1837   vtxwgt[0] = numExclusivelyOwned;
1838   if (ncon>1) vtxwgt[1] = 1;
1839   for (i=0; i<numNonExclusivelyOwned; i++) {
1840     vtxwgt[ncon*(i+1)] = 1;
1841     if (ncon>1) vtxwgt[ncon*(i+1)+1] = 0;
1842   }
1843 
1844   if (viewer) {
1845     PetscCall(PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %" PetscInt_FMT " on interface of mesh distribution.\n", entityDepth));
1846     PetscCall(PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %" PetscInt_FMT "\n", cumSumVertices[size]));
1847   }
1848   if (parallel) {
1849     PetscCall(PetscMalloc1(4, &options));
1850     options[0] = 1;
1851     options[1] = 0; /* Verbosity */
1852     options[2] = 0; /* Seed */
1853     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
1854     if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n"));
1855     if (useInitialGuess) {
1856       if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n"));
1857       PetscStackPush("ParMETIS_V3_RefineKway");
1858       ierr = ParMETIS_V3_RefineKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
1859       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
1860       PetscStackPop;
1861     } else {
1862       PetscStackPush("ParMETIS_V3_PartKway");
1863       ierr = ParMETIS_V3_PartKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
1864       PetscStackPop;
1865       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
1866     }
1867     PetscCall(PetscFree(options));
1868   } else {
1869     if (viewer) PetscCall(PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n"));
1870     Mat As;
1871     PetscInt numRows;
1872     PetscInt *partGlobal;
1873     PetscCall(MatCreateRedundantMatrix(A, size, MPI_COMM_NULL, MAT_INITIAL_MATRIX, &As));
1874 
1875     PetscInt *numExclusivelyOwnedAll;
1876     PetscCall(PetscMalloc1(size, &numExclusivelyOwnedAll));
1877     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
1878     PetscCallMPI(MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,numExclusivelyOwnedAll,1,MPIU_INT,comm));
1879 
1880     PetscCall(MatGetSize(As, &numRows, NULL));
1881     PetscCall(PetscMalloc1(numRows, &partGlobal));
1882     if (rank == 0) {
1883       PetscInt *adjncy_g, *xadj_g, *vtxwgt_g;
1884       lenadjncy = 0;
1885 
1886       for (i=0; i<numRows; i++) {
1887         PetscInt temp=0;
1888         PetscCall(MatGetRow(As, i, &temp, NULL, NULL));
1889         lenadjncy += temp;
1890         PetscCall(MatRestoreRow(As, i, &temp, NULL, NULL));
1891       }
1892       PetscCall(PetscMalloc1(lenadjncy, &adjncy_g));
1893       lenxadj = 1 + numRows;
1894       PetscCall(PetscMalloc1(lenxadj, &xadj_g));
1895       xadj_g[0] = 0;
1896       counter = 0;
1897       for (i=0; i<numRows; i++) {
1898         PetscInt        temp=0;
1899         const PetscInt *cols;
1900         PetscCall(MatGetRow(As, i, &temp, &cols, NULL));
1901         PetscCall(PetscArraycpy(&adjncy_g[counter], cols, temp));
1902         counter += temp;
1903         xadj_g[i+1] = counter;
1904         PetscCall(MatRestoreRow(As, i, &temp, &cols, NULL));
1905       }
1906       PetscCall(PetscMalloc1(2*numRows, &vtxwgt_g));
1907       for (i=0; i<size; i++) {
1908         vtxwgt_g[ncon*cumSumVertices[i]] = numExclusivelyOwnedAll[i];
1909         if (ncon>1) vtxwgt_g[ncon*cumSumVertices[i]+1] = 1;
1910         for (j=cumSumVertices[i]+1; j<cumSumVertices[i+1]; j++) {
1911           vtxwgt_g[ncon*j] = 1;
1912           if (ncon>1) vtxwgt_g[2*j+1] = 0;
1913         }
1914       }
1915       PetscCall(PetscMalloc1(64, &options));
1916       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
1917       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
1918       options[METIS_OPTION_CONTIG] = 1;
1919       PetscStackPush("METIS_PartGraphKway");
1920       ierr = METIS_PartGraphKway(&numRows, &ncon, xadj_g, adjncy_g, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
1921       PetscStackPop;
1922       PetscCheck(ierr == METIS_OK,PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
1923       PetscCall(PetscFree(options));
1924       PetscCall(PetscFree(xadj_g));
1925       PetscCall(PetscFree(adjncy_g));
1926       PetscCall(PetscFree(vtxwgt_g));
1927     }
1928     PetscCall(PetscFree(numExclusivelyOwnedAll));
1929 
1930     /* Now scatter the parts array. */
1931     {
1932       PetscMPIInt *counts, *mpiCumSumVertices;
1933       PetscCall(PetscMalloc1(size, &counts));
1934       PetscCall(PetscMalloc1(size+1, &mpiCumSumVertices));
1935       for (i=0; i<size; i++) {
1936         PetscCall(PetscMPIIntCast(cumSumVertices[i+1] - cumSumVertices[i], &(counts[i])));
1937       }
1938       for (i=0; i<=size; i++) {
1939         PetscCall(PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i])));
1940       }
1941       PetscCallMPI(MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm));
1942       PetscCall(PetscFree(counts));
1943       PetscCall(PetscFree(mpiCumSumVertices));
1944     }
1945 
1946     PetscCall(PetscFree(partGlobal));
1947     PetscCall(MatDestroy(&As));
1948   }
1949 
1950   PetscCall(MatDestroy(&A));
1951   PetscCall(PetscFree(ubvec));
1952   PetscCall(PetscFree(tpwgts));
1953 
1954   /* Now rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
1955 
1956   PetscCall(PetscMalloc1(size, &firstVertices));
1957   PetscCall(PetscMalloc1(size, &renumbering));
1958   firstVertices[rank] = part[0];
1959   PetscCallMPI(MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,firstVertices,1,MPIU_INT,comm));
1960   for (i=0; i<size; i++) {
1961     renumbering[firstVertices[i]] = i;
1962   }
1963   for (i=0; i<cumSumVertices[rank+1]-cumSumVertices[rank]; i++) {
1964     part[i] = renumbering[part[i]];
1965   }
1966   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
1967   failed = (PetscInt)(part[0] != rank);
1968   PetscCallMPI(MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm));
1969 
1970   PetscCall(PetscFree(firstVertices));
1971   PetscCall(PetscFree(renumbering));
1972 
1973   if (failedGlobal > 0) {
1974     PetscCall(PetscLayoutDestroy(&layout));
1975     PetscCall(PetscFree(xadj));
1976     PetscCall(PetscFree(adjncy));
1977     PetscCall(PetscFree(vtxwgt));
1978     PetscCall(PetscFree(toBalance));
1979     PetscCall(PetscFree(isLeaf));
1980     PetscCall(PetscFree(isNonExclusivelyOwned));
1981     PetscCall(PetscFree(isExclusivelyOwned));
1982     PetscCall(PetscFree(part));
1983     if (viewer) {
1984       PetscCall(PetscViewerPopFormat(viewer));
1985       PetscCall(PetscViewerDestroy(&viewer));
1986     }
1987     PetscCall(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
1988     PetscFunctionReturn(0);
1989   }
1990 
1991   /*Let's check how well we did distributing points*/
1992   if (viewer) {
1993     PetscCall(PetscViewerASCIIPrintf(viewer, "Comparing number of owned entities of depth %" PetscInt_FMT " on each process before rebalancing, after rebalancing, and after consistency checks.\n", entityDepth));
1994     PetscCall(PetscViewerASCIIPrintf(viewer, "Initial.     "));
1995     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, NULL, viewer));
1996     PetscCall(PetscViewerASCIIPrintf(viewer, "Rebalanced.  "));
1997     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer));
1998   }
1999 
2000   /* Now check that every vertex is owned by a process that it is actually connected to. */
2001   for (i=1; i<=numNonExclusivelyOwned; i++) {
2002     PetscInt loc = 0;
2003     PetscCall(PetscFindInt(cumSumVertices[part[i]], xadj[i+1]-xadj[i], &adjncy[xadj[i]], &loc));
2004     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
2005     if (loc<0) {
2006       part[i] = rank;
2007     }
2008   }
2009 
2010   /* Let's see how significant the influences of the previous fixing up step was.*/
2011   if (viewer) {
2012     PetscCall(PetscViewerASCIIPrintf(viewer, "After.       "));
2013     PetscCall(DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer));
2014   }
2015 
2016   PetscCall(PetscLayoutDestroy(&layout));
2017   PetscCall(PetscFree(xadj));
2018   PetscCall(PetscFree(adjncy));
2019   PetscCall(PetscFree(vtxwgt));
2020 
2021   /* Almost done, now rewrite the SF to reflect the new ownership. */
2022   {
2023     PetscInt *pointsToRewrite;
2024     PetscCall(PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite));
2025     counter = 0;
2026     for (i=0; i<pEnd-pStart; i++) {
2027       if (toBalance[i]) {
2028         if (isNonExclusivelyOwned[i]) {
2029           pointsToRewrite[counter] = i + pStart;
2030           counter++;
2031         }
2032       }
2033     }
2034     PetscCall(DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part+1, degrees));
2035     PetscCall(PetscFree(pointsToRewrite));
2036   }
2037 
2038   PetscCall(PetscFree(toBalance));
2039   PetscCall(PetscFree(isLeaf));
2040   PetscCall(PetscFree(isNonExclusivelyOwned));
2041   PetscCall(PetscFree(isExclusivelyOwned));
2042   PetscCall(PetscFree(part));
2043   if (viewer) {
2044     PetscCall(PetscViewerPopFormat(viewer));
2045     PetscCall(PetscViewerDestroy(&viewer));
2046   }
2047   if (success) *success = PETSC_TRUE;
2048   PetscCall(PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0));
2049   PetscFunctionReturn(0);
2050 #else
2051   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
2052 #endif
2053 }
2054