Actual source code: plexpartition.c

      1: #include <petsc/private/dmpleximpl.h>
      2: #include <petsc/private/partitionerimpl.h>
      3: #include <petsc/private/hashseti.h>

      5: const char * const DMPlexCSRAlgorithms[] = {"mat", "graph", "overlap", "DMPlexCSRAlgorithm", "DM_PLEX_CSR_",NULL};

      7: static inline PetscInt DMPlex_GlobalID(PetscInt point) { return point >= 0 ? point : -(point+1); }

      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;

     20:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
     21:   MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);
     22:   DMGetDimension(dm, &dim);
     23:   DMPlexGetDepth(dm, &depth);
     24:   if (dim != depth) {
     25:     /* We do not handle the uninterpolated case here */
     26:     DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);
     27:     /* DMPlexCreateNeighborCSR does not make a numbering */
     28:     if (globalNumbering) DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);
     29:     /* Different behavior for empty graphs */
     30:     if (!*numVertices) {
     31:       PetscMalloc1(1, offsets);
     32:       (*offsets)[0] = 0;
     33:     }
     34:     /* Broken in parallel */
     36:     return 0;
     37:   }
     38:   /* Always use FVM adjacency to create partitioner graph */
     39:   DMGetBasicAdjacency(dm, &useCone, &useClosure);
     40:   DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE);
     41:   /* Need overlap >= 1 */
     42:   DMPlexGetOverlap(dm, &overlap);
     43:   if (size && overlap < 1) {
     44:     DMPlexDistributeOverlap(dm, 1, NULL, &ovdm);
     45:   } else {
     46:     PetscObjectReference((PetscObject) dm);
     47:     ovdm = dm;
     48:   }
     49:   DMGetPointSF(ovdm, &sfPoint);
     50:   DMPlexGetHeightStratum(ovdm, height, &cStart, &cEnd);
     51:   DMPlexCreateNumbering_Plex(ovdm, cStart, cEnd, 0, NULL, sfPoint, &cellNumbering);
     52:   if (globalNumbering) {
     53:     PetscObjectReference((PetscObject) cellNumbering);
     54:     *globalNumbering = cellNumbering;
     55:   }
     56:   ISGetIndices(cellNumbering, &cellNum);
     57:   /* Determine sizes */
     58:   for (*numVertices = 0, c = cStart; c < cEnd; ++c) {
     59:     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
     60:     if (cellNum[c-cStart] < 0) continue;
     61:     (*numVertices)++;
     62:   }
     63:   PetscCalloc1(*numVertices+1, &vOffsets);
     64:   for (c = cStart, v = 0; c < cEnd; ++c) {
     65:     PetscInt adjSize = PETSC_DETERMINE, a, vsize = 0;

     67:     if (cellNum[c-cStart] < 0) continue;
     68:     DMPlexGetAdjacency(ovdm, c, &adjSize, &adj);
     69:     for (a = 0; a < adjSize; ++a) {
     70:       const PetscInt point = adj[a];
     71:       if (point != c && cStart <= point && point < cEnd) ++vsize;
     72:     }
     73:     vOffsets[v+1] = vOffsets[v] + vsize;
     74:     ++v;
     75:   }
     76:   /* Determine adjacency */
     77:   PetscMalloc1(vOffsets[*numVertices], &vAdj);
     78:   for (c = cStart, v = 0; c < cEnd; ++c) {
     79:     PetscInt adjSize = PETSC_DETERMINE, a, off = vOffsets[v];

     81:     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
     82:     if (cellNum[c-cStart] < 0) continue;
     83:     DMPlexGetAdjacency(ovdm, c, &adjSize, &adj);
     84:     for (a = 0; a < adjSize; ++a) {
     85:       const PetscInt point = adj[a];
     86:       if (point != c && cStart <= point && point < cEnd) {
     87:         vAdj[off++] = DMPlex_GlobalID(cellNum[point-cStart]);
     88:       }
     89:     }
     91:     /* Sort adjacencies (not strictly necessary) */
     92:     PetscSortInt(off-vOffsets[v], &vAdj[vOffsets[v]]);
     93:     ++v;
     94:   }
     95:   PetscFree(adj);
     96:   ISRestoreIndices(cellNumbering, &cellNum);
     97:   ISDestroy(&cellNumbering);
     98:   DMSetBasicAdjacency(dm, useCone, useClosure);
     99:   DMDestroy(&ovdm);
    100:   if (offsets)   {*offsets = vOffsets;}
    101:   else           PetscFree(vOffsets);
    102:   if (adjacency) {*adjacency = vAdj;}
    103:   else           PetscFree(vAdj);
    104:   return 0;
    105: }

    107: static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
    108: {
    109:   PetscInt       dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
    110:   PetscInt      *adj = NULL, *vOffsets = NULL, *graph = NULL;
    111:   IS             cellNumbering;
    112:   const PetscInt *cellNum;
    113:   PetscBool      useCone, useClosure;
    114:   PetscSection   section;
    115:   PetscSegBuffer adjBuffer;
    116:   PetscSF        sfPoint;
    117:   PetscInt       *adjCells = NULL, *remoteCells = NULL;
    118:   const PetscInt *local;
    119:   PetscInt       nroots, nleaves, l;
    120:   PetscMPIInt    rank;

    122:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
    123:   DMGetDimension(dm, &dim);
    124:   DMPlexGetDepth(dm, &depth);
    125:   if (dim != depth) {
    126:     /* We do not handle the uninterpolated case here */
    127:     DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);
    128:     /* DMPlexCreateNeighborCSR does not make a numbering */
    129:     if (globalNumbering) DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);
    130:     /* Different behavior for empty graphs */
    131:     if (!*numVertices) {
    132:       PetscMalloc1(1, offsets);
    133:       (*offsets)[0] = 0;
    134:     }
    135:     /* Broken in parallel */
    137:     return 0;
    138:   }
    139:   DMGetPointSF(dm, &sfPoint);
    140:   DMPlexGetHeightStratum(dm, height, &pStart, &pEnd);
    141:   /* Build adjacency graph via a section/segbuffer */
    142:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &section);
    143:   PetscSectionSetChart(section, pStart, pEnd);
    144:   PetscSegBufferCreate(sizeof(PetscInt),1000,&adjBuffer);
    145:   /* Always use FVM adjacency to create partitioner graph */
    146:   DMGetBasicAdjacency(dm, &useCone, &useClosure);
    147:   DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE);
    148:   DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, sfPoint, &cellNumbering);
    149:   if (globalNumbering) {
    150:     PetscObjectReference((PetscObject)cellNumbering);
    151:     *globalNumbering = cellNumbering;
    152:   }
    153:   ISGetIndices(cellNumbering, &cellNum);
    154:   /* For all boundary faces (including faces adjacent to a ghost cell), record the local cell in adjCells
    155:      Broadcast adjCells to remoteCells (to get cells from roots) and Reduce adjCells to remoteCells (to get cells from leaves)
    156:    */
    157:   PetscSFGetGraph(sfPoint, &nroots, &nleaves, &local, NULL);
    158:   if (nroots >= 0) {
    159:     PetscInt fStart, fEnd, f;

    161:     PetscCalloc2(nroots, &adjCells, nroots, &remoteCells);
    162:     DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);
    163:     for (l = 0; l < nroots; ++l) adjCells[l] = -3;
    164:     for (f = fStart; f < fEnd; ++f) {
    165:       const PetscInt *support;
    166:       PetscInt        supportSize;

    168:       DMPlexGetSupport(dm, f, &support);
    169:       DMPlexGetSupportSize(dm, f, &supportSize);
    170:       if (supportSize == 1) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]-pStart]);
    171:       else if (supportSize == 2) {
    172:         PetscFindInt(support[0], nleaves, local, &p);
    173:         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1]-pStart]);
    174:         PetscFindInt(support[1], nleaves, local, &p);
    175:         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]-pStart]);
    176:       }
    177:       /* Handle non-conforming meshes */
    178:       if (supportSize > 2) {
    179:         PetscInt        numChildren, i;
    180:         const PetscInt *children;

    182:         DMPlexGetTreeChildren(dm, f, &numChildren, &children);
    183:         for (i = 0; i < numChildren; ++i) {
    184:           const PetscInt child = children[i];
    185:           if (fStart <= child && child < fEnd) {
    186:             DMPlexGetSupport(dm, child, &support);
    187:             DMPlexGetSupportSize(dm, child, &supportSize);
    188:             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]-pStart]);
    189:             else if (supportSize == 2) {
    190:               PetscFindInt(support[0], nleaves, local, &p);
    191:               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1]-pStart]);
    192:               PetscFindInt(support[1], nleaves, local, &p);
    193:               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]-pStart]);
    194:             }
    195:           }
    196:         }
    197:       }
    198:     }
    199:     for (l = 0; l < nroots; ++l) remoteCells[l] = -1;
    200:     PetscSFBcastBegin(dm->sf, MPIU_INT, adjCells, remoteCells,MPI_REPLACE);
    201:     PetscSFBcastEnd(dm->sf, MPIU_INT, adjCells, remoteCells,MPI_REPLACE);
    202:     PetscSFReduceBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);
    203:     PetscSFReduceEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);
    204:   }
    205:   /* Combine local and global adjacencies */
    206:   for (*numVertices = 0, p = pStart; p < pEnd; p++) {
    207:     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
    208:     if (nroots > 0) {if (cellNum[p-pStart] < 0) continue;}
    209:     /* Add remote cells */
    210:     if (remoteCells) {
    211:       const PetscInt gp = DMPlex_GlobalID(cellNum[p-pStart]);
    212:       PetscInt       coneSize, numChildren, c, i;
    213:       const PetscInt *cone, *children;

    215:       DMPlexGetCone(dm, p, &cone);
    216:       DMPlexGetConeSize(dm, p, &coneSize);
    217:       for (c = 0; c < coneSize; ++c) {
    218:         const PetscInt point = cone[c];
    219:         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
    220:           PetscInt *PETSC_RESTRICT pBuf;
    221:           PetscSectionAddDof(section, p, 1);
    222:           PetscSegBufferGetInts(adjBuffer, 1, &pBuf);
    223:           *pBuf = remoteCells[point];
    224:         }
    225:         /* Handle non-conforming meshes */
    226:         DMPlexGetTreeChildren(dm, point, &numChildren, &children);
    227:         for (i = 0; i < numChildren; ++i) {
    228:           const PetscInt child = children[i];
    229:           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
    230:             PetscInt *PETSC_RESTRICT pBuf;
    231:             PetscSectionAddDof(section, p, 1);
    232:             PetscSegBufferGetInts(adjBuffer, 1, &pBuf);
    233:             *pBuf = remoteCells[child];
    234:           }
    235:         }
    236:       }
    237:     }
    238:     /* Add local cells */
    239:     adjSize = PETSC_DETERMINE;
    240:     DMPlexGetAdjacency(dm, p, &adjSize, &adj);
    241:     for (a = 0; a < adjSize; ++a) {
    242:       const PetscInt point = adj[a];
    243:       if (point != p && pStart <= point && point < pEnd) {
    244:         PetscInt *PETSC_RESTRICT pBuf;
    245:         PetscSectionAddDof(section, p, 1);
    246:         PetscSegBufferGetInts(adjBuffer, 1, &pBuf);
    247:         *pBuf = DMPlex_GlobalID(cellNum[point-pStart]);
    248:       }
    249:     }
    250:     (*numVertices)++;
    251:   }
    252:   PetscFree(adj);
    253:   PetscFree2(adjCells, remoteCells);
    254:   DMSetBasicAdjacency(dm, useCone, useClosure);

    256:   /* Derive CSR graph from section/segbuffer */
    257:   PetscSectionSetUp(section);
    258:   PetscSectionGetStorageSize(section, &size);
    259:   PetscMalloc1(*numVertices+1, &vOffsets);
    260:   for (idx = 0, p = pStart; p < pEnd; p++) {
    261:     if (nroots > 0) {if (cellNum[p-pStart] < 0) continue;}
    262:     PetscSectionGetOffset(section, p, &(vOffsets[idx++]));
    263:   }
    264:   vOffsets[*numVertices] = size;
    265:   PetscSegBufferExtractAlloc(adjBuffer, &graph);

    267:   if (nroots >= 0) {
    268:     /* Filter out duplicate edges using section/segbuffer */
    269:     PetscSectionReset(section);
    270:     PetscSectionSetChart(section, 0, *numVertices);
    271:     for (p = 0; p < *numVertices; p++) {
    272:       PetscInt start = vOffsets[p], end = vOffsets[p+1];
    273:       PetscInt numEdges = end-start, *PETSC_RESTRICT edges;
    274:       PetscSortRemoveDupsInt(&numEdges, &graph[start]);
    275:       PetscSectionSetDof(section, p, numEdges);
    276:       PetscSegBufferGetInts(adjBuffer, numEdges, &edges);
    277:       PetscArraycpy(edges, &graph[start], numEdges);
    278:     }
    279:     PetscFree(vOffsets);
    280:     PetscFree(graph);
    281:     /* Derive CSR graph from section/segbuffer */
    282:     PetscSectionSetUp(section);
    283:     PetscSectionGetStorageSize(section, &size);
    284:     PetscMalloc1(*numVertices+1, &vOffsets);
    285:     for (idx = 0, p = 0; p < *numVertices; p++) {
    286:       PetscSectionGetOffset(section, p, &(vOffsets[idx++]));
    287:     }
    288:     vOffsets[*numVertices] = size;
    289:     PetscSegBufferExtractAlloc(adjBuffer, &graph);
    290:   } else {
    291:     /* Sort adjacencies (not strictly necessary) */
    292:     for (p = 0; p < *numVertices; p++) {
    293:       PetscInt start = vOffsets[p], end = vOffsets[p+1];
    294:       PetscSortInt(end-start, &graph[start]);
    295:     }
    296:   }

    298:   if (offsets) *offsets = vOffsets;
    299:   if (adjacency) *adjacency = graph;

    301:   /* Cleanup */
    302:   PetscSegBufferDestroy(&adjBuffer);
    303:   PetscSectionDestroy(&section);
    304:   ISRestoreIndices(cellNumbering, &cellNum);
    305:   ISDestroy(&cellNumbering);
    306:   return 0;
    307: }

    309: static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
    310: {
    311:   Mat            conn, CSR;
    312:   IS             fis, cis, cis_own;
    313:   PetscSF        sfPoint;
    314:   const PetscInt *rows, *cols, *ii, *jj;
    315:   PetscInt       *idxs,*idxs2;
    316:   PetscInt       dim, depth, floc, cloc, i, M, N, c, lm, m, cStart, cEnd, fStart, fEnd;
    317:   PetscMPIInt    rank;
    318:   PetscBool      flg;

    320:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);
    321:   DMGetDimension(dm, &dim);
    322:   DMPlexGetDepth(dm, &depth);
    323:   if (dim != depth) {
    324:     /* We do not handle the uninterpolated case here */
    325:     DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);
    326:     /* DMPlexCreateNeighborCSR does not make a numbering */
    327:     if (globalNumbering) DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);
    328:     /* Different behavior for empty graphs */
    329:     if (!*numVertices) {
    330:       PetscMalloc1(1, offsets);
    331:       (*offsets)[0] = 0;
    332:     }
    333:     /* Broken in parallel */
    335:     return 0;
    336:   }
    337:   /* Interpolated and parallel case */

    339:   /* numbering */
    340:   DMGetPointSF(dm, &sfPoint);
    341:   DMPlexGetHeightStratum(dm, height, &cStart, &cEnd);
    342:   DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);
    343:   DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, &N, sfPoint, &cis);
    344:   DMPlexCreateNumbering_Plex(dm, fStart, fEnd, 0, &M, sfPoint, &fis);
    345:   if (globalNumbering) {
    346:     ISDuplicate(cis, globalNumbering);
    347:   }

    349:   /* get positive global ids and local sizes for facets and cells */
    350:   ISGetLocalSize(fis, &m);
    351:   ISGetIndices(fis, &rows);
    352:   PetscMalloc1(m, &idxs);
    353:   for (i = 0, floc = 0; i < m; i++) {
    354:     const PetscInt p = rows[i];

    356:     if (p < 0) {
    357:       idxs[i] = -(p+1);
    358:     } else {
    359:       idxs[i] = p;
    360:       floc   += 1;
    361:     }
    362:   }
    363:   ISRestoreIndices(fis, &rows);
    364:   ISDestroy(&fis);
    365:   ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis);

    367:   ISGetLocalSize(cis, &m);
    368:   ISGetIndices(cis, &cols);
    369:   PetscMalloc1(m, &idxs);
    370:   PetscMalloc1(m, &idxs2);
    371:   for (i = 0, cloc = 0; i < m; i++) {
    372:     const PetscInt p = cols[i];

    374:     if (p < 0) {
    375:       idxs[i] = -(p+1);
    376:     } else {
    377:       idxs[i]       = p;
    378:       idxs2[cloc++] = p;
    379:     }
    380:   }
    381:   ISRestoreIndices(cis, &cols);
    382:   ISDestroy(&cis);
    383:   ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis);
    384:   ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own);

    386:   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
    387:   MatCreate(PetscObjectComm((PetscObject)dm), &conn);
    388:   MatSetSizes(conn, floc, cloc, M, N);
    389:   MatSetType(conn, MATMPIAIJ);
    390:   DMPlexGetMaxSizes(dm, NULL, &lm);
    391:   MPI_Allreduce(&lm, &m, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm));
    392:   MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL);

    394:   /* Assemble matrix */
    395:   ISGetIndices(fis, &rows);
    396:   ISGetIndices(cis, &cols);
    397:   for (c = cStart; c < cEnd; c++) {
    398:     const PetscInt *cone;
    399:     PetscInt        coneSize, row, col, f;

    401:     col  = cols[c-cStart];
    402:     DMPlexGetCone(dm, c, &cone);
    403:     DMPlexGetConeSize(dm, c, &coneSize);
    404:     for (f = 0; f < coneSize; f++) {
    405:       const PetscScalar v = 1.0;
    406:       const PetscInt *children;
    407:       PetscInt        numChildren, ch;

    409:       row  = rows[cone[f]-fStart];
    410:       MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);

    412:       /* non-conforming meshes */
    413:       DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children);
    414:       for (ch = 0; ch < numChildren; ch++) {
    415:         const PetscInt child = children[ch];

    417:         if (child < fStart || child >= fEnd) continue;
    418:         row  = rows[child-fStart];
    419:         MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);
    420:       }
    421:     }
    422:   }
    423:   ISRestoreIndices(fis, &rows);
    424:   ISRestoreIndices(cis, &cols);
    425:   ISDestroy(&fis);
    426:   ISDestroy(&cis);
    427:   MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY);
    428:   MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY);

    430:   /* Get parallel CSR by doing conn^T * conn */
    431:   MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR);
    432:   MatDestroy(&conn);

    434:   /* extract local part of the CSR */
    435:   MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn);
    436:   MatDestroy(&CSR);
    437:   MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);

    440:   /* get back requested output */
    441:   if (numVertices) *numVertices = m;
    442:   if (offsets) {
    443:     PetscCalloc1(m+1, &idxs);
    444:     for (i = 1; i < m+1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
    445:     *offsets = idxs;
    446:   }
    447:   if (adjacency) {
    448:     PetscMalloc1(ii[m] - m, &idxs);
    449:     ISGetIndices(cis_own, &rows);
    450:     for (i = 0, c = 0; i < m; i++) {
    451:       PetscInt j, g = rows[i];

    453:       for (j = ii[i]; j < ii[i+1]; j++) {
    454:         if (jj[j] == g) continue; /* again, self-connectivity */
    455:         idxs[c++] = jj[j];
    456:       }
    457:     }
    459:     ISRestoreIndices(cis_own, &rows);
    460:     *adjacency = idxs;
    461:   }

    463:   /* cleanup */
    464:   ISDestroy(&cis_own);
    465:   MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);
    467:   MatDestroy(&conn);
    468:   return 0;
    469: }

    471: /*@C
    472:   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner

    474:   Input Parameters:
    475: + dm      - The mesh DM dm
    476: - height  - Height of the strata from which to construct the graph

    478:   Output Parameters:
    479: + numVertices     - Number of vertices in the graph
    480: . offsets         - Point offsets in the graph
    481: . adjacency       - Point connectivity in the graph
    482: - 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:   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
    485:   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().

    487:   Options Database Keys:
    488: . -dm_plex_csr_alg <mat,graph,overlap> - Choose the algorithm for computing the CSR graph

    490:   Level: developer

    492: .seealso: PetscPartitionerGetType(), PetscPartitionerCreate(), DMSetAdjacency()
    493: @*/
    494: PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
    495: {
    496:   DMPlexCSRAlgorithm alg = DM_PLEX_CSR_GRAPH;

    498:   PetscOptionsGetEnum(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_csr_alg", DMPlexCSRAlgorithms, (PetscEnum *) &alg, NULL);
    499:   switch (alg) {
    500:     case DM_PLEX_CSR_MAT:
    501:       DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering);break;
    502:     case DM_PLEX_CSR_GRAPH:
    503:       DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering);break;
    504:     case DM_PLEX_CSR_OVERLAP:
    505:       DMPlexCreatePartitionerGraph_Overlap(dm, height, numVertices, offsets, adjacency, globalNumbering);break;
    506:   }
    507:   return 0;
    508: }

    510: /*@C
    511:   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.

    513:   Collective on DM

    515:   Input Parameters:
    516: + dm - The DMPlex
    517: - cellHeight - The height of mesh points to treat as cells (default should be 0)

    519:   Output Parameters:
    520: + numVertices - The number of local vertices in the graph, or cells in the mesh.
    521: . offsets     - The offset to the adjacency list for each cell
    522: - adjacency   - The adjacency list for all cells

    524:   Note: This is suitable for input to a mesh partitioner like ParMetis.

    526:   Level: advanced

    528: .seealso: DMPlexCreate()
    529: @*/
    530: PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
    531: {
    532:   const PetscInt maxFaceCases = 30;
    533:   PetscInt       numFaceCases = 0;
    534:   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
    535:   PetscInt      *off, *adj;
    536:   PetscInt      *neighborCells = NULL;
    537:   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;

    539:   /* For parallel partitioning, I think you have to communicate supports */
    540:   DMGetDimension(dm, &dim);
    541:   cellDim = dim - cellHeight;
    542:   DMPlexGetDepth(dm, &depth);
    543:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
    544:   if (cEnd - cStart == 0) {
    545:     if (numVertices) *numVertices = 0;
    546:     if (offsets)   *offsets   = NULL;
    547:     if (adjacency) *adjacency = NULL;
    548:     return 0;
    549:   }
    550:   numCells  = cEnd - cStart;
    551:   faceDepth = depth - cellHeight;
    552:   if (dim == depth) {
    553:     PetscInt f, fStart, fEnd;

    555:     PetscCalloc1(numCells+1, &off);
    556:     /* Count neighboring cells */
    557:     DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);
    558:     for (f = fStart; f < fEnd; ++f) {
    559:       const PetscInt *support;
    560:       PetscInt        supportSize;
    561:       DMPlexGetSupportSize(dm, f, &supportSize);
    562:       DMPlexGetSupport(dm, f, &support);
    563:       if (supportSize == 2) {
    564:         PetscInt numChildren;

    566:         DMPlexGetTreeChildren(dm,f,&numChildren,NULL);
    567:         if (!numChildren) {
    568:           ++off[support[0]-cStart+1];
    569:           ++off[support[1]-cStart+1];
    570:         }
    571:       }
    572:     }
    573:     /* Prefix sum */
    574:     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
    575:     if (adjacency) {
    576:       PetscInt *tmp;

    578:       PetscMalloc1(off[numCells], &adj);
    579:       PetscMalloc1(numCells+1, &tmp);
    580:       PetscArraycpy(tmp, off, numCells+1);
    581:       /* Get neighboring cells */
    582:       for (f = fStart; f < fEnd; ++f) {
    583:         const PetscInt *support;
    584:         PetscInt        supportSize;
    585:         DMPlexGetSupportSize(dm, f, &supportSize);
    586:         DMPlexGetSupport(dm, f, &support);
    587:         if (supportSize == 2) {
    588:           PetscInt numChildren;

    590:           DMPlexGetTreeChildren(dm,f,&numChildren,NULL);
    591:           if (!numChildren) {
    592:             adj[tmp[support[0]-cStart]++] = support[1];
    593:             adj[tmp[support[1]-cStart]++] = support[0];
    594:           }
    595:         }
    596:       }
    597:       for (c = 0; c < cEnd-cStart; ++c) PetscAssert(tmp[c] == off[c+1],PETSC_COMM_SELF, PETSC_ERR_PLIB, "Offset %d != %d for cell %d", tmp[c], off[c], c+cStart);
    598:       PetscFree(tmp);
    599:     }
    600:     if (numVertices) *numVertices = numCells;
    601:     if (offsets)   *offsets   = off;
    602:     if (adjacency) *adjacency = adj;
    603:     return 0;
    604:   }
    605:   /* Setup face recognition */
    606:   if (faceDepth == 1) {
    607:     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 */

    609:     for (c = cStart; c < cEnd; ++c) {
    610:       PetscInt corners;

    612:       DMPlexGetConeSize(dm, c, &corners);
    613:       if (!cornersSeen[corners]) {
    614:         PetscInt nFV;

    617:         cornersSeen[corners] = 1;

    619:         DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);

    621:         numFaceVertices[numFaceCases++] = nFV;
    622:       }
    623:     }
    624:   }
    625:   PetscCalloc1(numCells+1, &off);
    626:   /* Count neighboring cells */
    627:   for (cell = cStart; cell < cEnd; ++cell) {
    628:     PetscInt numNeighbors = PETSC_DETERMINE, n;

    630:     DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);
    631:     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
    632:     for (n = 0; n < numNeighbors; ++n) {
    633:       PetscInt        cellPair[2];
    634:       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
    635:       PetscInt        meetSize = 0;
    636:       const PetscInt *meet    = NULL;

    638:       cellPair[0] = cell; cellPair[1] = neighborCells[n];
    639:       if (cellPair[0] == cellPair[1]) continue;
    640:       if (!found) {
    641:         DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);
    642:         if (meetSize) {
    643:           PetscInt f;

    645:           for (f = 0; f < numFaceCases; ++f) {
    646:             if (numFaceVertices[f] == meetSize) {
    647:               found = PETSC_TRUE;
    648:               break;
    649:             }
    650:           }
    651:         }
    652:         DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);
    653:       }
    654:       if (found) ++off[cell-cStart+1];
    655:     }
    656:   }
    657:   /* Prefix sum */
    658:   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];

    660:   if (adjacency) {
    661:     PetscMalloc1(off[numCells], &adj);
    662:     /* Get neighboring cells */
    663:     for (cell = cStart; cell < cEnd; ++cell) {
    664:       PetscInt numNeighbors = PETSC_DETERMINE, n;
    665:       PetscInt cellOffset   = 0;

    667:       DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);
    668:       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
    669:       for (n = 0; n < numNeighbors; ++n) {
    670:         PetscInt        cellPair[2];
    671:         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
    672:         PetscInt        meetSize = 0;
    673:         const PetscInt *meet    = NULL;

    675:         cellPair[0] = cell; cellPair[1] = neighborCells[n];
    676:         if (cellPair[0] == cellPair[1]) continue;
    677:         if (!found) {
    678:           DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);
    679:           if (meetSize) {
    680:             PetscInt f;

    682:             for (f = 0; f < numFaceCases; ++f) {
    683:               if (numFaceVertices[f] == meetSize) {
    684:                 found = PETSC_TRUE;
    685:                 break;
    686:               }
    687:             }
    688:           }
    689:           DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);
    690:         }
    691:         if (found) {
    692:           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
    693:           ++cellOffset;
    694:         }
    695:       }
    696:     }
    697:   }
    698:   PetscFree(neighborCells);
    699:   if (numVertices) *numVertices = numCells;
    700:   if (offsets)   *offsets   = off;
    701:   if (adjacency) *adjacency = adj;
    702:   return 0;
    703: }

    705: /*@
    706:   PetscPartitionerDMPlexPartition - Create a non-overlapping partition of the cells in the mesh

    708:   Collective on PetscPartitioner

    710:   Input Parameters:
    711: + part    - The PetscPartitioner
    712: . targetSection - The PetscSection describing the absolute weight of each partition (can be NULL)
    713: - dm      - The mesh DM

    715:   Output Parameters:
    716: + partSection     - The PetscSection giving the division of points by partition
    717: - partition       - The list of points by partition

    719:   Notes:
    720:     If the DM has a local section associated, each point to be partitioned will be weighted by the total number of dofs identified
    721:     by the section in the transitive closure of the point.

    723:   Level: developer

    725: .seealso DMPlexDistribute(), PetscPartitionerCreate(), PetscSectionCreate(), PetscSectionSetChart(), PetscPartitionerPartition()
    726: @*/
    727: PetscErrorCode PetscPartitionerDMPlexPartition(PetscPartitioner part, DM dm, PetscSection targetSection, PetscSection partSection, IS *partition)
    728: {
    729:   PetscMPIInt    size;
    730:   PetscBool      isplex;
    731:   PetscSection   vertSection = NULL;

    738:   PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isplex);
    740:   MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);
    741:   if (size == 1) {
    742:     PetscInt *points;
    743:     PetscInt  cStart, cEnd, c;

    745:     DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);
    746:     PetscSectionReset(partSection);
    747:     PetscSectionSetChart(partSection, 0, size);
    748:     PetscSectionSetDof(partSection, 0, cEnd-cStart);
    749:     PetscSectionSetUp(partSection);
    750:     PetscMalloc1(cEnd-cStart, &points);
    751:     for (c = cStart; c < cEnd; ++c) points[c] = c;
    752:     ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);
    753:     return 0;
    754:   }
    755:   if (part->height == 0) {
    756:     PetscInt numVertices = 0;
    757:     PetscInt *start     = NULL;
    758:     PetscInt *adjacency = NULL;
    759:     IS       globalNumbering;

    761:     if (!part->noGraph || part->viewGraph) {
    762:       DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering);
    763:     } else { /* only compute the number of owned local vertices */
    764:       const PetscInt *idxs;
    765:       PetscInt       p, pStart, pEnd;

    767:       DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd);
    768:       DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering);
    769:       ISGetIndices(globalNumbering, &idxs);
    770:       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
    771:       ISRestoreIndices(globalNumbering, &idxs);
    772:     }
    773:     if (part->usevwgt) {
    774:       PetscSection   section = dm->localSection, clSection = NULL;
    775:       IS             clPoints = NULL;
    776:       const PetscInt *gid,*clIdx;
    777:       PetscInt       v, p, pStart, pEnd;

    779:       /* 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) */
    780:       /* We do this only if the local section has been set */
    781:       if (section) {
    782:         PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, NULL);
    783:         if (!clSection) {
    784:           DMPlexCreateClosureIndex(dm,NULL);
    785:         }
    786:         PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, &clPoints);
    787:         ISGetIndices(clPoints,&clIdx);
    788:       }
    789:       DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd);
    790:       PetscSectionCreate(PETSC_COMM_SELF, &vertSection);
    791:       PetscSectionSetChart(vertSection, 0, numVertices);
    792:       if (globalNumbering) {
    793:         ISGetIndices(globalNumbering,&gid);
    794:       } else gid = NULL;
    795:       for (p = pStart, v = 0; p < pEnd; ++p) {
    796:         PetscInt dof = 1;

    798:         /* skip cells in the overlap */
    799:         if (gid && gid[p-pStart] < 0) continue;

    801:         if (section) {
    802:           PetscInt cl, clSize, clOff;

    804:           dof  = 0;
    805:           PetscSectionGetDof(clSection, p, &clSize);
    806:           PetscSectionGetOffset(clSection, p, &clOff);
    807:           for (cl = 0; cl < clSize; cl+=2) {
    808:             PetscInt clDof, clPoint = clIdx[clOff + cl]; /* odd indices are reserved for orientations */

    810:             PetscSectionGetDof(section, clPoint, &clDof);
    811:             dof += clDof;
    812:           }
    813:         }
    815:         PetscSectionSetDof(vertSection, v, dof);
    816:         v++;
    817:       }
    818:       if (globalNumbering) {
    819:         ISRestoreIndices(globalNumbering,&gid);
    820:       }
    821:       if (clPoints) {
    822:         ISRestoreIndices(clPoints,&clIdx);
    823:       }
    824:       PetscSectionSetUp(vertSection);
    825:     }
    826:     PetscPartitionerPartition(part, size, numVertices, start, adjacency, vertSection, targetSection, partSection, partition);
    827:     PetscFree(start);
    828:     PetscFree(adjacency);
    829:     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
    830:       const PetscInt *globalNum;
    831:       const PetscInt *partIdx;
    832:       PetscInt       *map, cStart, cEnd;
    833:       PetscInt       *adjusted, i, localSize, offset;
    834:       IS             newPartition;

    836:       ISGetLocalSize(*partition,&localSize);
    837:       PetscMalloc1(localSize,&adjusted);
    838:       ISGetIndices(globalNumbering,&globalNum);
    839:       ISGetIndices(*partition,&partIdx);
    840:       PetscMalloc1(localSize,&map);
    841:       DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);
    842:       for (i = cStart, offset = 0; i < cEnd; i++) {
    843:         if (globalNum[i - cStart] >= 0) map[offset++] = i;
    844:       }
    845:       for (i = 0; i < localSize; i++) {
    846:         adjusted[i] = map[partIdx[i]];
    847:       }
    848:       PetscFree(map);
    849:       ISRestoreIndices(*partition,&partIdx);
    850:       ISRestoreIndices(globalNumbering,&globalNum);
    851:       ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition);
    852:       ISDestroy(&globalNumbering);
    853:       ISDestroy(partition);
    854:       *partition = newPartition;
    855:     }
    856:   } else SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height);
    857:   PetscSectionDestroy(&vertSection);
    858:   return 0;
    859: }

    861: /*@
    862:   DMPlexGetPartitioner - Get the mesh partitioner

    864:   Not collective

    866:   Input Parameter:
    867: . dm - The DM

    869:   Output Parameter:
    870: . part - The PetscPartitioner

    872:   Level: developer

    874:   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.

    876: .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerDMPlexPartition(), PetscPartitionerCreate()
    877: @*/
    878: PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
    879: {
    880:   DM_Plex       *mesh = (DM_Plex *) dm->data;

    884:   *part = mesh->partitioner;
    885:   return 0;
    886: }

    888: /*@
    889:   DMPlexSetPartitioner - Set the mesh partitioner

    891:   logically collective on DM

    893:   Input Parameters:
    894: + dm - The DM
    895: - part - The partitioner

    897:   Level: developer

    899:   Note: Any existing PetscPartitioner will be destroyed.

    901: .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate()
    902: @*/
    903: PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
    904: {
    905:   DM_Plex       *mesh = (DM_Plex *) dm->data;

    909:   PetscObjectReference((PetscObject)part);
    910:   PetscPartitionerDestroy(&mesh->partitioner);
    911:   mesh->partitioner = part;
    912:   return 0;
    913: }

    915: static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point)
    916: {
    917:   const PetscInt *cone;
    918:   PetscInt       coneSize, c;
    919:   PetscBool      missing;

    922:   PetscHSetIQueryAdd(ht, point, &missing);
    923:   if (missing) {
    924:     DMPlexGetCone(dm, point, &cone);
    925:     DMPlexGetConeSize(dm, point, &coneSize);
    926:     for (c = 0; c < coneSize; c++) {
    927:       DMPlexAddClosure_Private(dm, ht, cone[c]);
    928:     }
    929:   }
    930:   return 0;
    931: }

    933: PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
    934: {
    935:   if (up) {
    936:     PetscInt parent;

    938:     DMPlexGetTreeParent(dm,point,&parent,NULL);
    939:     if (parent != point) {
    940:       PetscInt closureSize, *closure = NULL, i;

    942:       DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);
    943:       for (i = 0; i < closureSize; i++) {
    944:         PetscInt cpoint = closure[2*i];

    946:         PetscHSetIAdd(ht, cpoint);
    947:         DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE);
    948:       }
    949:       DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);
    950:     }
    951:   }
    952:   if (down) {
    953:     PetscInt numChildren;
    954:     const PetscInt *children;

    956:     DMPlexGetTreeChildren(dm,point,&numChildren,&children);
    957:     if (numChildren) {
    958:       PetscInt i;

    960:       for (i = 0; i < numChildren; i++) {
    961:         PetscInt cpoint = children[i];

    963:         PetscHSetIAdd(ht, cpoint);
    964:         DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE);
    965:       }
    966:     }
    967:   }
    968:   return 0;
    969: }

    971: static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point)
    972: {
    973:   PetscInt       parent;

    976:   DMPlexGetTreeParent(dm, point, &parent,NULL);
    977:   if (point != parent) {
    978:     const PetscInt *cone;
    979:     PetscInt       coneSize, c;

    981:     DMPlexAddClosureTree_Up_Private(dm, ht, parent);
    982:     DMPlexAddClosure_Private(dm, ht, parent);
    983:     DMPlexGetCone(dm, parent, &cone);
    984:     DMPlexGetConeSize(dm, parent, &coneSize);
    985:     for (c = 0; c < coneSize; c++) {
    986:       const PetscInt cp = cone[c];

    988:       DMPlexAddClosureTree_Up_Private(dm, ht, cp);
    989:     }
    990:   }
    991:   return 0;
    992: }

    994: static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point)
    995: {
    996:   PetscInt       i, numChildren;
    997:   const PetscInt *children;

    1000:   DMPlexGetTreeChildren(dm, point, &numChildren, &children);
    1001:   for (i = 0; i < numChildren; i++) {
    1002:     PetscHSetIAdd(ht, children[i]);
    1003:   }
    1004:   return 0;
    1005: }

    1007: static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point)
    1008: {
    1009:   const PetscInt *cone;
    1010:   PetscInt       coneSize, c;

    1013:   PetscHSetIAdd(ht, point);
    1014:   DMPlexAddClosureTree_Up_Private(dm, ht, point);
    1015:   DMPlexAddClosureTree_Down_Private(dm, ht, point);
    1016:   DMPlexGetCone(dm, point, &cone);
    1017:   DMPlexGetConeSize(dm, point, &coneSize);
    1018:   for (c = 0; c < coneSize; c++) {
    1019:     DMPlexAddClosureTree_Private(dm, ht, cone[c]);
    1020:   }
    1021:   return 0;
    1022: }

    1024: PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS)
    1025: {
    1026:   DM_Plex         *mesh = (DM_Plex *)dm->data;
    1027:   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
    1028:   PetscInt        nelems, *elems, off = 0, p;
    1029:   PetscHSetI      ht = NULL;

    1031:   PetscHSetICreate(&ht);
    1032:   PetscHSetIResize(ht, numPoints*16);
    1033:   if (!hasTree) {
    1034:     for (p = 0; p < numPoints; ++p) {
    1035:       DMPlexAddClosure_Private(dm, ht, points[p]);
    1036:     }
    1037:   } else {
    1038: #if 1
    1039:     for (p = 0; p < numPoints; ++p) {
    1040:       DMPlexAddClosureTree_Private(dm, ht, points[p]);
    1041:     }
    1042: #else
    1043:     PetscInt  *closure = NULL, closureSize, c;
    1044:     for (p = 0; p < numPoints; ++p) {
    1045:       DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);
    1046:       for (c = 0; c < closureSize*2; c += 2) {
    1047:         PetscHSetIAdd(ht, closure[c]);
    1048:         if (hasTree) DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE);
    1049:       }
    1050:     }
    1051:     if (closure) DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure);
    1052: #endif
    1053:   }
    1054:   PetscHSetIGetSize(ht, &nelems);
    1055:   PetscMalloc1(nelems, &elems);
    1056:   PetscHSetIGetElems(ht, &off, elems);
    1057:   PetscHSetIDestroy(&ht);
    1058:   PetscSortInt(nelems, elems);
    1059:   ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS);
    1060:   return 0;
    1061: }

    1063: /*@
    1064:   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label

    1066:   Input Parameters:
    1067: + dm     - The DM
    1068: - label  - DMLabel assigning ranks to remote roots

    1070:   Level: developer

    1072: .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
    1073: @*/
    1074: PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
    1075: {
    1076:   IS              rankIS,   pointIS, closureIS;
    1077:   const PetscInt *ranks,   *points;
    1078:   PetscInt        numRanks, numPoints, r;

    1080:   DMLabelGetValueIS(label, &rankIS);
    1081:   ISGetLocalSize(rankIS, &numRanks);
    1082:   ISGetIndices(rankIS, &ranks);
    1083:   for (r = 0; r < numRanks; ++r) {
    1084:     const PetscInt rank = ranks[r];
    1085:     DMLabelGetStratumIS(label, rank, &pointIS);
    1086:     ISGetLocalSize(pointIS, &numPoints);
    1087:     ISGetIndices(pointIS, &points);
    1088:     DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS);
    1089:     ISRestoreIndices(pointIS, &points);
    1090:     ISDestroy(&pointIS);
    1091:     DMLabelSetStratumIS(label, rank, closureIS);
    1092:     ISDestroy(&closureIS);
    1093:   }
    1094:   ISRestoreIndices(rankIS, &ranks);
    1095:   ISDestroy(&rankIS);
    1096:   return 0;
    1097: }

    1099: /*@
    1100:   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label

    1102:   Input Parameters:
    1103: + dm     - The DM
    1104: - label  - DMLabel assigning ranks to remote roots

    1106:   Level: developer

    1108: .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
    1109: @*/
    1110: PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
    1111: {
    1112:   IS              rankIS,   pointIS;
    1113:   const PetscInt *ranks,   *points;
    1114:   PetscInt        numRanks, numPoints, r, p, a, adjSize;
    1115:   PetscInt       *adj = NULL;

    1117:   DMLabelGetValueIS(label, &rankIS);
    1118:   ISGetLocalSize(rankIS, &numRanks);
    1119:   ISGetIndices(rankIS, &ranks);
    1120:   for (r = 0; r < numRanks; ++r) {
    1121:     const PetscInt rank = ranks[r];

    1123:     DMLabelGetStratumIS(label, rank, &pointIS);
    1124:     ISGetLocalSize(pointIS, &numPoints);
    1125:     ISGetIndices(pointIS, &points);
    1126:     for (p = 0; p < numPoints; ++p) {
    1127:       adjSize = PETSC_DETERMINE;
    1128:       DMPlexGetAdjacency(dm, points[p], &adjSize, &adj);
    1129:       for (a = 0; a < adjSize; ++a) DMLabelSetValue(label, adj[a], rank);
    1130:     }
    1131:     ISRestoreIndices(pointIS, &points);
    1132:     ISDestroy(&pointIS);
    1133:   }
    1134:   ISRestoreIndices(rankIS, &ranks);
    1135:   ISDestroy(&rankIS);
    1136:   PetscFree(adj);
    1137:   return 0;
    1138: }

    1140: /*@
    1141:   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF

    1143:   Input Parameters:
    1144: + dm     - The DM
    1145: - label  - DMLabel assigning ranks to remote roots

    1147:   Level: developer

    1149:   Note: This is required when generating multi-level overlaps to capture
    1150:   overlap points from non-neighbouring partitions.

    1152: .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
    1153: @*/
    1154: PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
    1155: {
    1156:   MPI_Comm        comm;
    1157:   PetscMPIInt     rank;
    1158:   PetscSF         sfPoint;
    1159:   DMLabel         lblRoots, lblLeaves;
    1160:   IS              rankIS, pointIS;
    1161:   const PetscInt *ranks;
    1162:   PetscInt        numRanks, r;

    1164:   PetscObjectGetComm((PetscObject) dm, &comm);
    1165:   MPI_Comm_rank(comm, &rank);
    1166:   DMGetPointSF(dm, &sfPoint);
    1167:   /* Pull point contributions from remote leaves into local roots */
    1168:   DMLabelGather(label, sfPoint, &lblLeaves);
    1169:   DMLabelGetValueIS(lblLeaves, &rankIS);
    1170:   ISGetLocalSize(rankIS, &numRanks);
    1171:   ISGetIndices(rankIS, &ranks);
    1172:   for (r = 0; r < numRanks; ++r) {
    1173:     const PetscInt remoteRank = ranks[r];
    1174:     if (remoteRank == rank) continue;
    1175:     DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS);
    1176:     DMLabelInsertIS(label, pointIS, remoteRank);
    1177:     ISDestroy(&pointIS);
    1178:   }
    1179:   ISRestoreIndices(rankIS, &ranks);
    1180:   ISDestroy(&rankIS);
    1181:   DMLabelDestroy(&lblLeaves);
    1182:   /* Push point contributions from roots into remote leaves */
    1183:   DMLabelDistribute(label, sfPoint, &lblRoots);
    1184:   DMLabelGetValueIS(lblRoots, &rankIS);
    1185:   ISGetLocalSize(rankIS, &numRanks);
    1186:   ISGetIndices(rankIS, &ranks);
    1187:   for (r = 0; r < numRanks; ++r) {
    1188:     const PetscInt remoteRank = ranks[r];
    1189:     if (remoteRank == rank) continue;
    1190:     DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS);
    1191:     DMLabelInsertIS(label, pointIS, remoteRank);
    1192:     ISDestroy(&pointIS);
    1193:   }
    1194:   ISRestoreIndices(rankIS, &ranks);
    1195:   ISDestroy(&rankIS);
    1196:   DMLabelDestroy(&lblRoots);
    1197:   return 0;
    1198: }

    1200: /*@
    1201:   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label

    1203:   Input Parameters:
    1204: + dm        - The DM
    1205: . rootLabel - DMLabel assigning ranks to local roots
    1206: - processSF - A star forest mapping into the local index on each remote rank

    1208:   Output Parameter:
    1209: . leafLabel - DMLabel assigning ranks to remote roots

    1211:   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
    1212:   resulting leafLabel is a receiver mapping of remote roots to their parent rank.

    1214:   Level: developer

    1216: .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
    1217: @*/
    1218: PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
    1219: {
    1220:   MPI_Comm           comm;
    1221:   PetscMPIInt        rank, size, r;
    1222:   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
    1223:   PetscSF            sfPoint;
    1224:   PetscSection       rootSection;
    1225:   PetscSFNode       *rootPoints, *leafPoints;
    1226:   const PetscSFNode *remote;
    1227:   const PetscInt    *local, *neighbors;
    1228:   IS                 valueIS;
    1229:   PetscBool          mpiOverflow = PETSC_FALSE;

    1231:   PetscLogEventBegin(DMPLEX_PartLabelInvert,dm,0,0,0);
    1232:   PetscObjectGetComm((PetscObject) dm, &comm);
    1233:   MPI_Comm_rank(comm, &rank);
    1234:   MPI_Comm_size(comm, &size);
    1235:   DMGetPointSF(dm, &sfPoint);

    1237:   /* Convert to (point, rank) and use actual owners */
    1238:   PetscSectionCreate(comm, &rootSection);
    1239:   PetscSectionSetChart(rootSection, 0, size);
    1240:   DMLabelGetValueIS(rootLabel, &valueIS);
    1241:   ISGetLocalSize(valueIS, &numNeighbors);
    1242:   ISGetIndices(valueIS, &neighbors);
    1243:   for (n = 0; n < numNeighbors; ++n) {
    1244:     DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints);
    1245:     PetscSectionAddDof(rootSection, neighbors[n], numPoints);
    1246:   }
    1247:   PetscSectionSetUp(rootSection);
    1248:   PetscSectionGetStorageSize(rootSection, &rootSize);
    1249:   PetscMalloc1(rootSize, &rootPoints);
    1250:   PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote);
    1251:   for (n = 0; n < numNeighbors; ++n) {
    1252:     IS              pointIS;
    1253:     const PetscInt *points;

    1255:     PetscSectionGetOffset(rootSection, neighbors[n], &off);
    1256:     DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS);
    1257:     ISGetLocalSize(pointIS, &numPoints);
    1258:     ISGetIndices(pointIS, &points);
    1259:     for (p = 0; p < numPoints; ++p) {
    1260:       if (local) PetscFindInt(points[p], nleaves, local, &l);
    1261:       else       {l = -1;}
    1262:       if (l >= 0) {rootPoints[off+p] = remote[l];}
    1263:       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
    1264:     }
    1265:     ISRestoreIndices(pointIS, &points);
    1266:     ISDestroy(&pointIS);
    1267:   }

    1269:   /* Try to communicate overlap using All-to-All */
    1270:   if (!processSF) {
    1271:     PetscInt64  counter = 0;
    1272:     PetscBool   locOverflow = PETSC_FALSE;
    1273:     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;

    1275:     PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls);
    1276:     for (n = 0; n < numNeighbors; ++n) {
    1277:       PetscSectionGetDof(rootSection, neighbors[n], &dof);
    1278:       PetscSectionGetOffset(rootSection, neighbors[n], &off);
    1279: #if defined(PETSC_USE_64BIT_INDICES)
    1280:       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
    1281:       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
    1282: #endif
    1283:       scounts[neighbors[n]] = (PetscMPIInt) dof;
    1284:       sdispls[neighbors[n]] = (PetscMPIInt) off;
    1285:     }
    1286:     MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm);
    1287:     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
    1288:     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
    1289:     MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm);
    1290:     if (!mpiOverflow) {
    1291:       PetscInfo(dm,"Using Alltoallv for mesh distribution\n");
    1292:       leafSize = (PetscInt) counter;
    1293:       PetscMalloc1(leafSize, &leafPoints);
    1294:       MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm);
    1295:     }
    1296:     PetscFree4(scounts, sdispls, rcounts, rdispls);
    1297:   }

    1299:   /* Communicate overlap using process star forest */
    1300:   if (processSF || mpiOverflow) {
    1301:     PetscSF      procSF;
    1302:     PetscSection leafSection;

    1304:     if (processSF) {
    1305:       PetscInfo(dm,"Using processSF for mesh distribution\n");
    1306:       PetscObjectReference((PetscObject)processSF);
    1307:       procSF = processSF;
    1308:     } else {
    1309:       PetscInfo(dm,"Using processSF for mesh distribution (MPI overflow)\n");
    1310:       PetscSFCreate(comm,&procSF);
    1311:       PetscSFSetGraphWithPattern(procSF,NULL,PETSCSF_PATTERN_ALLTOALL);
    1312:     }

    1314:     PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection);
    1315:     DMPlexDistributeData(dm, procSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints);
    1316:     PetscSectionGetStorageSize(leafSection, &leafSize);
    1317:     PetscSectionDestroy(&leafSection);
    1318:     PetscSFDestroy(&procSF);
    1319:   }

    1321:   for (p = 0; p < leafSize; p++) {
    1322:     DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank);
    1323:   }

    1325:   ISRestoreIndices(valueIS, &neighbors);
    1326:   ISDestroy(&valueIS);
    1327:   PetscSectionDestroy(&rootSection);
    1328:   PetscFree(rootPoints);
    1329:   PetscFree(leafPoints);
    1330:   PetscLogEventEnd(DMPLEX_PartLabelInvert,dm,0,0,0);
    1331:   return 0;
    1332: }

    1334: /*@
    1335:   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points

    1337:   Input Parameters:
    1338: + dm    - The DM
    1339: - label - DMLabel assigning ranks to remote roots

    1341:   Output Parameter:
    1342: . sf    - The star forest communication context encapsulating the defined mapping

    1344:   Note: The incoming label is a receiver mapping of remote points to their parent rank.

    1346:   Level: developer

    1348: .seealso: DMPlexDistribute(), DMPlexCreateOverlap()
    1349: @*/
    1350: PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
    1351: {
    1352:   PetscMPIInt     rank;
    1353:   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
    1354:   PetscSFNode    *remotePoints;
    1355:   IS              remoteRootIS, neighborsIS;
    1356:   const PetscInt *remoteRoots, *neighbors;

    1358:   PetscLogEventBegin(DMPLEX_PartLabelCreateSF,dm,0,0,0);
    1359:   MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);

    1361:   DMLabelGetValueIS(label, &neighborsIS);
    1362: #if 0
    1363:   {
    1364:     IS is;
    1365:     ISDuplicate(neighborsIS, &is);
    1366:     ISSort(is);
    1367:     ISDestroy(&neighborsIS);
    1368:     neighborsIS = is;
    1369:   }
    1370: #endif
    1371:   ISGetLocalSize(neighborsIS, &nNeighbors);
    1372:   ISGetIndices(neighborsIS, &neighbors);
    1373:   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
    1374:     DMLabelGetStratumSize(label, neighbors[n], &numPoints);
    1375:     numRemote += numPoints;
    1376:   }
    1377:   PetscMalloc1(numRemote, &remotePoints);
    1378:   /* Put owned points first */
    1379:   DMLabelGetStratumSize(label, rank, &numPoints);
    1380:   if (numPoints > 0) {
    1381:     DMLabelGetStratumIS(label, rank, &remoteRootIS);
    1382:     ISGetIndices(remoteRootIS, &remoteRoots);
    1383:     for (p = 0; p < numPoints; p++) {
    1384:       remotePoints[idx].index = remoteRoots[p];
    1385:       remotePoints[idx].rank = rank;
    1386:       idx++;
    1387:     }
    1388:     ISRestoreIndices(remoteRootIS, &remoteRoots);
    1389:     ISDestroy(&remoteRootIS);
    1390:   }
    1391:   /* Now add remote points */
    1392:   for (n = 0; n < nNeighbors; ++n) {
    1393:     const PetscInt nn = neighbors[n];

    1395:     DMLabelGetStratumSize(label, nn, &numPoints);
    1396:     if (nn == rank || numPoints <= 0) continue;
    1397:     DMLabelGetStratumIS(label, nn, &remoteRootIS);
    1398:     ISGetIndices(remoteRootIS, &remoteRoots);
    1399:     for (p = 0; p < numPoints; p++) {
    1400:       remotePoints[idx].index = remoteRoots[p];
    1401:       remotePoints[idx].rank = nn;
    1402:       idx++;
    1403:     }
    1404:     ISRestoreIndices(remoteRootIS, &remoteRoots);
    1405:     ISDestroy(&remoteRootIS);
    1406:   }
    1407:   PetscSFCreate(PetscObjectComm((PetscObject) dm), sf);
    1408:   DMPlexGetChart(dm, &pStart, &pEnd);
    1409:   PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);
    1410:   PetscSFSetUp(*sf);
    1411:   ISDestroy(&neighborsIS);
    1412:   PetscLogEventEnd(DMPLEX_PartLabelCreateSF,dm,0,0,0);
    1413:   return 0;
    1414: }

    1416: #if defined(PETSC_HAVE_PARMETIS)
    1417: #include <parmetis.h>
    1418: #endif

    1420: /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
    1421:  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
    1422:  * them out in that case. */
    1423: #if defined(PETSC_HAVE_PARMETIS)
    1424: /*@C

    1426:   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).

    1428:   Input parameters:
    1429: + dm                - The DMPlex object.
    1430: . n                 - The number of points.
    1431: . pointsToRewrite   - The points in the SF whose ownership will change.
    1432: . targetOwners      - New owner for each element in pointsToRewrite.
    1433: - degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.

    1435:   Level: developer

    1437: @*/
    1438: static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
    1439: {
    1440:   PetscInt      pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
    1441:   PetscInt     *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
    1442:   PetscSFNode  *leafLocationsNew;
    1443:   const         PetscSFNode *iremote;
    1444:   const         PetscInt *ilocal;
    1445:   PetscBool    *isLeaf;
    1446:   PetscSF       sf;
    1447:   MPI_Comm      comm;
    1448:   PetscMPIInt   rank, size;

    1450:   PetscObjectGetComm((PetscObject) dm, &comm);
    1451:   MPI_Comm_rank(comm, &rank);
    1452:   MPI_Comm_size(comm, &size);
    1453:   DMPlexGetChart(dm, &pStart, &pEnd);

    1455:   DMGetPointSF(dm, &sf);
    1456:   PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote);
    1457:   PetscMalloc1(pEnd-pStart, &isLeaf);
    1458:   for (i=0; i<pEnd-pStart; i++) {
    1459:     isLeaf[i] = PETSC_FALSE;
    1460:   }
    1461:   for (i=0; i<nleafs; i++) {
    1462:     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
    1463:   }

    1465:   PetscMalloc1(pEnd-pStart+1, &cumSumDegrees);
    1466:   cumSumDegrees[0] = 0;
    1467:   for (i=1; i<=pEnd-pStart; i++) {
    1468:     cumSumDegrees[i] = cumSumDegrees[i-1] + degrees[i-1];
    1469:   }
    1470:   sumDegrees = cumSumDegrees[pEnd-pStart];
    1471:   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */

    1473:   PetscMalloc1(sumDegrees, &locationsOfLeafs);
    1474:   PetscMalloc1(pEnd-pStart, &rankOnLeafs);
    1475:   for (i=0; i<pEnd-pStart; i++) {
    1476:     rankOnLeafs[i] = rank;
    1477:   }
    1478:   PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);
    1479:   PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);
    1480:   PetscFree(rankOnLeafs);

    1482:   /* get the remote local points of my leaves */
    1483:   PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs);
    1484:   PetscMalloc1(pEnd-pStart, &points);
    1485:   for (i=0; i<pEnd-pStart; i++) {
    1486:     points[i] = pStart+i;
    1487:   }
    1488:   PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs);
    1489:   PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs);
    1490:   PetscFree(points);
    1491:   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
    1492:   PetscMalloc1(pEnd-pStart, &newOwners);
    1493:   PetscMalloc1(pEnd-pStart, &newNumbers);
    1494:   for (i=0; i<pEnd-pStart; i++) {
    1495:     newOwners[i] = -1;
    1496:     newNumbers[i] = -1;
    1497:   }
    1498:   {
    1499:     PetscInt oldNumber, newNumber, oldOwner, newOwner;
    1500:     for (i=0; i<n; i++) {
    1501:       oldNumber = pointsToRewrite[i];
    1502:       newNumber = -1;
    1503:       oldOwner = rank;
    1504:       newOwner = targetOwners[i];
    1505:       if (oldOwner == newOwner) {
    1506:         newNumber = oldNumber;
    1507:       } else {
    1508:         for (j=0; j<degrees[oldNumber]; j++) {
    1509:           if (locationsOfLeafs[cumSumDegrees[oldNumber]+j] == newOwner) {
    1510:             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber]+j];
    1511:             break;
    1512:           }
    1513:         }
    1514:       }

    1517:       newOwners[oldNumber] = newOwner;
    1518:       newNumbers[oldNumber] = newNumber;
    1519:     }
    1520:   }
    1521:   PetscFree(cumSumDegrees);
    1522:   PetscFree(locationsOfLeafs);
    1523:   PetscFree(remoteLocalPointOfLeafs);

    1525:   PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners,MPI_REPLACE);
    1526:   PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners,MPI_REPLACE);
    1527:   PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers,MPI_REPLACE);
    1528:   PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers,MPI_REPLACE);

    1530:   /* Now count how many leafs we have on each processor. */
    1531:   leafCounter=0;
    1532:   for (i=0; i<pEnd-pStart; i++) {
    1533:     if (newOwners[i] >= 0) {
    1534:       if (newOwners[i] != rank) {
    1535:         leafCounter++;
    1536:       }
    1537:     } else {
    1538:       if (isLeaf[i]) {
    1539:         leafCounter++;
    1540:       }
    1541:     }
    1542:   }

    1544:   /* Now set up the new sf by creating the leaf arrays */
    1545:   PetscMalloc1(leafCounter, &leafsNew);
    1546:   PetscMalloc1(leafCounter, &leafLocationsNew);

    1548:   leafCounter = 0;
    1549:   counter = 0;
    1550:   for (i=0; i<pEnd-pStart; i++) {
    1551:     if (newOwners[i] >= 0) {
    1552:       if (newOwners[i] != rank) {
    1553:         leafsNew[leafCounter] = i;
    1554:         leafLocationsNew[leafCounter].rank = newOwners[i];
    1555:         leafLocationsNew[leafCounter].index = newNumbers[i];
    1556:         leafCounter++;
    1557:       }
    1558:     } else {
    1559:       if (isLeaf[i]) {
    1560:         leafsNew[leafCounter] = i;
    1561:         leafLocationsNew[leafCounter].rank = iremote[counter].rank;
    1562:         leafLocationsNew[leafCounter].index = iremote[counter].index;
    1563:         leafCounter++;
    1564:       }
    1565:     }
    1566:     if (isLeaf[i]) {
    1567:       counter++;
    1568:     }
    1569:   }

    1571:   PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER);
    1572:   PetscFree(newOwners);
    1573:   PetscFree(newNumbers);
    1574:   PetscFree(isLeaf);
    1575:   return 0;
    1576: }

    1578: static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
    1579: {
    1580:   PetscInt    *distribution, min, max, sum;
    1581:   PetscMPIInt rank, size;

    1583:   MPI_Comm_size(comm, &size);
    1584:   MPI_Comm_rank(comm, &rank);
    1585:   PetscCalloc1(size, &distribution);
    1586:   for (PetscInt i=0; i<n; i++) {
    1587:     if (part) distribution[part[i]] += vtxwgt[skip*i];
    1588:     else distribution[rank] += vtxwgt[skip*i];
    1589:   }
    1590:   MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm);
    1591:   min = distribution[0];
    1592:   max = distribution[0];
    1593:   sum = distribution[0];
    1594:   for (PetscInt i=1; i<size; i++) {
    1595:     if (distribution[i]<min) min=distribution[i];
    1596:     if (distribution[i]>max) max=distribution[i];
    1597:     sum += distribution[i];
    1598:   }
    1599:   PetscViewerASCIIPrintf(viewer, "Min: %D, Avg: %D, Max: %D, Balance: %f\n", min, sum/size, max, (max*1.*size)/sum);
    1600:   PetscFree(distribution);
    1601:   return 0;
    1602: }

    1604: #endif

    1606: /*@
    1607:   DMPlexRebalanceSharedPoints - Redistribute points in the plex that are shared in order to achieve better balancing. This routine updates the PointSF of the DM inplace.

    1609:   Input parameters:
    1610: + dm               - The DMPlex object.
    1611: . entityDepth      - depth of the entity to balance (0 -> balance vertices).
    1612: . useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
    1613: - parallel         - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.

    1615:   Output parameters:
    1616: . success          - whether the graph partitioning was successful or not. If not, try useInitialGuess=True and parallel=True.

    1618:   Level: intermediate

    1620: @*/

    1622: PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
    1623: {
    1624: #if defined(PETSC_HAVE_PARMETIS)
    1625:   PetscSF     sf;
    1626:   PetscInt    ierr, i, j, idx, jdx;
    1627:   PetscInt    eBegin, eEnd, nroots, nleafs, pStart, pEnd;
    1628:   const       PetscInt *degrees, *ilocal;
    1629:   const       PetscSFNode *iremote;
    1630:   PetscBool   *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
    1631:   PetscInt    numExclusivelyOwned, numNonExclusivelyOwned;
    1632:   PetscMPIInt rank, size;
    1633:   PetscInt    *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
    1634:   const       PetscInt *cumSumVertices;
    1635:   PetscInt    offset, counter;
    1636:   PetscInt    lenadjncy;
    1637:   PetscInt    *xadj, *adjncy, *vtxwgt;
    1638:   PetscInt    lenxadj;
    1639:   PetscInt    *adjwgt = NULL;
    1640:   PetscInt    *part, *options;
    1641:   PetscInt    nparts, wgtflag, numflag, ncon, edgecut;
    1642:   real_t      *ubvec;
    1643:   PetscInt    *firstVertices, *renumbering;
    1644:   PetscInt    failed, failedGlobal;
    1645:   MPI_Comm    comm;
    1646:   Mat         A, Apre;
    1647:   const char *prefix = NULL;
    1648:   PetscViewer       viewer;
    1649:   PetscViewerFormat format;
    1650:   PetscLayout layout;

    1652:   if (success) *success = PETSC_FALSE;
    1653:   PetscObjectGetComm((PetscObject) dm, &comm);
    1654:   MPI_Comm_rank(comm, &rank);
    1655:   MPI_Comm_size(comm, &size);
    1656:   if (size==1) return 0;

    1658:   PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);

    1660:   PetscOptionsGetViewer(comm,((PetscObject)dm)->options, prefix,"-dm_rebalance_partition_view",&viewer,&format,NULL);
    1661:   if (viewer) {
    1662:     PetscViewerPushFormat(viewer,format);
    1663:   }

    1665:   /* Figure out all points in the plex that we are interested in balancing. */
    1666:   DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd);
    1667:   DMPlexGetChart(dm, &pStart, &pEnd);
    1668:   PetscMalloc1(pEnd-pStart, &toBalance);

    1670:   for (i=0; i<pEnd-pStart; i++) {
    1671:     toBalance[i] = (PetscBool)(i-pStart>=eBegin && i-pStart<eEnd);
    1672:   }

    1674:   /* There are three types of points:
    1675:    * exclusivelyOwned: points that are owned by this process and only seen by this process
    1676:    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
    1677:    * leaf: a point that is seen by this process but owned by a different process
    1678:    */
    1679:   DMGetPointSF(dm, &sf);
    1680:   PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote);
    1681:   PetscMalloc1(pEnd-pStart, &isLeaf);
    1682:   PetscMalloc1(pEnd-pStart, &isNonExclusivelyOwned);
    1683:   PetscMalloc1(pEnd-pStart, &isExclusivelyOwned);
    1684:   for (i=0; i<pEnd-pStart; i++) {
    1685:     isNonExclusivelyOwned[i] = PETSC_FALSE;
    1686:     isExclusivelyOwned[i] = PETSC_FALSE;
    1687:     isLeaf[i] = PETSC_FALSE;
    1688:   }

    1690:   /* start by marking all the leafs */
    1691:   for (i=0; i<nleafs; i++) {
    1692:     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
    1693:   }

    1695:   /* for an owned point, we can figure out whether another processor sees it or
    1696:    * not by calculating its degree */
    1697:   PetscSFComputeDegreeBegin(sf, &degrees);
    1698:   PetscSFComputeDegreeEnd(sf, &degrees);

    1700:   numExclusivelyOwned = 0;
    1701:   numNonExclusivelyOwned = 0;
    1702:   for (i=0; i<pEnd-pStart; i++) {
    1703:     if (toBalance[i]) {
    1704:       if (degrees[i] > 0) {
    1705:         isNonExclusivelyOwned[i] = PETSC_TRUE;
    1706:         numNonExclusivelyOwned += 1;
    1707:       } else {
    1708:         if (!isLeaf[i]) {
    1709:           isExclusivelyOwned[i] = PETSC_TRUE;
    1710:           numExclusivelyOwned += 1;
    1711:         }
    1712:       }
    1713:     }
    1714:   }

    1716:   /* We are going to build a graph with one vertex per core representing the
    1717:    * exclusively owned points and then one vertex per nonExclusively owned
    1718:    * point. */

    1720:   PetscLayoutCreate(comm, &layout);
    1721:   PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned);
    1722:   PetscLayoutSetUp(layout);
    1723:   PetscLayoutGetRanges(layout, &cumSumVertices);

    1725:   PetscMalloc1(pEnd-pStart, &globalNumbersOfLocalOwnedVertices);
    1726:   for (i=0; i<pEnd-pStart; i++) {globalNumbersOfLocalOwnedVertices[i] = pStart - 1;}
    1727:   offset = cumSumVertices[rank];
    1728:   counter = 0;
    1729:   for (i=0; i<pEnd-pStart; i++) {
    1730:     if (toBalance[i]) {
    1731:       if (degrees[i] > 0) {
    1732:         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
    1733:         counter++;
    1734:       }
    1735:     }
    1736:   }

    1738:   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
    1739:   PetscMalloc1(pEnd-pStart, &leafGlobalNumbers);
    1740:   PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers,MPI_REPLACE);
    1741:   PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers,MPI_REPLACE);

    1743:   /* Now start building the data structure for ParMETIS */

    1745:   MatCreate(comm, &Apre);
    1746:   MatSetType(Apre, MATPREALLOCATOR);
    1747:   MatSetSizes(Apre, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);
    1748:   MatSetUp(Apre);

    1750:   for (i=0; i<pEnd-pStart; i++) {
    1751:     if (toBalance[i]) {
    1752:       idx = cumSumVertices[rank];
    1753:       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
    1754:       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
    1755:       else continue;
    1756:       MatSetValue(Apre, idx, jdx, 1, INSERT_VALUES);
    1757:       MatSetValue(Apre, jdx, idx, 1, INSERT_VALUES);
    1758:     }
    1759:   }

    1761:   MatAssemblyBegin(Apre, MAT_FINAL_ASSEMBLY);
    1762:   MatAssemblyEnd(Apre, MAT_FINAL_ASSEMBLY);

    1764:   MatCreate(comm, &A);
    1765:   MatSetType(A, MATMPIAIJ);
    1766:   MatSetSizes(A, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);
    1767:   MatPreallocatorPreallocate(Apre, PETSC_FALSE, A);
    1768:   MatDestroy(&Apre);

    1770:   for (i=0; i<pEnd-pStart; i++) {
    1771:     if (toBalance[i]) {
    1772:       idx = cumSumVertices[rank];
    1773:       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
    1774:       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
    1775:       else continue;
    1776:       MatSetValue(A, idx, jdx, 1, INSERT_VALUES);
    1777:       MatSetValue(A, jdx, idx, 1, INSERT_VALUES);
    1778:     }
    1779:   }

    1781:   MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);
    1782:   MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);
    1783:   PetscFree(leafGlobalNumbers);
    1784:   PetscFree(globalNumbersOfLocalOwnedVertices);

    1786:   nparts = size;
    1787:   wgtflag = 2;
    1788:   numflag = 0;
    1789:   ncon = 2;
    1790:   real_t *tpwgts;
    1791:   PetscMalloc1(ncon * nparts, &tpwgts);
    1792:   for (i=0; i<ncon*nparts; i++) {
    1793:     tpwgts[i] = 1./(nparts);
    1794:   }

    1796:   PetscMalloc1(ncon, &ubvec);
    1797:   ubvec[0] = 1.01;
    1798:   ubvec[1] = 1.01;
    1799:   lenadjncy = 0;
    1800:   for (i=0; i<1+numNonExclusivelyOwned; i++) {
    1801:     PetscInt temp=0;
    1802:     MatGetRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);
    1803:     lenadjncy += temp;
    1804:     MatRestoreRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);
    1805:   }
    1806:   PetscMalloc1(lenadjncy, &adjncy);
    1807:   lenxadj = 2 + numNonExclusivelyOwned;
    1808:   PetscMalloc1(lenxadj, &xadj);
    1809:   xadj[0] = 0;
    1810:   counter = 0;
    1811:   for (i=0; i<1+numNonExclusivelyOwned; i++) {
    1812:     PetscInt        temp=0;
    1813:     const PetscInt *cols;
    1814:     MatGetRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);
    1815:     PetscArraycpy(&adjncy[counter], cols, temp);
    1816:     counter += temp;
    1817:     xadj[i+1] = counter;
    1818:     MatRestoreRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);
    1819:   }

    1821:   PetscMalloc1(cumSumVertices[rank+1]-cumSumVertices[rank], &part);
    1822:   PetscMalloc1(ncon*(1 + numNonExclusivelyOwned), &vtxwgt);
    1823:   vtxwgt[0] = numExclusivelyOwned;
    1824:   if (ncon>1) vtxwgt[1] = 1;
    1825:   for (i=0; i<numNonExclusivelyOwned; i++) {
    1826:     vtxwgt[ncon*(i+1)] = 1;
    1827:     if (ncon>1) vtxwgt[ncon*(i+1)+1] = 0;
    1828:   }

    1830:   if (viewer) {
    1831:     PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %D on interface of mesh distribution.\n", entityDepth);
    1832:     PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %D\n", cumSumVertices[size]);
    1833:   }
    1834:   if (parallel) {
    1835:     PetscMalloc1(4, &options);
    1836:     options[0] = 1;
    1837:     options[1] = 0; /* Verbosity */
    1838:     options[2] = 0; /* Seed */
    1839:     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
    1840:     if (viewer) PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n");
    1841:     if (useInitialGuess) {
    1842:       if (viewer) PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n");
    1843:       PetscStackPush("ParMETIS_V3_RefineKway");
    1844:       ParMETIS_V3_RefineKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
    1846:       PetscStackPop;
    1847:     } else {
    1848:       PetscStackPush("ParMETIS_V3_PartKway");
    1849:       ParMETIS_V3_PartKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
    1850:       PetscStackPop;
    1852:     }
    1853:     PetscFree(options);
    1854:   } else {
    1855:     if (viewer) PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n");
    1856:     Mat As;
    1857:     PetscInt numRows;
    1858:     PetscInt *partGlobal;
    1859:     MatCreateRedundantMatrix(A, size, MPI_COMM_NULL, MAT_INITIAL_MATRIX, &As);

    1861:     PetscInt *numExclusivelyOwnedAll;
    1862:     PetscMalloc1(size, &numExclusivelyOwnedAll);
    1863:     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
    1864:     MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,numExclusivelyOwnedAll,1,MPIU_INT,comm);

    1866:     MatGetSize(As, &numRows, NULL);
    1867:     PetscMalloc1(numRows, &partGlobal);
    1868:     if (rank == 0) {
    1869:       PetscInt *adjncy_g, *xadj_g, *vtxwgt_g;
    1870:       lenadjncy = 0;

    1872:       for (i=0; i<numRows; i++) {
    1873:         PetscInt temp=0;
    1874:         MatGetRow(As, i, &temp, NULL, NULL);
    1875:         lenadjncy += temp;
    1876:         MatRestoreRow(As, i, &temp, NULL, NULL);
    1877:       }
    1878:       PetscMalloc1(lenadjncy, &adjncy_g);
    1879:       lenxadj = 1 + numRows;
    1880:       PetscMalloc1(lenxadj, &xadj_g);
    1881:       xadj_g[0] = 0;
    1882:       counter = 0;
    1883:       for (i=0; i<numRows; i++) {
    1884:         PetscInt        temp=0;
    1885:         const PetscInt *cols;
    1886:         MatGetRow(As, i, &temp, &cols, NULL);
    1887:         PetscArraycpy(&adjncy_g[counter], cols, temp);
    1888:         counter += temp;
    1889:         xadj_g[i+1] = counter;
    1890:         MatRestoreRow(As, i, &temp, &cols, NULL);
    1891:       }
    1892:       PetscMalloc1(2*numRows, &vtxwgt_g);
    1893:       for (i=0; i<size; i++) {
    1894:         vtxwgt_g[ncon*cumSumVertices[i]] = numExclusivelyOwnedAll[i];
    1895:         if (ncon>1) vtxwgt_g[ncon*cumSumVertices[i]+1] = 1;
    1896:         for (j=cumSumVertices[i]+1; j<cumSumVertices[i+1]; j++) {
    1897:           vtxwgt_g[ncon*j] = 1;
    1898:           if (ncon>1) vtxwgt_g[2*j+1] = 0;
    1899:         }
    1900:       }
    1901:       PetscMalloc1(64, &options);
    1902:       METIS_SetDefaultOptions(options); /* initialize all defaults */
    1904:       options[METIS_OPTION_CONTIG] = 1;
    1905:       PetscStackPush("METIS_PartGraphKway");
    1906:       METIS_PartGraphKway(&numRows, &ncon, xadj_g, adjncy_g, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
    1907:       PetscStackPop;
    1909:       PetscFree(options);
    1910:       PetscFree(xadj_g);
    1911:       PetscFree(adjncy_g);
    1912:       PetscFree(vtxwgt_g);
    1913:     }
    1914:     PetscFree(numExclusivelyOwnedAll);

    1916:     /* Now scatter the parts array. */
    1917:     {
    1918:       PetscMPIInt *counts, *mpiCumSumVertices;
    1919:       PetscMalloc1(size, &counts);
    1920:       PetscMalloc1(size+1, &mpiCumSumVertices);
    1921:       for (i=0; i<size; i++) {
    1922:         PetscMPIIntCast(cumSumVertices[i+1] - cumSumVertices[i], &(counts[i]));
    1923:       }
    1924:       for (i=0; i<=size; i++) {
    1925:         PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i]));
    1926:       }
    1927:       MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm);
    1928:       PetscFree(counts);
    1929:       PetscFree(mpiCumSumVertices);
    1930:     }

    1932:     PetscFree(partGlobal);
    1933:     MatDestroy(&As);
    1934:   }

    1936:   MatDestroy(&A);
    1937:   PetscFree(ubvec);
    1938:   PetscFree(tpwgts);

    1940:   /* Now rename the result so that the vertex resembling the exclusively owned points stays on the same rank */

    1942:   PetscMalloc1(size, &firstVertices);
    1943:   PetscMalloc1(size, &renumbering);
    1944:   firstVertices[rank] = part[0];
    1945:   MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,firstVertices,1,MPIU_INT,comm);
    1946:   for (i=0; i<size; i++) {
    1947:     renumbering[firstVertices[i]] = i;
    1948:   }
    1949:   for (i=0; i<cumSumVertices[rank+1]-cumSumVertices[rank]; i++) {
    1950:     part[i] = renumbering[part[i]];
    1951:   }
    1952:   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
    1953:   failed = (PetscInt)(part[0] != rank);
    1954:   MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm);

    1956:   PetscFree(firstVertices);
    1957:   PetscFree(renumbering);

    1959:   if (failedGlobal > 0) {
    1960:     PetscLayoutDestroy(&layout);
    1961:     PetscFree(xadj);
    1962:     PetscFree(adjncy);
    1963:     PetscFree(vtxwgt);
    1964:     PetscFree(toBalance);
    1965:     PetscFree(isLeaf);
    1966:     PetscFree(isNonExclusivelyOwned);
    1967:     PetscFree(isExclusivelyOwned);
    1968:     PetscFree(part);
    1969:     if (viewer) {
    1970:       PetscViewerPopFormat(viewer);
    1971:       PetscViewerDestroy(&viewer);
    1972:     }
    1973:     PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);
    1974:     return 0;
    1975:   }

    1977:   /*Let's check how well we did distributing points*/
    1978:   if (viewer) {
    1979:     PetscViewerASCIIPrintf(viewer, "Comparing number of owned entities of depth %D on each process before rebalancing, after rebalancing, and after consistency checks.\n", entityDepth);
    1980:     PetscViewerASCIIPrintf(viewer, "Initial.     ");
    1981:     DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, NULL, viewer);
    1982:     PetscViewerASCIIPrintf(viewer, "Rebalanced.  ");
    1983:     DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);
    1984:   }

    1986:   /* Now check that every vertex is owned by a process that it is actually connected to. */
    1987:   for (i=1; i<=numNonExclusivelyOwned; i++) {
    1988:     PetscInt loc = 0;
    1989:     PetscFindInt(cumSumVertices[part[i]], xadj[i+1]-xadj[i], &adjncy[xadj[i]], &loc);
    1990:     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
    1991:     if (loc<0) {
    1992:       part[i] = rank;
    1993:     }
    1994:   }

    1996:   /* Let's see how significant the influences of the previous fixing up step was.*/
    1997:   if (viewer) {
    1998:     PetscViewerASCIIPrintf(viewer, "After.       ");
    1999:     DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);
    2000:   }

    2002:   PetscLayoutDestroy(&layout);
    2003:   PetscFree(xadj);
    2004:   PetscFree(adjncy);
    2005:   PetscFree(vtxwgt);

    2007:   /* Almost done, now rewrite the SF to reflect the new ownership. */
    2008:   {
    2009:     PetscInt *pointsToRewrite;
    2010:     PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite);
    2011:     counter = 0;
    2012:     for (i=0; i<pEnd-pStart; i++) {
    2013:       if (toBalance[i]) {
    2014:         if (isNonExclusivelyOwned[i]) {
    2015:           pointsToRewrite[counter] = i + pStart;
    2016:           counter++;
    2017:         }
    2018:       }
    2019:     }
    2020:     DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part+1, degrees);
    2021:     PetscFree(pointsToRewrite);
    2022:   }

    2024:   PetscFree(toBalance);
    2025:   PetscFree(isLeaf);
    2026:   PetscFree(isNonExclusivelyOwned);
    2027:   PetscFree(isExclusivelyOwned);
    2028:   PetscFree(part);
    2029:   if (viewer) {
    2030:     PetscViewerPopFormat(viewer);
    2031:     PetscViewerDestroy(&viewer);
    2032:   }
    2033:   if (success) *success = PETSC_TRUE;
    2034:   PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);
    2035:   return 0;
    2036: #else
    2037:   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
    2038: #endif
    2039: }