xref: /petsc/src/dm/impls/plex/plexpartition.c (revision bbbc8e51870e2779407bb0f2e18f2ea4346c4bc5)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2e8f14785SLisandro Dalcin #include <petsc/private/hashseti.h>
370034214SMatthew G. Knepley 
477623264SMatthew G. Knepley PetscClassId PETSCPARTITIONER_CLASSID = 0;
577623264SMatthew G. Knepley 
677623264SMatthew G. Knepley PetscFunctionList PetscPartitionerList              = NULL;
777623264SMatthew G. Knepley PetscBool         PetscPartitionerRegisterAllCalled = PETSC_FALSE;
877623264SMatthew G. Knepley 
977623264SMatthew G. Knepley PetscBool ChacoPartitionercite = PETSC_FALSE;
1077623264SMatthew G. Knepley const char ChacoPartitionerCitation[] = "@inproceedings{Chaco95,\n"
1177623264SMatthew G. Knepley                                "  author    = {Bruce Hendrickson and Robert Leland},\n"
1277623264SMatthew G. Knepley                                "  title     = {A multilevel algorithm for partitioning graphs},\n"
1377623264SMatthew G. Knepley                                "  booktitle = {Supercomputing '95: Proceedings of the 1995 ACM/IEEE Conference on Supercomputing (CDROM)},"
1477623264SMatthew G. Knepley                                "  isbn      = {0-89791-816-9},\n"
1577623264SMatthew G. Knepley                                "  pages     = {28},\n"
1677623264SMatthew G. Knepley                                "  doi       = {http://doi.acm.org/10.1145/224170.224228},\n"
1777623264SMatthew G. Knepley                                "  publisher = {ACM Press},\n"
1877623264SMatthew G. Knepley                                "  address   = {New York},\n"
1977623264SMatthew G. Knepley                                "  year      = {1995}\n}\n";
2077623264SMatthew G. Knepley 
2177623264SMatthew G. Knepley PetscBool ParMetisPartitionercite = PETSC_FALSE;
2277623264SMatthew G. Knepley const char ParMetisPartitionerCitation[] = "@article{KarypisKumar98,\n"
2377623264SMatthew G. Knepley                                "  author  = {George Karypis and Vipin Kumar},\n"
2477623264SMatthew G. Knepley                                "  title   = {A Parallel Algorithm for Multilevel Graph Partitioning and Sparse Matrix Ordering},\n"
2577623264SMatthew G. Knepley                                "  journal = {Journal of Parallel and Distributed Computing},\n"
2677623264SMatthew G. Knepley                                "  volume  = {48},\n"
2777623264SMatthew G. Knepley                                "  pages   = {71--85},\n"
2877623264SMatthew G. Knepley                                "  year    = {1998}\n}\n";
2977623264SMatthew G. Knepley 
300134a67bSLisandro Dalcin PETSC_STATIC_INLINE PetscInt DMPlex_GlobalID(PetscInt point) { return point >= 0 ? point : -(point+1); }
310134a67bSLisandro Dalcin 
32*bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
33532c4e7dSMichael Lange {
34ffbd6163SMatthew G. Knepley   PetscInt       dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
35389e55d8SMichael Lange   PetscInt      *adj = NULL, *vOffsets = NULL, *graph = NULL;
368cfe4c1fSMichael Lange   IS             cellNumbering;
378cfe4c1fSMichael Lange   const PetscInt *cellNum;
38532c4e7dSMichael Lange   PetscBool      useCone, useClosure;
39532c4e7dSMichael Lange   PetscSection   section;
40532c4e7dSMichael Lange   PetscSegBuffer adjBuffer;
418cfe4c1fSMichael Lange   PetscSF        sfPoint;
428f4e72b9SMatthew G. Knepley   PetscInt       *adjCells = NULL, *remoteCells = NULL;
438f4e72b9SMatthew G. Knepley   const PetscInt *local;
448f4e72b9SMatthew G. Knepley   PetscInt       nroots, nleaves, l;
45532c4e7dSMichael Lange   PetscMPIInt    rank;
46532c4e7dSMichael Lange   PetscErrorCode ierr;
47532c4e7dSMichael Lange 
48532c4e7dSMichael Lange   PetscFunctionBegin;
49532c4e7dSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
50ffbd6163SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
51ffbd6163SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
52ffbd6163SMatthew G. Knepley   if (dim != depth) {
53ffbd6163SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
54ffbd6163SMatthew G. Knepley     ierr = DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);CHKERRQ(ierr);
55ffbd6163SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
56ffbd6163SMatthew G. Knepley     if (globalNumbering) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);CHKERRQ(ierr);}
57ffbd6163SMatthew G. Knepley     /* Different behavior for empty graphs */
58ffbd6163SMatthew G. Knepley     if (!*numVertices) {
59ffbd6163SMatthew G. Knepley       ierr = PetscMalloc1(1, offsets);CHKERRQ(ierr);
60ffbd6163SMatthew G. Knepley       (*offsets)[0] = 0;
61ffbd6163SMatthew G. Knepley     }
62ffbd6163SMatthew G. Knepley     /* Broken in parallel */
63ffbd6163SMatthew G. Knepley     if (rank && *numVertices) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
64ffbd6163SMatthew G. Knepley     PetscFunctionReturn(0);
65ffbd6163SMatthew G. Knepley   }
668cfe4c1fSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
670134a67bSLisandro Dalcin   ierr = DMPlexGetHeightStratum(dm, height, &pStart, &pEnd);CHKERRQ(ierr);
68532c4e7dSMichael Lange   /* Build adjacency graph via a section/segbuffer */
69532c4e7dSMichael Lange   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &section);CHKERRQ(ierr);
70532c4e7dSMichael Lange   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
71532c4e7dSMichael Lange   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&adjBuffer);CHKERRQ(ierr);
72532c4e7dSMichael Lange   /* Always use FVM adjacency to create partitioner graph */
73b0441da4SMatthew G. Knepley   ierr = DMGetBasicAdjacency(dm, &useCone, &useClosure);CHKERRQ(ierr);
74b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE);CHKERRQ(ierr);
750134a67bSLisandro Dalcin   ierr = DMPlexCreateNumbering_Internal(dm, pStart, pEnd, 0, NULL, sfPoint, &cellNumbering);CHKERRQ(ierr);
763fa7752dSToby Isaac   if (globalNumbering) {
773fa7752dSToby Isaac     ierr = PetscObjectReference((PetscObject)cellNumbering);CHKERRQ(ierr);
783fa7752dSToby Isaac     *globalNumbering = cellNumbering;
793fa7752dSToby Isaac   }
808cfe4c1fSMichael Lange   ierr = ISGetIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
818f4e72b9SMatthew G. Knepley   /* For all boundary faces (including faces adjacent to a ghost cell), record the local cell in adjCells
828f4e72b9SMatthew G. Knepley      Broadcast adjCells to remoteCells (to get cells from roots) and Reduce adjCells to remoteCells (to get cells from leaves)
838f4e72b9SMatthew G. Knepley    */
840134a67bSLisandro Dalcin   ierr = PetscSFGetGraph(sfPoint, &nroots, &nleaves, &local, NULL);CHKERRQ(ierr);
858f4e72b9SMatthew G. Knepley   if (nroots >= 0) {
868f4e72b9SMatthew G. Knepley     PetscInt fStart, fEnd, f;
878f4e72b9SMatthew G. Knepley 
888f4e72b9SMatthew G. Knepley     ierr = PetscCalloc2(nroots, &adjCells, nroots, &remoteCells);CHKERRQ(ierr);
890134a67bSLisandro Dalcin     ierr = DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);CHKERRQ(ierr);
908f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) adjCells[l] = -3;
918f4e72b9SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
928f4e72b9SMatthew G. Knepley       const PetscInt *support;
938f4e72b9SMatthew G. Knepley       PetscInt        supportSize;
948f4e72b9SMatthew G. Knepley 
958f4e72b9SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
968f4e72b9SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
970134a67bSLisandro Dalcin       if (supportSize == 1) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
988f4e72b9SMatthew G. Knepley       else if (supportSize == 2) {
998f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
1000134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1]]);
1018f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
1020134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
1030134a67bSLisandro Dalcin       }
1040134a67bSLisandro Dalcin       /* Handle non-conforming meshes */
1050134a67bSLisandro Dalcin       if (supportSize > 2) {
1060134a67bSLisandro Dalcin         PetscInt        numChildren, i;
1070134a67bSLisandro Dalcin         const PetscInt *children;
1080134a67bSLisandro Dalcin 
1090134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, f, &numChildren, &children);CHKERRQ(ierr);
1100134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1110134a67bSLisandro Dalcin           const PetscInt child = children[i];
1120134a67bSLisandro Dalcin           if (fStart <= child && child < fEnd) {
1130134a67bSLisandro Dalcin             ierr = DMPlexGetSupport(dm, child, &support);CHKERRQ(ierr);
1140134a67bSLisandro Dalcin             ierr = DMPlexGetSupportSize(dm, child, &supportSize);CHKERRQ(ierr);
1150134a67bSLisandro Dalcin             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
1160134a67bSLisandro Dalcin             else if (supportSize == 2) {
1170134a67bSLisandro Dalcin               ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
1180134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1]]);
1190134a67bSLisandro Dalcin               ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
1200134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
1210134a67bSLisandro Dalcin             }
1220134a67bSLisandro Dalcin           }
1230134a67bSLisandro Dalcin         }
1248f4e72b9SMatthew G. Knepley       }
1258f4e72b9SMatthew G. Knepley     }
1268f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) remoteCells[l] = -1;
1278f4e72b9SMatthew G. Knepley     ierr = PetscSFBcastBegin(dm->sf, MPIU_INT, adjCells, remoteCells);CHKERRQ(ierr);
1288f4e72b9SMatthew G. Knepley     ierr = PetscSFBcastEnd(dm->sf, MPIU_INT, adjCells, remoteCells);CHKERRQ(ierr);
1298f4e72b9SMatthew G. Knepley     ierr = PetscSFReduceBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);CHKERRQ(ierr);
1308f4e72b9SMatthew G. Knepley     ierr = PetscSFReduceEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);CHKERRQ(ierr);
1318f4e72b9SMatthew G. Knepley   }
1328f4e72b9SMatthew G. Knepley   /* Combine local and global adjacencies */
1338cfe4c1fSMichael Lange   for (*numVertices = 0, p = pStart; p < pEnd; p++) {
1348cfe4c1fSMichael Lange     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
1358cfe4c1fSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
1368f4e72b9SMatthew G. Knepley     /* Add remote cells */
1378f4e72b9SMatthew G. Knepley     if (remoteCells) {
1380134a67bSLisandro Dalcin       const PetscInt gp = DMPlex_GlobalID(cellNum[p]);
1390134a67bSLisandro Dalcin       PetscInt       coneSize, numChildren, c, i;
1400134a67bSLisandro Dalcin       const PetscInt *cone, *children;
1410134a67bSLisandro Dalcin 
1428f4e72b9SMatthew G. Knepley       ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1438f4e72b9SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1448f4e72b9SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
1450134a67bSLisandro Dalcin         const PetscInt point = cone[c];
1460134a67bSLisandro Dalcin         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
1478f4e72b9SMatthew G. Knepley           PetscInt *PETSC_RESTRICT pBuf;
1488f4e72b9SMatthew G. Knepley           ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
1498f4e72b9SMatthew G. Knepley           ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1500134a67bSLisandro Dalcin           *pBuf = remoteCells[point];
1510134a67bSLisandro Dalcin         }
1520134a67bSLisandro Dalcin         /* Handle non-conforming meshes */
1530134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, point, &numChildren, &children);CHKERRQ(ierr);
1540134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1550134a67bSLisandro Dalcin           const PetscInt child = children[i];
1560134a67bSLisandro Dalcin           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
1570134a67bSLisandro Dalcin             PetscInt *PETSC_RESTRICT pBuf;
1580134a67bSLisandro Dalcin             ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
1590134a67bSLisandro Dalcin             ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1600134a67bSLisandro Dalcin             *pBuf = remoteCells[child];
1610134a67bSLisandro Dalcin           }
1628f4e72b9SMatthew G. Knepley         }
1638f4e72b9SMatthew G. Knepley       }
1648f4e72b9SMatthew G. Knepley     }
1658f4e72b9SMatthew G. Knepley     /* Add local cells */
166532c4e7dSMichael Lange     adjSize = PETSC_DETERMINE;
167532c4e7dSMichael Lange     ierr = DMPlexGetAdjacency(dm, p, &adjSize, &adj);CHKERRQ(ierr);
168532c4e7dSMichael Lange     for (a = 0; a < adjSize; ++a) {
169532c4e7dSMichael Lange       const PetscInt point = adj[a];
170532c4e7dSMichael Lange       if (point != p && pStart <= point && point < pEnd) {
171532c4e7dSMichael Lange         PetscInt *PETSC_RESTRICT pBuf;
172532c4e7dSMichael Lange         ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
173532c4e7dSMichael Lange         ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1740134a67bSLisandro Dalcin         *pBuf = DMPlex_GlobalID(cellNum[point]);
175532c4e7dSMichael Lange       }
176532c4e7dSMichael Lange     }
1778cfe4c1fSMichael Lange     (*numVertices)++;
178532c4e7dSMichael Lange   }
1794e468a93SLisandro Dalcin   ierr = PetscFree(adj);CHKERRQ(ierr);
1808f4e72b9SMatthew G. Knepley   ierr = PetscFree2(adjCells, remoteCells);CHKERRQ(ierr);
181b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, useCone, useClosure);CHKERRQ(ierr);
1824e468a93SLisandro Dalcin 
183532c4e7dSMichael Lange   /* Derive CSR graph from section/segbuffer */
184532c4e7dSMichael Lange   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
185532c4e7dSMichael Lange   ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
186389e55d8SMichael Lange   ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
18743f7d02bSMichael Lange   for (idx = 0, p = pStart; p < pEnd; p++) {
18843f7d02bSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
18943f7d02bSMichael Lange     ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
19043f7d02bSMichael Lange   }
191532c4e7dSMichael Lange   vOffsets[*numVertices] = size;
192389e55d8SMichael Lange   ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
1934e468a93SLisandro Dalcin 
1944e468a93SLisandro Dalcin   if (nroots >= 0) {
1954e468a93SLisandro Dalcin     /* Filter out duplicate edges using section/segbuffer */
1964e468a93SLisandro Dalcin     ierr = PetscSectionReset(section);CHKERRQ(ierr);
1974e468a93SLisandro Dalcin     ierr = PetscSectionSetChart(section, 0, *numVertices);CHKERRQ(ierr);
1984e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
1994e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
2004e468a93SLisandro Dalcin       PetscInt numEdges = end-start, *PETSC_RESTRICT edges;
2014e468a93SLisandro Dalcin       ierr = PetscSortRemoveDupsInt(&numEdges, &graph[start]);CHKERRQ(ierr);
2024e468a93SLisandro Dalcin       ierr = PetscSectionSetDof(section, p, numEdges);CHKERRQ(ierr);
2034e468a93SLisandro Dalcin       ierr = PetscSegBufferGetInts(adjBuffer, numEdges, &edges);CHKERRQ(ierr);
2044e468a93SLisandro Dalcin       ierr = PetscMemcpy(edges, &graph[start], numEdges*sizeof(*edges));CHKERRQ(ierr);
2054e468a93SLisandro Dalcin     }
2064e468a93SLisandro Dalcin     ierr = PetscFree(vOffsets);CHKERRQ(ierr);
2074e468a93SLisandro Dalcin     ierr = PetscFree(graph);CHKERRQ(ierr);
2084e468a93SLisandro Dalcin     /* Derive CSR graph from section/segbuffer */
2094e468a93SLisandro Dalcin     ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
2104e468a93SLisandro Dalcin     ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
2114e468a93SLisandro Dalcin     ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
2124e468a93SLisandro Dalcin     for (idx = 0, p = 0; p < *numVertices; p++) {
2134e468a93SLisandro Dalcin       ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
2144e468a93SLisandro Dalcin     }
2154e468a93SLisandro Dalcin     vOffsets[*numVertices] = size;
2164e468a93SLisandro Dalcin     ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
2174e468a93SLisandro Dalcin   } else {
2184e468a93SLisandro Dalcin     /* Sort adjacencies (not strictly necessary) */
2194e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2204e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
2214e468a93SLisandro Dalcin       ierr = PetscSortInt(end-start, &graph[start]);CHKERRQ(ierr);
2224e468a93SLisandro Dalcin     }
2234e468a93SLisandro Dalcin   }
2244e468a93SLisandro Dalcin 
2254e468a93SLisandro Dalcin   if (offsets) *offsets = vOffsets;
226389e55d8SMichael Lange   if (adjacency) *adjacency = graph;
2274e468a93SLisandro Dalcin 
228532c4e7dSMichael Lange   /* Cleanup */
229532c4e7dSMichael Lange   ierr = PetscSegBufferDestroy(&adjBuffer);CHKERRQ(ierr);
230532c4e7dSMichael Lange   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
2314e468a93SLisandro Dalcin   ierr = ISRestoreIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
2324e468a93SLisandro Dalcin   ierr = ISDestroy(&cellNumbering);CHKERRQ(ierr);
233532c4e7dSMichael Lange   PetscFunctionReturn(0);
234532c4e7dSMichael Lange }
235532c4e7dSMichael Lange 
236*bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
237*bbbc8e51SStefano Zampini {
238*bbbc8e51SStefano Zampini   Mat            conn, CSR;
239*bbbc8e51SStefano Zampini   IS             fis, cis, cis_own;
240*bbbc8e51SStefano Zampini   PetscSF        sfPoint;
241*bbbc8e51SStefano Zampini   const char     *prefix;
242*bbbc8e51SStefano Zampini   const PetscInt *rows, *cols, *ii, *jj;
243*bbbc8e51SStefano Zampini   PetscInt       *idxs,*idxs2;
244*bbbc8e51SStefano Zampini   PetscInt       dim, depth, floc, cloc, i, M, N, c, m, cStart, cEnd, fStart, fEnd;
245*bbbc8e51SStefano Zampini   PetscMPIInt    rank;
246*bbbc8e51SStefano Zampini   PetscBool      flg;
247*bbbc8e51SStefano Zampini   PetscErrorCode ierr;
248*bbbc8e51SStefano Zampini 
249*bbbc8e51SStefano Zampini   PetscFunctionBegin;
250*bbbc8e51SStefano Zampini   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
251*bbbc8e51SStefano Zampini   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
252*bbbc8e51SStefano Zampini   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
253*bbbc8e51SStefano Zampini   if (dim != depth) {
254*bbbc8e51SStefano Zampini     /* We do not handle the uninterpolated case here */
255*bbbc8e51SStefano Zampini     ierr = DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);CHKERRQ(ierr);
256*bbbc8e51SStefano Zampini     /* DMPlexCreateNeighborCSR does not make a numbering */
257*bbbc8e51SStefano Zampini     if (globalNumbering) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);CHKERRQ(ierr);}
258*bbbc8e51SStefano Zampini     /* Different behavior for empty graphs */
259*bbbc8e51SStefano Zampini     if (!*numVertices) {
260*bbbc8e51SStefano Zampini       ierr = PetscMalloc1(1, offsets);CHKERRQ(ierr);
261*bbbc8e51SStefano Zampini       (*offsets)[0] = 0;
262*bbbc8e51SStefano Zampini     }
263*bbbc8e51SStefano Zampini     /* Broken in parallel */
264*bbbc8e51SStefano Zampini     if (rank && *numVertices) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
265*bbbc8e51SStefano Zampini     PetscFunctionReturn(0);
266*bbbc8e51SStefano Zampini   }
267*bbbc8e51SStefano Zampini   /* Interpolated and parallel case */
268*bbbc8e51SStefano Zampini   ierr = DMGetOptionsPrefix(dm, &prefix);CHKERRQ(ierr);
269*bbbc8e51SStefano Zampini 
270*bbbc8e51SStefano Zampini   /* numbering */
271*bbbc8e51SStefano Zampini   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
272*bbbc8e51SStefano Zampini   ierr = DMPlexGetHeightStratum(dm, height, &cStart, &cEnd);CHKERRQ(ierr);
273*bbbc8e51SStefano Zampini   ierr = DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);CHKERRQ(ierr);
274*bbbc8e51SStefano Zampini   ierr = DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, &N, sfPoint, &cis);CHKERRQ(ierr);
275*bbbc8e51SStefano Zampini   ierr = DMPlexCreateNumbering_Internal(dm, fStart, fEnd, 0, &M, sfPoint, &fis);CHKERRQ(ierr);
276*bbbc8e51SStefano Zampini   if (globalNumbering) {
277*bbbc8e51SStefano Zampini     ierr = ISDuplicate(cis, globalNumbering);CHKERRQ(ierr);
278*bbbc8e51SStefano Zampini   }
279*bbbc8e51SStefano Zampini 
280*bbbc8e51SStefano Zampini   /* get positive global ids and local sizes for facets and cells */
281*bbbc8e51SStefano Zampini   ierr = ISGetLocalSize(fis, &m);CHKERRQ(ierr);
282*bbbc8e51SStefano Zampini   ierr = ISGetIndices(fis, &rows);CHKERRQ(ierr);
283*bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs);CHKERRQ(ierr);
284*bbbc8e51SStefano Zampini   for (i = 0, floc = 0; i < m; i++) {
285*bbbc8e51SStefano Zampini     const PetscInt p = rows[i];
286*bbbc8e51SStefano Zampini 
287*bbbc8e51SStefano Zampini     if (p < 0) {
288*bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
289*bbbc8e51SStefano Zampini     } else {
290*bbbc8e51SStefano Zampini       idxs[i] = p;
291*bbbc8e51SStefano Zampini       floc   += 1;
292*bbbc8e51SStefano Zampini     }
293*bbbc8e51SStefano Zampini   }
294*bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(fis, &rows);CHKERRQ(ierr);
295*bbbc8e51SStefano Zampini   ierr = ISDestroy(&fis);CHKERRQ(ierr);
296*bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr);
297*bbbc8e51SStefano Zampini 
298*bbbc8e51SStefano Zampini   ierr = ISGetLocalSize(cis, &m);CHKERRQ(ierr);
299*bbbc8e51SStefano Zampini   ierr = ISGetIndices(cis, &cols);CHKERRQ(ierr);
300*bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs);CHKERRQ(ierr);
301*bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs2);CHKERRQ(ierr);
302*bbbc8e51SStefano Zampini   for (i = 0, cloc = 0; i < m; i++) {
303*bbbc8e51SStefano Zampini     const PetscInt p = cols[i];
304*bbbc8e51SStefano Zampini 
305*bbbc8e51SStefano Zampini     if (p < 0) {
306*bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
307*bbbc8e51SStefano Zampini     } else {
308*bbbc8e51SStefano Zampini       idxs[i]       = p;
309*bbbc8e51SStefano Zampini       idxs2[cloc++] = p;
310*bbbc8e51SStefano Zampini     }
311*bbbc8e51SStefano Zampini   }
312*bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(cis, &cols);CHKERRQ(ierr);
313*bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis);CHKERRQ(ierr);
314*bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr);
315*bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own);CHKERRQ(ierr);
316*bbbc8e51SStefano Zampini 
317*bbbc8e51SStefano Zampini   ierr = PetscObjectSetName((PetscObject)cis, "Local cells");CHKERRQ(ierr);
318*bbbc8e51SStefano Zampini   ierr = PetscObjectSetName((PetscObject)cis_own, "Owned local cells");CHKERRQ(ierr);
319*bbbc8e51SStefano Zampini   ierr = PetscObjectSetOptionsPrefix((PetscObject)cis, prefix);CHKERRQ(ierr);
320*bbbc8e51SStefano Zampini   ierr = PetscObjectSetOptionsPrefix((PetscObject)cis_own, prefix);CHKERRQ(ierr);
321*bbbc8e51SStefano Zampini   ierr = ISViewFromOptions(cis, NULL, "-dm_plex_csr_is_view");CHKERRQ(ierr);
322*bbbc8e51SStefano Zampini   ierr = ISViewFromOptions(cis_own, NULL, "-dm_plex_csr_is_view");CHKERRQ(ierr);
323*bbbc8e51SStefano Zampini 
324*bbbc8e51SStefano Zampini   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
325*bbbc8e51SStefano Zampini   ierr = MatCreate(PetscObjectComm((PetscObject)dm), &conn);CHKERRQ(ierr);
326*bbbc8e51SStefano Zampini   ierr = MatSetSizes(conn, floc, cloc, M, N);CHKERRQ(ierr);
327*bbbc8e51SStefano Zampini   ierr = MatSetType(conn, MATMPIAIJ);CHKERRQ(ierr);
328*bbbc8e51SStefano Zampini   ierr = DMPlexGetMaxSizes(dm, NULL, &m);CHKERRQ(ierr);
329*bbbc8e51SStefano Zampini   ierr = MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL);CHKERRQ(ierr);
330*bbbc8e51SStefano Zampini 
331*bbbc8e51SStefano Zampini   /* Assemble matrix */
332*bbbc8e51SStefano Zampini   ierr = ISGetIndices(fis, &rows);CHKERRQ(ierr);
333*bbbc8e51SStefano Zampini   ierr = ISGetIndices(cis, &cols);CHKERRQ(ierr);
334*bbbc8e51SStefano Zampini   for (c = cStart; c < cEnd; c++) {
335*bbbc8e51SStefano Zampini     const PetscInt *cone;
336*bbbc8e51SStefano Zampini     PetscInt        coneSize, row, col, f;
337*bbbc8e51SStefano Zampini 
338*bbbc8e51SStefano Zampini     col  = cols[c-cStart];
339*bbbc8e51SStefano Zampini     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
340*bbbc8e51SStefano Zampini     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
341*bbbc8e51SStefano Zampini     for (f = 0; f < coneSize; f++) {
342*bbbc8e51SStefano Zampini       const PetscScalar v = 1.0;
343*bbbc8e51SStefano Zampini       const PetscInt *children;
344*bbbc8e51SStefano Zampini       PetscInt        numChildren, ch;
345*bbbc8e51SStefano Zampini 
346*bbbc8e51SStefano Zampini       row  = rows[cone[f]-fStart];
347*bbbc8e51SStefano Zampini       ierr = MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);CHKERRQ(ierr);
348*bbbc8e51SStefano Zampini 
349*bbbc8e51SStefano Zampini       /* non-conforming meshes */
350*bbbc8e51SStefano Zampini       ierr = DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children);CHKERRQ(ierr);
351*bbbc8e51SStefano Zampini       for (ch = 0; ch < numChildren; ch++) {
352*bbbc8e51SStefano Zampini         const PetscInt child = children[ch];
353*bbbc8e51SStefano Zampini 
354*bbbc8e51SStefano Zampini         if (child < fStart || child >= fEnd) continue;
355*bbbc8e51SStefano Zampini         row  = rows[child-fStart];
356*bbbc8e51SStefano Zampini         ierr = MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);CHKERRQ(ierr);
357*bbbc8e51SStefano Zampini       }
358*bbbc8e51SStefano Zampini     }
359*bbbc8e51SStefano Zampini   }
360*bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(fis, &rows);CHKERRQ(ierr);
361*bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(cis, &cols);CHKERRQ(ierr);
362*bbbc8e51SStefano Zampini   ierr = ISDestroy(&fis);CHKERRQ(ierr);
363*bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis);CHKERRQ(ierr);
364*bbbc8e51SStefano Zampini   ierr = MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
365*bbbc8e51SStefano Zampini   ierr = MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
366*bbbc8e51SStefano Zampini 
367*bbbc8e51SStefano Zampini   ierr = PetscObjectSetName((PetscObject)conn, "F-C connectivity");CHKERRQ(ierr);
368*bbbc8e51SStefano Zampini   ierr = MatSetOptionsPrefix(conn, prefix);CHKERRQ(ierr);
369*bbbc8e51SStefano Zampini   ierr = MatViewFromOptions(conn, NULL, "-dm_plex_csr_conn_view");CHKERRQ(ierr);
370*bbbc8e51SStefano Zampini 
371*bbbc8e51SStefano Zampini   /* Get parallel CSR by doing conn^T * conn */
372*bbbc8e51SStefano Zampini   ierr = MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR);CHKERRQ(ierr);
373*bbbc8e51SStefano Zampini   ierr = MatDestroy(&conn);CHKERRQ(ierr);
374*bbbc8e51SStefano Zampini 
375*bbbc8e51SStefano Zampini   ierr = PetscObjectSetName((PetscObject)CSR, "Connectivity");CHKERRQ(ierr);
376*bbbc8e51SStefano Zampini   ierr = MatSetOptionsPrefix(CSR, prefix);CHKERRQ(ierr);
377*bbbc8e51SStefano Zampini   ierr = DMViewFromOptions(dm, NULL, "-dm_plex_csr_dm_view");CHKERRQ(ierr);
378*bbbc8e51SStefano Zampini   ierr = MatViewFromOptions(CSR, NULL, "-dm_plex_csr_mat_view");CHKERRQ(ierr);
379*bbbc8e51SStefano Zampini 
380*bbbc8e51SStefano Zampini   /* extract local part of the CSR */
381*bbbc8e51SStefano Zampini   ierr = MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn);CHKERRQ(ierr);
382*bbbc8e51SStefano Zampini   ierr = MatDestroy(&CSR);CHKERRQ(ierr);
383*bbbc8e51SStefano Zampini   ierr = MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);CHKERRQ(ierr);
384*bbbc8e51SStefano Zampini   if (!flg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
385*bbbc8e51SStefano Zampini 
386*bbbc8e51SStefano Zampini   /* get back requested output */
387*bbbc8e51SStefano Zampini   if (numVertices) *numVertices = m;
388*bbbc8e51SStefano Zampini   if (offsets) {
389*bbbc8e51SStefano Zampini     ierr = PetscCalloc1(m+1, &idxs);CHKERRQ(ierr);
390*bbbc8e51SStefano Zampini     for (i = 1; i < m+1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
391*bbbc8e51SStefano Zampini     *offsets = idxs;
392*bbbc8e51SStefano Zampini   }
393*bbbc8e51SStefano Zampini   if (adjacency) {
394*bbbc8e51SStefano Zampini     ierr = PetscMalloc1(ii[m] - m, &idxs);CHKERRQ(ierr);
395*bbbc8e51SStefano Zampini     ierr = ISGetIndices(cis_own, &rows);CHKERRQ(ierr);
396*bbbc8e51SStefano Zampini     for (i = 0, c = 0; i < m; i++) {
397*bbbc8e51SStefano Zampini       PetscInt j, g = rows[i];
398*bbbc8e51SStefano Zampini 
399*bbbc8e51SStefano Zampini       for (j = ii[i]; j < ii[i+1]; j++) {
400*bbbc8e51SStefano Zampini         if (jj[j] == g) continue; /* again, self-connectivity */
401*bbbc8e51SStefano Zampini         idxs[c++] = jj[j];
402*bbbc8e51SStefano Zampini       }
403*bbbc8e51SStefano Zampini     }
404*bbbc8e51SStefano Zampini     if (c != ii[m] - m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %D != %D",c,ii[m]-m);
405*bbbc8e51SStefano Zampini     ierr = ISRestoreIndices(cis_own, &rows);CHKERRQ(ierr);
406*bbbc8e51SStefano Zampini     *adjacency = idxs;
407*bbbc8e51SStefano Zampini   }
408*bbbc8e51SStefano Zampini 
409*bbbc8e51SStefano Zampini   /* cleanup */
410*bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis_own);CHKERRQ(ierr);
411*bbbc8e51SStefano Zampini   ierr = MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);CHKERRQ(ierr);
412*bbbc8e51SStefano Zampini   if (!flg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
413*bbbc8e51SStefano Zampini   ierr = MatDestroy(&conn);CHKERRQ(ierr);
414*bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
415*bbbc8e51SStefano Zampini }
416*bbbc8e51SStefano Zampini 
417*bbbc8e51SStefano Zampini /*@C
418*bbbc8e51SStefano Zampini   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
419*bbbc8e51SStefano Zampini 
420*bbbc8e51SStefano Zampini   Input Parameters:
421*bbbc8e51SStefano Zampini + dm      - The mesh DM dm
422*bbbc8e51SStefano Zampini - height  - Height of the strata from which to construct the graph
423*bbbc8e51SStefano Zampini 
424*bbbc8e51SStefano Zampini   Output Parameter:
425*bbbc8e51SStefano Zampini + numVertices     - Number of vertices in the graph
426*bbbc8e51SStefano Zampini . offsets         - Point offsets in the graph
427*bbbc8e51SStefano Zampini . adjacency       - Point connectivity in the graph
428*bbbc8e51SStefano Zampini - globalNumbering - A map from the local cell numbering to the global numbering used in "adjacency".  Negative indicates that the cell is a duplicate from another process.
429*bbbc8e51SStefano Zampini 
430*bbbc8e51SStefano Zampini   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
431*bbbc8e51SStefano Zampini   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
432*bbbc8e51SStefano Zampini 
433*bbbc8e51SStefano Zampini   Level: developer
434*bbbc8e51SStefano Zampini 
435*bbbc8e51SStefano Zampini .seealso: PetscPartitionerGetType(), PetscPartitionerCreate(), DMSetAdjacency()
436*bbbc8e51SStefano Zampini @*/
437*bbbc8e51SStefano Zampini PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
438*bbbc8e51SStefano Zampini {
439*bbbc8e51SStefano Zampini   PetscErrorCode ierr;
440*bbbc8e51SStefano Zampini   PetscBool      usemat = PETSC_FALSE;
441*bbbc8e51SStefano Zampini 
442*bbbc8e51SStefano Zampini   PetscFunctionBegin;
443*bbbc8e51SStefano Zampini   ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_csr_via_mat", &usemat, NULL);CHKERRQ(ierr);
444*bbbc8e51SStefano Zampini   if (usemat) {
445*bbbc8e51SStefano Zampini     ierr = DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering);CHKERRQ(ierr);
446*bbbc8e51SStefano Zampini   } else {
447*bbbc8e51SStefano Zampini     ierr = DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering);CHKERRQ(ierr);
448*bbbc8e51SStefano Zampini   }
449*bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
450*bbbc8e51SStefano Zampini }
451*bbbc8e51SStefano Zampini 
452d5577e40SMatthew G. Knepley /*@C
453d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
454d5577e40SMatthew G. Knepley 
455d5577e40SMatthew G. Knepley   Collective
456d5577e40SMatthew G. Knepley 
457d5577e40SMatthew G. Knepley   Input Arguments:
458d5577e40SMatthew G. Knepley + dm - The DMPlex
459d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
460d5577e40SMatthew G. Knepley 
461d5577e40SMatthew G. Knepley   Output Arguments:
462d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
463d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
464d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
465d5577e40SMatthew G. Knepley 
466d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
467d5577e40SMatthew G. Knepley 
468d5577e40SMatthew G. Knepley   Level: advanced
469d5577e40SMatthew G. Knepley 
470d5577e40SMatthew G. Knepley .seealso: DMPlexCreate()
471d5577e40SMatthew G. Knepley @*/
47270034214SMatthew G. Knepley PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
47370034214SMatthew G. Knepley {
47470034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
47570034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
47670034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
47770034214SMatthew G. Knepley   PetscInt      *off, *adj;
47870034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
47970034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
48070034214SMatthew G. Knepley   PetscErrorCode ierr;
48170034214SMatthew G. Knepley 
48270034214SMatthew G. Knepley   PetscFunctionBegin;
48370034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
484c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
48570034214SMatthew G. Knepley   cellDim = dim - cellHeight;
48670034214SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
48770034214SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
48870034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
48970034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
49070034214SMatthew G. Knepley     if (offsets)   *offsets   = NULL;
49170034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
49270034214SMatthew G. Knepley     PetscFunctionReturn(0);
49370034214SMatthew G. Knepley   }
49470034214SMatthew G. Knepley   numCells  = cEnd - cStart;
49570034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
49670034214SMatthew G. Knepley   if (dim == depth) {
49770034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
49870034214SMatthew G. Knepley 
49970034214SMatthew G. Knepley     ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
50070034214SMatthew G. Knepley     /* Count neighboring cells */
50170034214SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr);
50270034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
50370034214SMatthew G. Knepley       const PetscInt *support;
50470034214SMatthew G. Knepley       PetscInt        supportSize;
50570034214SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
50670034214SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
50770034214SMatthew G. Knepley       if (supportSize == 2) {
5089ffc88e4SToby Isaac         PetscInt numChildren;
5099ffc88e4SToby Isaac 
5109ffc88e4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
5119ffc88e4SToby Isaac         if (!numChildren) {
51270034214SMatthew G. Knepley           ++off[support[0]-cStart+1];
51370034214SMatthew G. Knepley           ++off[support[1]-cStart+1];
51470034214SMatthew G. Knepley         }
51570034214SMatthew G. Knepley       }
5169ffc88e4SToby Isaac     }
51770034214SMatthew G. Knepley     /* Prefix sum */
51870034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
51970034214SMatthew G. Knepley     if (adjacency) {
52070034214SMatthew G. Knepley       PetscInt *tmp;
52170034214SMatthew G. Knepley 
52270034214SMatthew G. Knepley       ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
523854ce69bSBarry Smith       ierr = PetscMalloc1(numCells+1, &tmp);CHKERRQ(ierr);
52470034214SMatthew G. Knepley       ierr = PetscMemcpy(tmp, off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
52570034214SMatthew G. Knepley       /* Get neighboring cells */
52670034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
52770034214SMatthew G. Knepley         const PetscInt *support;
52870034214SMatthew G. Knepley         PetscInt        supportSize;
52970034214SMatthew G. Knepley         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
53070034214SMatthew G. Knepley         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
53170034214SMatthew G. Knepley         if (supportSize == 2) {
5329ffc88e4SToby Isaac           PetscInt numChildren;
5339ffc88e4SToby Isaac 
5349ffc88e4SToby Isaac           ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
5359ffc88e4SToby Isaac           if (!numChildren) {
53670034214SMatthew G. Knepley             adj[tmp[support[0]-cStart]++] = support[1];
53770034214SMatthew G. Knepley             adj[tmp[support[1]-cStart]++] = support[0];
53870034214SMatthew G. Knepley           }
53970034214SMatthew G. Knepley         }
5409ffc88e4SToby Isaac       }
54170034214SMatthew G. Knepley #if defined(PETSC_USE_DEBUG)
54270034214SMatthew G. Knepley       for (c = 0; c < cEnd-cStart; ++c) if (tmp[c] != off[c+1]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Offset %d != %d for cell %d", tmp[c], off[c], c+cStart);
54370034214SMatthew G. Knepley #endif
54470034214SMatthew G. Knepley       ierr = PetscFree(tmp);CHKERRQ(ierr);
54570034214SMatthew G. Knepley     }
54670034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
54770034214SMatthew G. Knepley     if (offsets)   *offsets   = off;
54870034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
54970034214SMatthew G. Knepley     PetscFunctionReturn(0);
55070034214SMatthew G. Knepley   }
55170034214SMatthew G. Knepley   /* Setup face recognition */
55270034214SMatthew G. Knepley   if (faceDepth == 1) {
55370034214SMatthew G. Knepley     PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */
55470034214SMatthew G. Knepley 
55570034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
55670034214SMatthew G. Knepley       PetscInt corners;
55770034214SMatthew G. Knepley 
55870034214SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
55970034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
56070034214SMatthew G. Knepley         PetscInt nFV;
56170034214SMatthew G. Knepley 
56270034214SMatthew G. Knepley         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
56370034214SMatthew G. Knepley         cornersSeen[corners] = 1;
56470034214SMatthew G. Knepley 
56570034214SMatthew G. Knepley         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
56670034214SMatthew G. Knepley 
56770034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
56870034214SMatthew G. Knepley       }
56970034214SMatthew G. Knepley     }
57070034214SMatthew G. Knepley   }
57170034214SMatthew G. Knepley   ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
57270034214SMatthew G. Knepley   /* Count neighboring cells */
57370034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
57470034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
57570034214SMatthew G. Knepley 
5768b0b4c70SToby Isaac     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
57770034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
57870034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
57970034214SMatthew G. Knepley       PetscInt        cellPair[2];
58070034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
58170034214SMatthew G. Knepley       PetscInt        meetSize = 0;
58270034214SMatthew G. Knepley       const PetscInt *meet    = NULL;
58370034214SMatthew G. Knepley 
58470034214SMatthew G. Knepley       cellPair[0] = cell; cellPair[1] = neighborCells[n];
58570034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
58670034214SMatthew G. Knepley       if (!found) {
58770034214SMatthew G. Knepley         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
58870034214SMatthew G. Knepley         if (meetSize) {
58970034214SMatthew G. Knepley           PetscInt f;
59070034214SMatthew G. Knepley 
59170034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
59270034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
59370034214SMatthew G. Knepley               found = PETSC_TRUE;
59470034214SMatthew G. Knepley               break;
59570034214SMatthew G. Knepley             }
59670034214SMatthew G. Knepley           }
59770034214SMatthew G. Knepley         }
59870034214SMatthew G. Knepley         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
59970034214SMatthew G. Knepley       }
60070034214SMatthew G. Knepley       if (found) ++off[cell-cStart+1];
60170034214SMatthew G. Knepley     }
60270034214SMatthew G. Knepley   }
60370034214SMatthew G. Knepley   /* Prefix sum */
60470034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
60570034214SMatthew G. Knepley 
60670034214SMatthew G. Knepley   if (adjacency) {
60770034214SMatthew G. Knepley     ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
60870034214SMatthew G. Knepley     /* Get neighboring cells */
60970034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
61070034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
61170034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
61270034214SMatthew G. Knepley 
6138b0b4c70SToby Isaac       ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
61470034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
61570034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
61670034214SMatthew G. Knepley         PetscInt        cellPair[2];
61770034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
61870034214SMatthew G. Knepley         PetscInt        meetSize = 0;
61970034214SMatthew G. Knepley         const PetscInt *meet    = NULL;
62070034214SMatthew G. Knepley 
62170034214SMatthew G. Knepley         cellPair[0] = cell; cellPair[1] = neighborCells[n];
62270034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
62370034214SMatthew G. Knepley         if (!found) {
62470034214SMatthew G. Knepley           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
62570034214SMatthew G. Knepley           if (meetSize) {
62670034214SMatthew G. Knepley             PetscInt f;
62770034214SMatthew G. Knepley 
62870034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
62970034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
63070034214SMatthew G. Knepley                 found = PETSC_TRUE;
63170034214SMatthew G. Knepley                 break;
63270034214SMatthew G. Knepley               }
63370034214SMatthew G. Knepley             }
63470034214SMatthew G. Knepley           }
63570034214SMatthew G. Knepley           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
63670034214SMatthew G. Knepley         }
63770034214SMatthew G. Knepley         if (found) {
63870034214SMatthew G. Knepley           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
63970034214SMatthew G. Knepley           ++cellOffset;
64070034214SMatthew G. Knepley         }
64170034214SMatthew G. Knepley       }
64270034214SMatthew G. Knepley     }
64370034214SMatthew G. Knepley   }
64470034214SMatthew G. Knepley   ierr = PetscFree(neighborCells);CHKERRQ(ierr);
64570034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
64670034214SMatthew G. Knepley   if (offsets)   *offsets   = off;
64770034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
64870034214SMatthew G. Knepley   PetscFunctionReturn(0);
64970034214SMatthew G. Knepley }
65070034214SMatthew G. Knepley 
65177623264SMatthew G. Knepley /*@C
65277623264SMatthew G. Knepley   PetscPartitionerRegister - Adds a new PetscPartitioner implementation
65377623264SMatthew G. Knepley 
65477623264SMatthew G. Knepley   Not Collective
65577623264SMatthew G. Knepley 
65677623264SMatthew G. Knepley   Input Parameters:
65777623264SMatthew G. Knepley + name        - The name of a new user-defined creation routine
65877623264SMatthew G. Knepley - create_func - The creation routine itself
65977623264SMatthew G. Knepley 
66077623264SMatthew G. Knepley   Notes:
66177623264SMatthew G. Knepley   PetscPartitionerRegister() may be called multiple times to add several user-defined PetscPartitioners
66277623264SMatthew G. Knepley 
66377623264SMatthew G. Knepley   Sample usage:
66477623264SMatthew G. Knepley .vb
66577623264SMatthew G. Knepley     PetscPartitionerRegister("my_part", MyPetscPartitionerCreate);
66677623264SMatthew G. Knepley .ve
66777623264SMatthew G. Knepley 
66877623264SMatthew G. Knepley   Then, your PetscPartitioner type can be chosen with the procedural interface via
66977623264SMatthew G. Knepley .vb
67077623264SMatthew G. Knepley     PetscPartitionerCreate(MPI_Comm, PetscPartitioner *);
67177623264SMatthew G. Knepley     PetscPartitionerSetType(PetscPartitioner, "my_part");
67277623264SMatthew G. Knepley .ve
67377623264SMatthew G. Knepley    or at runtime via the option
67477623264SMatthew G. Knepley .vb
67577623264SMatthew G. Knepley     -petscpartitioner_type my_part
67677623264SMatthew G. Knepley .ve
67777623264SMatthew G. Knepley 
67877623264SMatthew G. Knepley   Level: advanced
67977623264SMatthew G. Knepley 
68077623264SMatthew G. Knepley .keywords: PetscPartitioner, register
68177623264SMatthew G. Knepley .seealso: PetscPartitionerRegisterAll(), PetscPartitionerRegisterDestroy()
68277623264SMatthew G. Knepley 
68377623264SMatthew G. Knepley @*/
68477623264SMatthew G. Knepley PetscErrorCode PetscPartitionerRegister(const char sname[], PetscErrorCode (*function)(PetscPartitioner))
68577623264SMatthew G. Knepley {
68677623264SMatthew G. Knepley   PetscErrorCode ierr;
68777623264SMatthew G. Knepley 
68877623264SMatthew G. Knepley   PetscFunctionBegin;
68977623264SMatthew G. Knepley   ierr = PetscFunctionListAdd(&PetscPartitionerList, sname, function);CHKERRQ(ierr);
69077623264SMatthew G. Knepley   PetscFunctionReturn(0);
69177623264SMatthew G. Knepley }
69277623264SMatthew G. Knepley 
69377623264SMatthew G. Knepley /*@C
69477623264SMatthew G. Knepley   PetscPartitionerSetType - Builds a particular PetscPartitioner
69577623264SMatthew G. Knepley 
69677623264SMatthew G. Knepley   Collective on PetscPartitioner
69777623264SMatthew G. Knepley 
69877623264SMatthew G. Knepley   Input Parameters:
69977623264SMatthew G. Knepley + part - The PetscPartitioner object
70077623264SMatthew G. Knepley - name - The kind of partitioner
70177623264SMatthew G. Knepley 
70277623264SMatthew G. Knepley   Options Database Key:
70377623264SMatthew G. Knepley . -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types
70477623264SMatthew G. Knepley 
70577623264SMatthew G. Knepley   Level: intermediate
70677623264SMatthew G. Knepley 
70777623264SMatthew G. Knepley .keywords: PetscPartitioner, set, type
70877623264SMatthew G. Knepley .seealso: PetscPartitionerGetType(), PetscPartitionerCreate()
70977623264SMatthew G. Knepley @*/
71077623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name)
71177623264SMatthew G. Knepley {
71277623264SMatthew G. Knepley   PetscErrorCode (*r)(PetscPartitioner);
71377623264SMatthew G. Knepley   PetscBool      match;
71477623264SMatthew G. Knepley   PetscErrorCode ierr;
71577623264SMatthew G. Knepley 
71677623264SMatthew G. Knepley   PetscFunctionBegin;
71777623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
71877623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) part, name, &match);CHKERRQ(ierr);
71977623264SMatthew G. Knepley   if (match) PetscFunctionReturn(0);
72077623264SMatthew G. Knepley 
7210f51fdf8SToby Isaac   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
72277623264SMatthew G. Knepley   ierr = PetscFunctionListFind(PetscPartitionerList, name, &r);CHKERRQ(ierr);
72377623264SMatthew G. Knepley   if (!r) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name);
72477623264SMatthew G. Knepley 
72577623264SMatthew G. Knepley   if (part->ops->destroy) {
72677623264SMatthew G. Knepley     ierr = (*part->ops->destroy)(part);CHKERRQ(ierr);
72777623264SMatthew G. Knepley   }
728074d466cSStefano Zampini   part->noGraph = PETSC_FALSE;
72909161815SVaclav Hapla   ierr = PetscMemzero(part->ops, sizeof(struct _PetscPartitionerOps));CHKERRQ(ierr);
73077623264SMatthew G. Knepley   ierr = (*r)(part);CHKERRQ(ierr);
73177623264SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) part, name);CHKERRQ(ierr);
73277623264SMatthew G. Knepley   PetscFunctionReturn(0);
73377623264SMatthew G. Knepley }
73477623264SMatthew G. Knepley 
73577623264SMatthew G. Knepley /*@C
73677623264SMatthew G. Knepley   PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object.
73777623264SMatthew G. Knepley 
73877623264SMatthew G. Knepley   Not Collective
73977623264SMatthew G. Knepley 
74077623264SMatthew G. Knepley   Input Parameter:
74177623264SMatthew G. Knepley . part - The PetscPartitioner
74277623264SMatthew G. Knepley 
74377623264SMatthew G. Knepley   Output Parameter:
74477623264SMatthew G. Knepley . name - The PetscPartitioner type name
74577623264SMatthew G. Knepley 
74677623264SMatthew G. Knepley   Level: intermediate
74777623264SMatthew G. Knepley 
74877623264SMatthew G. Knepley .keywords: PetscPartitioner, get, type, name
74977623264SMatthew G. Knepley .seealso: PetscPartitionerSetType(), PetscPartitionerCreate()
75077623264SMatthew G. Knepley @*/
75177623264SMatthew G. Knepley PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name)
75277623264SMatthew G. Knepley {
75377623264SMatthew G. Knepley   PetscErrorCode ierr;
75477623264SMatthew G. Knepley 
75577623264SMatthew G. Knepley   PetscFunctionBegin;
75677623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
75777623264SMatthew G. Knepley   PetscValidPointer(name, 2);
7580f51fdf8SToby Isaac   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
75977623264SMatthew G. Knepley   *name = ((PetscObject) part)->type_name;
76077623264SMatthew G. Knepley   PetscFunctionReturn(0);
76177623264SMatthew G. Knepley }
76277623264SMatthew G. Knepley 
76377623264SMatthew G. Knepley /*@C
76477623264SMatthew G. Knepley   PetscPartitionerView - Views a PetscPartitioner
76577623264SMatthew G. Knepley 
76677623264SMatthew G. Knepley   Collective on PetscPartitioner
76777623264SMatthew G. Knepley 
76877623264SMatthew G. Knepley   Input Parameter:
76977623264SMatthew G. Knepley + part - the PetscPartitioner object to view
77077623264SMatthew G. Knepley - v    - the viewer
77177623264SMatthew G. Knepley 
77277623264SMatthew G. Knepley   Level: developer
77377623264SMatthew G. Knepley 
77477623264SMatthew G. Knepley .seealso: PetscPartitionerDestroy()
77577623264SMatthew G. Knepley @*/
77677623264SMatthew G. Knepley PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v)
77777623264SMatthew G. Knepley {
778ffc59708SMatthew G. Knepley   PetscMPIInt    size;
7792abdaa70SMatthew G. Knepley   PetscBool      isascii;
78077623264SMatthew G. Knepley   PetscErrorCode ierr;
78177623264SMatthew G. Knepley 
78277623264SMatthew G. Knepley   PetscFunctionBegin;
78377623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
78477623264SMatthew G. Knepley   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v);CHKERRQ(ierr);}
7852abdaa70SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
7862abdaa70SMatthew G. Knepley   if (isascii) {
7872abdaa70SMatthew G. Knepley     ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
788ffc59708SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "Graph Partitioner: %d MPI Process%s\n", size, size > 1 ? "es" : "");CHKERRQ(ierr);
7892abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "  type: %s\n", part->hdr.type_name);CHKERRQ(ierr);
7902abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr);
7912abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "edge cut: %D\n", part->edgeCut);CHKERRQ(ierr);
7922abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "balance:  %.2g\n", part->balance);CHKERRQ(ierr);
7932abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr);
7942abdaa70SMatthew G. Knepley   }
79577623264SMatthew G. Knepley   if (part->ops->view) {ierr = (*part->ops->view)(part, v);CHKERRQ(ierr);}
79677623264SMatthew G. Knepley   PetscFunctionReturn(0);
79777623264SMatthew G. Knepley }
79877623264SMatthew G. Knepley 
799a0058e54SToby Isaac static PetscErrorCode PetscPartitionerGetDefaultType(const char *currentType, const char **defaultType)
800a0058e54SToby Isaac {
801a0058e54SToby Isaac   PetscFunctionBegin;
802a0058e54SToby Isaac   if (!currentType) {
803a0058e54SToby Isaac #if defined(PETSC_HAVE_CHACO)
804a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERCHACO;
805a0058e54SToby Isaac #elif defined(PETSC_HAVE_PARMETIS)
806a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERPARMETIS;
807137cd93aSLisandro Dalcin #elif defined(PETSC_HAVE_PTSCOTCH)
808137cd93aSLisandro Dalcin     *defaultType = PETSCPARTITIONERPTSCOTCH;
809a0058e54SToby Isaac #else
810a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERSIMPLE;
811a0058e54SToby Isaac #endif
812a0058e54SToby Isaac   } else {
813a0058e54SToby Isaac     *defaultType = currentType;
814a0058e54SToby Isaac   }
815a0058e54SToby Isaac   PetscFunctionReturn(0);
816a0058e54SToby Isaac }
817a0058e54SToby Isaac 
81877623264SMatthew G. Knepley /*@
81977623264SMatthew G. Knepley   PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database
82077623264SMatthew G. Knepley 
82177623264SMatthew G. Knepley   Collective on PetscPartitioner
82277623264SMatthew G. Knepley 
82377623264SMatthew G. Knepley   Input Parameter:
82477623264SMatthew G. Knepley . part - the PetscPartitioner object to set options for
82577623264SMatthew G. Knepley 
82677623264SMatthew G. Knepley   Level: developer
82777623264SMatthew G. Knepley 
82877623264SMatthew G. Knepley .seealso: PetscPartitionerView()
82977623264SMatthew G. Knepley @*/
83077623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part)
83177623264SMatthew G. Knepley {
8326bb9daa8SLisandro Dalcin   const char    *defaultType;
8336bb9daa8SLisandro Dalcin   char           name[256];
8346bb9daa8SLisandro Dalcin   PetscBool      flg;
83577623264SMatthew G. Knepley   PetscErrorCode ierr;
83677623264SMatthew G. Knepley 
83777623264SMatthew G. Knepley   PetscFunctionBegin;
83877623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
8396bb9daa8SLisandro Dalcin   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
8406bb9daa8SLisandro Dalcin   ierr = PetscPartitionerGetDefaultType(((PetscObject) part)->type_name,&defaultType);CHKERRQ(ierr);
84177623264SMatthew G. Knepley   ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr);
8426bb9daa8SLisandro Dalcin   ierr = PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, defaultType, name, sizeof(name), &flg);CHKERRQ(ierr);
8436bb9daa8SLisandro Dalcin   if (flg) {
8446bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, name);CHKERRQ(ierr);
8456bb9daa8SLisandro Dalcin   } else if (!((PetscObject) part)->type_name) {
8466bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, defaultType);CHKERRQ(ierr);
8476bb9daa8SLisandro Dalcin   }
8486bb9daa8SLisandro Dalcin   if (part->ops->setfromoptions) {
8496bb9daa8SLisandro Dalcin     ierr = (*part->ops->setfromoptions)(PetscOptionsObject,part);CHKERRQ(ierr);
8506bb9daa8SLisandro Dalcin   }
851783e1fb6SStefano Zampini   ierr = PetscViewerDestroy(&part->viewerGraph);CHKERRQ(ierr);
8520358368aSMatthew G. Knepley   ierr = PetscOptionsGetViewer(((PetscObject) part)->comm, ((PetscObject) part)->options, ((PetscObject) part)->prefix, "-petscpartitioner_view_graph", &part->viewerGraph, &part->formatGraph, &part->viewGraph);CHKERRQ(ierr);
85377623264SMatthew G. Knepley   /* process any options handlers added with PetscObjectAddOptionsHandler() */
8540633abcbSJed Brown   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) part);CHKERRQ(ierr);
85577623264SMatthew G. Knepley   ierr = PetscOptionsEnd();CHKERRQ(ierr);
85677623264SMatthew G. Knepley   PetscFunctionReturn(0);
85777623264SMatthew G. Knepley }
85877623264SMatthew G. Knepley 
85977623264SMatthew G. Knepley /*@C
86077623264SMatthew G. Knepley   PetscPartitionerSetUp - Construct data structures for the PetscPartitioner
86177623264SMatthew G. Knepley 
86277623264SMatthew G. Knepley   Collective on PetscPartitioner
86377623264SMatthew G. Knepley 
86477623264SMatthew G. Knepley   Input Parameter:
86577623264SMatthew G. Knepley . part - the PetscPartitioner object to setup
86677623264SMatthew G. Knepley 
86777623264SMatthew G. Knepley   Level: developer
86877623264SMatthew G. Knepley 
86977623264SMatthew G. Knepley .seealso: PetscPartitionerView(), PetscPartitionerDestroy()
87077623264SMatthew G. Knepley @*/
87177623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part)
87277623264SMatthew G. Knepley {
87377623264SMatthew G. Knepley   PetscErrorCode ierr;
87477623264SMatthew G. Knepley 
87577623264SMatthew G. Knepley   PetscFunctionBegin;
87677623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
87777623264SMatthew G. Knepley   if (part->ops->setup) {ierr = (*part->ops->setup)(part);CHKERRQ(ierr);}
87877623264SMatthew G. Knepley   PetscFunctionReturn(0);
87977623264SMatthew G. Knepley }
88077623264SMatthew G. Knepley 
88177623264SMatthew G. Knepley /*@
88277623264SMatthew G. Knepley   PetscPartitionerDestroy - Destroys a PetscPartitioner object
88377623264SMatthew G. Knepley 
88477623264SMatthew G. Knepley   Collective on PetscPartitioner
88577623264SMatthew G. Knepley 
88677623264SMatthew G. Knepley   Input Parameter:
88777623264SMatthew G. Knepley . part - the PetscPartitioner object to destroy
88877623264SMatthew G. Knepley 
88977623264SMatthew G. Knepley   Level: developer
89077623264SMatthew G. Knepley 
89177623264SMatthew G. Knepley .seealso: PetscPartitionerView()
89277623264SMatthew G. Knepley @*/
89377623264SMatthew G. Knepley PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part)
89477623264SMatthew G. Knepley {
89577623264SMatthew G. Knepley   PetscErrorCode ierr;
89677623264SMatthew G. Knepley 
89777623264SMatthew G. Knepley   PetscFunctionBegin;
89877623264SMatthew G. Knepley   if (!*part) PetscFunctionReturn(0);
89977623264SMatthew G. Knepley   PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1);
90077623264SMatthew G. Knepley 
90177623264SMatthew G. Knepley   if (--((PetscObject)(*part))->refct > 0) {*part = 0; PetscFunctionReturn(0);}
90277623264SMatthew G. Knepley   ((PetscObject) (*part))->refct = 0;
90377623264SMatthew G. Knepley 
9040358368aSMatthew G. Knepley   ierr = PetscViewerDestroy(&(*part)->viewerGraph);CHKERRQ(ierr);
90577623264SMatthew G. Knepley   if ((*part)->ops->destroy) {ierr = (*(*part)->ops->destroy)(*part);CHKERRQ(ierr);}
90677623264SMatthew G. Knepley   ierr = PetscHeaderDestroy(part);CHKERRQ(ierr);
90777623264SMatthew G. Knepley   PetscFunctionReturn(0);
90877623264SMatthew G. Knepley }
90977623264SMatthew G. Knepley 
91077623264SMatthew G. Knepley /*@
91177623264SMatthew G. Knepley   PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType().
91277623264SMatthew G. Knepley 
91377623264SMatthew G. Knepley   Collective on MPI_Comm
91477623264SMatthew G. Knepley 
91577623264SMatthew G. Knepley   Input Parameter:
91677623264SMatthew G. Knepley . comm - The communicator for the PetscPartitioner object
91777623264SMatthew G. Knepley 
91877623264SMatthew G. Knepley   Output Parameter:
91977623264SMatthew G. Knepley . part - The PetscPartitioner object
92077623264SMatthew G. Knepley 
92177623264SMatthew G. Knepley   Level: beginner
92277623264SMatthew G. Knepley 
923dae52e14SToby Isaac .seealso: PetscPartitionerSetType(), PETSCPARTITIONERCHACO, PETSCPARTITIONERPARMETIS, PETSCPARTITIONERSHELL, PETSCPARTITIONERSIMPLE, PETSCPARTITIONERGATHER
92477623264SMatthew G. Knepley @*/
92577623264SMatthew G. Knepley PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
92677623264SMatthew G. Knepley {
92777623264SMatthew G. Knepley   PetscPartitioner p;
928a0058e54SToby Isaac   const char       *partitionerType = NULL;
92977623264SMatthew G. Knepley   PetscErrorCode   ierr;
93077623264SMatthew G. Knepley 
93177623264SMatthew G. Knepley   PetscFunctionBegin;
93277623264SMatthew G. Knepley   PetscValidPointer(part, 2);
93377623264SMatthew G. Knepley   *part = NULL;
93483cde681SMatthew G. Knepley   ierr = DMInitializePackage();CHKERRQ(ierr);
93577623264SMatthew G. Knepley 
93673107ff1SLisandro Dalcin   ierr = PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView);CHKERRQ(ierr);
937a0058e54SToby Isaac   ierr = PetscPartitionerGetDefaultType(NULL,&partitionerType);CHKERRQ(ierr);
938a0058e54SToby Isaac   ierr = PetscPartitionerSetType(p,partitionerType);CHKERRQ(ierr);
93977623264SMatthew G. Knepley 
94072379da4SMatthew G. Knepley   p->edgeCut = 0;
94172379da4SMatthew G. Knepley   p->balance = 0.0;
94272379da4SMatthew G. Knepley 
94377623264SMatthew G. Knepley   *part = p;
94477623264SMatthew G. Knepley   PetscFunctionReturn(0);
94577623264SMatthew G. Knepley }
94677623264SMatthew G. Knepley 
94777623264SMatthew G. Knepley /*@
94877623264SMatthew G. Knepley   PetscPartitionerPartition - Create a non-overlapping partition of the cells in the mesh
94977623264SMatthew G. Knepley 
95077623264SMatthew G. Knepley   Collective on DM
95177623264SMatthew G. Knepley 
95277623264SMatthew G. Knepley   Input Parameters:
95377623264SMatthew G. Knepley + part    - The PetscPartitioner
954f8987ae8SMichael Lange - dm      - The mesh DM
95577623264SMatthew G. Knepley 
95677623264SMatthew G. Knepley   Output Parameters:
95777623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
958f8987ae8SMichael Lange - partition       - The list of points by partition
95977623264SMatthew G. Knepley 
9600358368aSMatthew G. Knepley   Options Database:
9610358368aSMatthew G. Knepley . -petscpartitioner_view_graph - View the graph we are partitioning
9620358368aSMatthew G. Knepley 
96377623264SMatthew G. Knepley   Note: Instead of cells, points at a given height can be partitioned by calling PetscPartitionerSetPointHeight()
96477623264SMatthew G. Knepley 
96577623264SMatthew G. Knepley   Level: developer
96677623264SMatthew G. Knepley 
96777623264SMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerSetPointHeight(), PetscPartitionerCreate()
9684b15ede2SMatthew G. Knepley @*/
969f8987ae8SMichael Lange PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, DM dm, PetscSection partSection, IS *partition)
97077623264SMatthew G. Knepley {
97177623264SMatthew G. Knepley   PetscMPIInt    size;
97277623264SMatthew G. Knepley   PetscErrorCode ierr;
97377623264SMatthew G. Knepley 
97477623264SMatthew G. Knepley   PetscFunctionBegin;
97577623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
97677623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
97777623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
97877623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
97977623264SMatthew G. Knepley   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
98077623264SMatthew G. Knepley   if (size == 1) {
98177623264SMatthew G. Knepley     PetscInt *points;
98277623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
98377623264SMatthew G. Knepley 
98477623264SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
98577623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr);
98677623264SMatthew G. Knepley     ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr);
98777623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
98877623264SMatthew G. Knepley     ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr);
98977623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
99077623264SMatthew G. Knepley     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
99177623264SMatthew G. Knepley     PetscFunctionReturn(0);
99277623264SMatthew G. Knepley   }
99377623264SMatthew G. Knepley   if (part->height == 0) {
994074d466cSStefano Zampini     PetscInt numVertices = 0;
99577623264SMatthew G. Knepley     PetscInt *start     = NULL;
99677623264SMatthew G. Knepley     PetscInt *adjacency = NULL;
9973fa7752dSToby Isaac     IS       globalNumbering;
99877623264SMatthew G. Knepley 
999074d466cSStefano Zampini     if (!part->noGraph || part->viewGraph) {
1000074d466cSStefano Zampini       ierr = DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering);CHKERRQ(ierr);
1001074d466cSStefano Zampini     } else {
1002074d466cSStefano Zampini       const PetscInt *idxs;
1003074d466cSStefano Zampini       PetscInt       p, pStart, pEnd;
1004074d466cSStefano Zampini 
1005074d466cSStefano Zampini       ierr = DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd);CHKERRQ(ierr);
1006074d466cSStefano Zampini       ierr = DMPlexCreateNumbering_Internal(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering);CHKERRQ(ierr);
1007074d466cSStefano Zampini       ierr = ISGetIndices(globalNumbering, &idxs);CHKERRQ(ierr);
1008074d466cSStefano Zampini       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
1009074d466cSStefano Zampini       ierr = ISRestoreIndices(globalNumbering, &idxs);CHKERRQ(ierr);
1010074d466cSStefano Zampini     }
10110358368aSMatthew G. Knepley     if (part->viewGraph) {
10120358368aSMatthew G. Knepley       PetscViewer viewer = part->viewerGraph;
10130358368aSMatthew G. Knepley       PetscBool   isascii;
10140358368aSMatthew G. Knepley       PetscInt    v, i;
10150358368aSMatthew G. Knepley       PetscMPIInt rank;
10160358368aSMatthew G. Knepley 
10170358368aSMatthew G. Knepley       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) viewer), &rank);CHKERRQ(ierr);
10180358368aSMatthew G. Knepley       ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
10190358368aSMatthew G. Knepley       if (isascii) {
10200358368aSMatthew G. Knepley         ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
10210358368aSMatthew G. Knepley         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]Nv: %D\n", rank, numVertices);CHKERRQ(ierr);
10220358368aSMatthew G. Knepley         for (v = 0; v < numVertices; ++v) {
10230358368aSMatthew G. Knepley           const PetscInt s = start[v];
10240358368aSMatthew G. Knepley           const PetscInt e = start[v+1];
10250358368aSMatthew G. Knepley 
10260358368aSMatthew G. Knepley           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]  ", rank);CHKERRQ(ierr);
10270358368aSMatthew G. Knepley           for (i = s; i < e; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%D ", adjacency[i]);CHKERRQ(ierr);}
10280358368aSMatthew G. Knepley           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D-%D)\n", s, e);CHKERRQ(ierr);
10290358368aSMatthew G. Knepley         }
10300358368aSMatthew G. Knepley         ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
10310358368aSMatthew G. Knepley         ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
10320358368aSMatthew G. Knepley       }
10330358368aSMatthew G. Knepley     }
1034*bbbc8e51SStefano Zampini     if (!part->ops->partition) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_WRONGSTATE, "PetscPartitioner has no partitioning method");
103577623264SMatthew G. Knepley     ierr = (*part->ops->partition)(part, dm, size, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
103677623264SMatthew G. Knepley     ierr = PetscFree(start);CHKERRQ(ierr);
103777623264SMatthew G. Knepley     ierr = PetscFree(adjacency);CHKERRQ(ierr);
10383fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
10393fa7752dSToby Isaac       const PetscInt *globalNum;
10403fa7752dSToby Isaac       const PetscInt *partIdx;
10413fa7752dSToby Isaac       PetscInt       *map, cStart, cEnd;
10423fa7752dSToby Isaac       PetscInt       *adjusted, i, localSize, offset;
10433fa7752dSToby Isaac       IS             newPartition;
10443fa7752dSToby Isaac 
10453fa7752dSToby Isaac       ierr = ISGetLocalSize(*partition,&localSize);CHKERRQ(ierr);
10463fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&adjusted);CHKERRQ(ierr);
10473fa7752dSToby Isaac       ierr = ISGetIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
10483fa7752dSToby Isaac       ierr = ISGetIndices(*partition,&partIdx);CHKERRQ(ierr);
10493fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&map);CHKERRQ(ierr);
10503fa7752dSToby Isaac       ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
10513fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
10523fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
10533fa7752dSToby Isaac       }
10543fa7752dSToby Isaac       for (i = 0; i < localSize; i++) {
10553fa7752dSToby Isaac         adjusted[i] = map[partIdx[i]];
10563fa7752dSToby Isaac       }
10573fa7752dSToby Isaac       ierr = PetscFree(map);CHKERRQ(ierr);
10583fa7752dSToby Isaac       ierr = ISRestoreIndices(*partition,&partIdx);CHKERRQ(ierr);
10593fa7752dSToby Isaac       ierr = ISRestoreIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
10603fa7752dSToby Isaac       ierr = ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition);CHKERRQ(ierr);
10613fa7752dSToby Isaac       ierr = ISDestroy(&globalNumbering);CHKERRQ(ierr);
10623fa7752dSToby Isaac       ierr = ISDestroy(partition);CHKERRQ(ierr);
10633fa7752dSToby Isaac       *partition = newPartition;
10643fa7752dSToby Isaac     }
106577623264SMatthew G. Knepley   } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height);
10662abdaa70SMatthew G. Knepley   ierr = PetscPartitionerViewFromOptions(part, NULL, "-petscpartitioner_view");CHKERRQ(ierr);
106777623264SMatthew G. Knepley   PetscFunctionReturn(0);
106877623264SMatthew G. Knepley }
106977623264SMatthew G. Knepley 
1070d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Shell(PetscPartitioner part)
107177623264SMatthew G. Knepley {
107277623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
107377623264SMatthew G. Knepley   PetscErrorCode          ierr;
107477623264SMatthew G. Knepley 
107577623264SMatthew G. Knepley   PetscFunctionBegin;
107677623264SMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
107777623264SMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
107877623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
107977623264SMatthew G. Knepley   PetscFunctionReturn(0);
108077623264SMatthew G. Knepley }
108177623264SMatthew G. Knepley 
1082d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell_Ascii(PetscPartitioner part, PetscViewer viewer)
108377623264SMatthew G. Knepley {
1084077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
108577623264SMatthew G. Knepley   PetscErrorCode          ierr;
108677623264SMatthew G. Knepley 
108777623264SMatthew G. Knepley   PetscFunctionBegin;
1088077101c0SMatthew G. Knepley   if (p->random) {
1089077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1090077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(viewer, "using random partition\n");CHKERRQ(ierr);
1091077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1092077101c0SMatthew G. Knepley   }
109377623264SMatthew G. Knepley   PetscFunctionReturn(0);
109477623264SMatthew G. Knepley }
109577623264SMatthew G. Knepley 
1096d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell(PetscPartitioner part, PetscViewer viewer)
109777623264SMatthew G. Knepley {
109877623264SMatthew G. Knepley   PetscBool      iascii;
109977623264SMatthew G. Knepley   PetscErrorCode ierr;
110077623264SMatthew G. Knepley 
110177623264SMatthew G. Knepley   PetscFunctionBegin;
110277623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
110377623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
110477623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
110577623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Shell_Ascii(part, viewer);CHKERRQ(ierr);}
110677623264SMatthew G. Knepley   PetscFunctionReturn(0);
110777623264SMatthew G. Knepley }
110877623264SMatthew G. Knepley 
1109d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerSetFromOptions_Shell(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
1110077101c0SMatthew G. Knepley {
1111077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1112077101c0SMatthew G. Knepley   PetscErrorCode          ierr;
1113077101c0SMatthew G. Knepley 
1114077101c0SMatthew G. Knepley   PetscFunctionBegin;
1115077101c0SMatthew G. Knepley   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner Shell Options");CHKERRQ(ierr);
1116077101c0SMatthew G. Knepley   ierr = PetscOptionsBool("-petscpartitioner_shell_random", "Use a random partition", "PetscPartitionerView", PETSC_FALSE, &p->random, NULL);CHKERRQ(ierr);
1117077101c0SMatthew G. Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1118077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1119077101c0SMatthew G. Knepley }
1120077101c0SMatthew G. Knepley 
1121d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Shell(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
112277623264SMatthew G. Knepley {
112377623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
112477623264SMatthew G. Knepley   PetscInt                np;
112577623264SMatthew G. Knepley   PetscErrorCode          ierr;
112677623264SMatthew G. Knepley 
112777623264SMatthew G. Knepley   PetscFunctionBegin;
1128077101c0SMatthew G. Knepley   if (p->random) {
1129077101c0SMatthew G. Knepley     PetscRandom r;
1130aa1d5631SMatthew G. Knepley     PetscInt   *sizes, *points, v, p;
1131aa1d5631SMatthew G. Knepley     PetscMPIInt rank;
1132077101c0SMatthew G. Knepley 
1133aa1d5631SMatthew G. Knepley     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
1134077101c0SMatthew G. Knepley     ierr = PetscRandomCreate(PETSC_COMM_SELF, &r);CHKERRQ(ierr);
1135c717d290SMatthew G. Knepley     ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) nparts);CHKERRQ(ierr);
1136077101c0SMatthew G. Knepley     ierr = PetscRandomSetFromOptions(r);CHKERRQ(ierr);
1137077101c0SMatthew G. Knepley     ierr = PetscCalloc2(nparts, &sizes, numVertices, &points);CHKERRQ(ierr);
1138aa1d5631SMatthew G. Knepley     for (v = 0; v < numVertices; ++v) {points[v] = v;}
1139ac9a96f1SMichael Lange     for (p = 0; p < nparts; ++p) {sizes[p] = numVertices/nparts + (PetscInt) (p < numVertices % nparts);}
1140aa1d5631SMatthew G. Knepley     for (v = numVertices-1; v > 0; --v) {
1141077101c0SMatthew G. Knepley       PetscReal val;
1142aa1d5631SMatthew G. Knepley       PetscInt  w, tmp;
1143077101c0SMatthew G. Knepley 
1144aa1d5631SMatthew G. Knepley       ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) (v+1));CHKERRQ(ierr);
1145077101c0SMatthew G. Knepley       ierr = PetscRandomGetValueReal(r, &val);CHKERRQ(ierr);
1146aa1d5631SMatthew G. Knepley       w    = PetscFloorReal(val);
1147aa1d5631SMatthew G. Knepley       tmp       = points[v];
1148aa1d5631SMatthew G. Knepley       points[v] = points[w];
1149aa1d5631SMatthew G. Knepley       points[w] = tmp;
1150077101c0SMatthew G. Knepley     }
1151077101c0SMatthew G. Knepley     ierr = PetscRandomDestroy(&r);CHKERRQ(ierr);
1152077101c0SMatthew G. Knepley     ierr = PetscPartitionerShellSetPartition(part, nparts, sizes, points);CHKERRQ(ierr);
1153077101c0SMatthew G. Knepley     ierr = PetscFree2(sizes, points);CHKERRQ(ierr);
1154077101c0SMatthew G. Knepley   }
1155c717d290SMatthew G. Knepley   if (!p->section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Shell partitioner information not provided. Please call PetscPartitionerShellSetPartition()");
115677623264SMatthew G. Knepley   ierr = PetscSectionGetChart(p->section, NULL, &np);CHKERRQ(ierr);
115777623264SMatthew G. Knepley   if (nparts != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of requested partitions %d != configured partitions %d", nparts, np);
115877623264SMatthew G. Knepley   ierr = ISGetLocalSize(p->partition, &np);CHKERRQ(ierr);
115977623264SMatthew G. Knepley   if (numVertices != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input vertices %d != configured vertices %d", numVertices, np);
11605680f57bSMatthew G. Knepley   ierr = PetscSectionCopy(p->section, partSection);CHKERRQ(ierr);
116177623264SMatthew G. Knepley   *partition = p->partition;
116277623264SMatthew G. Knepley   ierr = PetscObjectReference((PetscObject) p->partition);CHKERRQ(ierr);
116377623264SMatthew G. Knepley   PetscFunctionReturn(0);
116477623264SMatthew G. Knepley }
116577623264SMatthew G. Knepley 
1166d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Shell(PetscPartitioner part)
116777623264SMatthew G. Knepley {
116877623264SMatthew G. Knepley   PetscFunctionBegin;
1169074d466cSStefano Zampini   part->noGraph             = PETSC_TRUE; /* PetscPartitionerShell cannot overload the partition call, so it is safe for now */
117077623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_Shell;
1171077101c0SMatthew G. Knepley   part->ops->setfromoptions = PetscPartitionerSetFromOptions_Shell;
117277623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_Shell;
117377623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_Shell;
117477623264SMatthew G. Knepley   PetscFunctionReturn(0);
117577623264SMatthew G. Knepley }
117677623264SMatthew G. Knepley 
117777623264SMatthew G. Knepley /*MC
117877623264SMatthew G. Knepley   PETSCPARTITIONERSHELL = "shell" - A PetscPartitioner object
117977623264SMatthew G. Knepley 
118077623264SMatthew G. Knepley   Level: intermediate
118177623264SMatthew G. Knepley 
118277623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
118377623264SMatthew G. Knepley M*/
118477623264SMatthew G. Knepley 
118577623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Shell(PetscPartitioner part)
118677623264SMatthew G. Knepley {
118777623264SMatthew G. Knepley   PetscPartitioner_Shell *p;
118877623264SMatthew G. Knepley   PetscErrorCode          ierr;
118977623264SMatthew G. Knepley 
119077623264SMatthew G. Knepley   PetscFunctionBegin;
119177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
119277623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
119377623264SMatthew G. Knepley   part->data = p;
119477623264SMatthew G. Knepley 
119577623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Shell(part);CHKERRQ(ierr);
1196077101c0SMatthew G. Knepley   p->random = PETSC_FALSE;
119777623264SMatthew G. Knepley   PetscFunctionReturn(0);
119877623264SMatthew G. Knepley }
119977623264SMatthew G. Knepley 
12005680f57bSMatthew G. Knepley /*@C
12015680f57bSMatthew G. Knepley   PetscPartitionerShellSetPartition - Set an artifical partition for a mesh
12025680f57bSMatthew G. Knepley 
1203077101c0SMatthew G. Knepley   Collective on Part
12045680f57bSMatthew G. Knepley 
12055680f57bSMatthew G. Knepley   Input Parameters:
12065680f57bSMatthew G. Knepley + part   - The PetscPartitioner
12079852e123SBarry Smith . size   - The number of partitions
12089852e123SBarry Smith . sizes  - array of size size (or NULL) providing the number of points in each partition
12099758bf69SToby Isaac - points - array of size sum(sizes) (may be NULL iff sizes is NULL), a permutation of the points that groups those assigned to each partition in order (i.e., partition 0 first, partition 1 next, etc.)
12105680f57bSMatthew G. Knepley 
12115680f57bSMatthew G. Knepley   Level: developer
12125680f57bSMatthew G. Knepley 
1213b7e49471SLawrence Mitchell   Notes:
1214b7e49471SLawrence Mitchell 
1215b7e49471SLawrence Mitchell     It is safe to free the sizes and points arrays after use in this routine.
1216b7e49471SLawrence Mitchell 
12175680f57bSMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerCreate()
12185680f57bSMatthew G. Knepley @*/
12199852e123SBarry Smith PetscErrorCode PetscPartitionerShellSetPartition(PetscPartitioner part, PetscInt size, const PetscInt sizes[], const PetscInt points[])
12205680f57bSMatthew G. Knepley {
12215680f57bSMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
12225680f57bSMatthew G. Knepley   PetscInt                proc, numPoints;
12235680f57bSMatthew G. Knepley   PetscErrorCode          ierr;
12245680f57bSMatthew G. Knepley 
12255680f57bSMatthew G. Knepley   PetscFunctionBegin;
12265680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
12275680f57bSMatthew G. Knepley   if (sizes)  {PetscValidPointer(sizes, 3);}
1228c717d290SMatthew G. Knepley   if (points) {PetscValidPointer(points, 4);}
12295680f57bSMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
12305680f57bSMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
12315680f57bSMatthew G. Knepley   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) part), &p->section);CHKERRQ(ierr);
12329852e123SBarry Smith   ierr = PetscSectionSetChart(p->section, 0, size);CHKERRQ(ierr);
12335680f57bSMatthew G. Knepley   if (sizes) {
12349852e123SBarry Smith     for (proc = 0; proc < size; ++proc) {
12355680f57bSMatthew G. Knepley       ierr = PetscSectionSetDof(p->section, proc, sizes[proc]);CHKERRQ(ierr);
12365680f57bSMatthew G. Knepley     }
12375680f57bSMatthew G. Knepley   }
12385680f57bSMatthew G. Knepley   ierr = PetscSectionSetUp(p->section);CHKERRQ(ierr);
12395680f57bSMatthew G. Knepley   ierr = PetscSectionGetStorageSize(p->section, &numPoints);CHKERRQ(ierr);
12405680f57bSMatthew G. Knepley   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), numPoints, points, PETSC_COPY_VALUES, &p->partition);CHKERRQ(ierr);
12415680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
12425680f57bSMatthew G. Knepley }
12435680f57bSMatthew G. Knepley 
1244077101c0SMatthew G. Knepley /*@
1245077101c0SMatthew G. Knepley   PetscPartitionerShellSetRandom - Set the flag to use a random partition
1246077101c0SMatthew G. Knepley 
1247077101c0SMatthew G. Knepley   Collective on Part
1248077101c0SMatthew G. Knepley 
1249077101c0SMatthew G. Knepley   Input Parameters:
1250077101c0SMatthew G. Knepley + part   - The PetscPartitioner
1251077101c0SMatthew G. Knepley - random - The flag to use a random partition
1252077101c0SMatthew G. Knepley 
1253077101c0SMatthew G. Knepley   Level: intermediate
1254077101c0SMatthew G. Knepley 
1255077101c0SMatthew G. Knepley .seealso PetscPartitionerShellGetRandom(), PetscPartitionerCreate()
1256077101c0SMatthew G. Knepley @*/
1257077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellSetRandom(PetscPartitioner part, PetscBool random)
1258077101c0SMatthew G. Knepley {
1259077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1260077101c0SMatthew G. Knepley 
1261077101c0SMatthew G. Knepley   PetscFunctionBegin;
1262077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1263077101c0SMatthew G. Knepley   p->random = random;
1264077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1265077101c0SMatthew G. Knepley }
1266077101c0SMatthew G. Knepley 
1267077101c0SMatthew G. Knepley /*@
1268077101c0SMatthew G. Knepley   PetscPartitionerShellGetRandom - get the flag to use a random partition
1269077101c0SMatthew G. Knepley 
1270077101c0SMatthew G. Knepley   Collective on Part
1271077101c0SMatthew G. Knepley 
1272077101c0SMatthew G. Knepley   Input Parameter:
1273077101c0SMatthew G. Knepley . part   - The PetscPartitioner
1274077101c0SMatthew G. Knepley 
1275077101c0SMatthew G. Knepley   Output Parameter
1276077101c0SMatthew G. Knepley . random - The flag to use a random partition
1277077101c0SMatthew G. Knepley 
1278077101c0SMatthew G. Knepley   Level: intermediate
1279077101c0SMatthew G. Knepley 
1280077101c0SMatthew G. Knepley .seealso PetscPartitionerShellSetRandom(), PetscPartitionerCreate()
1281077101c0SMatthew G. Knepley @*/
1282077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellGetRandom(PetscPartitioner part, PetscBool *random)
1283077101c0SMatthew G. Knepley {
1284077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1285077101c0SMatthew G. Knepley 
1286077101c0SMatthew G. Knepley   PetscFunctionBegin;
1287077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1288077101c0SMatthew G. Knepley   PetscValidPointer(random, 2);
1289077101c0SMatthew G. Knepley   *random = p->random;
1290077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1291077101c0SMatthew G. Knepley }
1292077101c0SMatthew G. Knepley 
1293d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Simple(PetscPartitioner part)
1294555a9cf8SMatthew G. Knepley {
1295555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p = (PetscPartitioner_Simple *) part->data;
1296555a9cf8SMatthew G. Knepley   PetscErrorCode          ierr;
1297555a9cf8SMatthew G. Knepley 
1298555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1299555a9cf8SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
1300555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1301555a9cf8SMatthew G. Knepley }
1302555a9cf8SMatthew G. Knepley 
1303d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple_Ascii(PetscPartitioner part, PetscViewer viewer)
1304555a9cf8SMatthew G. Knepley {
1305555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1306555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1307555a9cf8SMatthew G. Knepley }
1308555a9cf8SMatthew G. Knepley 
1309d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple(PetscPartitioner part, PetscViewer viewer)
1310555a9cf8SMatthew G. Knepley {
1311555a9cf8SMatthew G. Knepley   PetscBool      iascii;
1312555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1313555a9cf8SMatthew G. Knepley 
1314555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1315555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1316555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1317555a9cf8SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1318555a9cf8SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Simple_Ascii(part, viewer);CHKERRQ(ierr);}
1319555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1320555a9cf8SMatthew G. Knepley }
1321555a9cf8SMatthew G. Knepley 
1322d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Simple(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1323555a9cf8SMatthew G. Knepley {
1324cead94edSToby Isaac   MPI_Comm       comm;
1325555a9cf8SMatthew G. Knepley   PetscInt       np;
1326cead94edSToby Isaac   PetscMPIInt    size;
1327555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1328555a9cf8SMatthew G. Knepley 
1329555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
133004ba2274SStefano Zampini   comm = PetscObjectComm((PetscObject)part);
1331cead94edSToby Isaac   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1332555a9cf8SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1333555a9cf8SMatthew G. Knepley   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1334cead94edSToby Isaac   if (size == 1) {
1335cead94edSToby Isaac     for (np = 0; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, numVertices/nparts + ((numVertices % nparts) > np));CHKERRQ(ierr);}
133604ba2274SStefano Zampini   } else {
1337cead94edSToby Isaac     PetscMPIInt rank;
1338cead94edSToby Isaac     PetscInt nvGlobal, *offsets, myFirst, myLast;
1339cead94edSToby Isaac 
1340a679a563SToby Isaac     ierr = PetscMalloc1(size+1,&offsets);CHKERRQ(ierr);
1341cead94edSToby Isaac     offsets[0] = 0;
1342cead94edSToby Isaac     ierr = MPI_Allgather(&numVertices,1,MPIU_INT,&offsets[1],1,MPIU_INT,comm);CHKERRQ(ierr);
1343cead94edSToby Isaac     for (np = 2; np <= size; np++) {
1344cead94edSToby Isaac       offsets[np] += offsets[np-1];
1345cead94edSToby Isaac     }
1346cead94edSToby Isaac     nvGlobal = offsets[size];
1347cead94edSToby Isaac     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1348cead94edSToby Isaac     myFirst = offsets[rank];
1349cead94edSToby Isaac     myLast  = offsets[rank + 1] - 1;
1350cead94edSToby Isaac     ierr = PetscFree(offsets);CHKERRQ(ierr);
1351cead94edSToby Isaac     if (numVertices) {
1352cead94edSToby Isaac       PetscInt firstPart = 0, firstLargePart = 0;
1353cead94edSToby Isaac       PetscInt lastPart = 0, lastLargePart = 0;
1354cead94edSToby Isaac       PetscInt rem = nvGlobal % nparts;
1355cead94edSToby Isaac       PetscInt pSmall = nvGlobal/nparts;
1356cead94edSToby Isaac       PetscInt pBig = nvGlobal/nparts + 1;
1357cead94edSToby Isaac 
1358cead94edSToby Isaac 
1359cead94edSToby Isaac       if (rem) {
1360cead94edSToby Isaac         firstLargePart = myFirst / pBig;
1361cead94edSToby Isaac         lastLargePart  = myLast  / pBig;
1362cead94edSToby Isaac 
1363cead94edSToby Isaac         if (firstLargePart < rem) {
1364cead94edSToby Isaac           firstPart = firstLargePart;
136504ba2274SStefano Zampini         } else {
1366cead94edSToby Isaac           firstPart = rem + (myFirst - (rem * pBig)) / pSmall;
1367cead94edSToby Isaac         }
1368cead94edSToby Isaac         if (lastLargePart < rem) {
1369cead94edSToby Isaac           lastPart = lastLargePart;
137004ba2274SStefano Zampini         } else {
1371cead94edSToby Isaac           lastPart = rem + (myLast - (rem * pBig)) / pSmall;
1372cead94edSToby Isaac         }
137304ba2274SStefano Zampini       } else {
1374cead94edSToby Isaac         firstPart = myFirst / (nvGlobal/nparts);
1375cead94edSToby Isaac         lastPart  = myLast  / (nvGlobal/nparts);
1376cead94edSToby Isaac       }
1377cead94edSToby Isaac 
1378cead94edSToby Isaac       for (np = firstPart; np <= lastPart; np++) {
1379cead94edSToby Isaac         PetscInt PartStart =  np    * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np);
1380cead94edSToby Isaac         PetscInt PartEnd   = (np+1) * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np+1);
1381cead94edSToby Isaac 
1382cead94edSToby Isaac         PartStart = PetscMax(PartStart,myFirst);
1383cead94edSToby Isaac         PartEnd   = PetscMin(PartEnd,myLast+1);
1384cead94edSToby Isaac         ierr = PetscSectionSetDof(partSection,np,PartEnd-PartStart);CHKERRQ(ierr);
1385cead94edSToby Isaac       }
1386cead94edSToby Isaac     }
1387cead94edSToby Isaac   }
1388cead94edSToby Isaac   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1389555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1390555a9cf8SMatthew G. Knepley }
1391555a9cf8SMatthew G. Knepley 
1392d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Simple(PetscPartitioner part)
1393555a9cf8SMatthew G. Knepley {
1394555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1395074d466cSStefano Zampini   part->noGraph        = PETSC_TRUE;
1396555a9cf8SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Simple;
1397555a9cf8SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Simple;
1398555a9cf8SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Simple;
1399555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1400555a9cf8SMatthew G. Knepley }
1401555a9cf8SMatthew G. Knepley 
1402555a9cf8SMatthew G. Knepley /*MC
1403555a9cf8SMatthew G. Knepley   PETSCPARTITIONERSIMPLE = "simple" - A PetscPartitioner object
1404555a9cf8SMatthew G. Knepley 
1405555a9cf8SMatthew G. Knepley   Level: intermediate
1406555a9cf8SMatthew G. Knepley 
1407555a9cf8SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1408555a9cf8SMatthew G. Knepley M*/
1409555a9cf8SMatthew G. Knepley 
1410555a9cf8SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Simple(PetscPartitioner part)
1411555a9cf8SMatthew G. Knepley {
1412555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p;
1413555a9cf8SMatthew G. Knepley   PetscErrorCode           ierr;
1414555a9cf8SMatthew G. Knepley 
1415555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1416555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1417555a9cf8SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1418555a9cf8SMatthew G. Knepley   part->data = p;
1419555a9cf8SMatthew G. Knepley 
1420555a9cf8SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Simple(part);CHKERRQ(ierr);
1421555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1422555a9cf8SMatthew G. Knepley }
1423555a9cf8SMatthew G. Knepley 
1424d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Gather(PetscPartitioner part)
1425dae52e14SToby Isaac {
1426dae52e14SToby Isaac   PetscPartitioner_Gather *p = (PetscPartitioner_Gather *) part->data;
1427dae52e14SToby Isaac   PetscErrorCode          ierr;
1428dae52e14SToby Isaac 
1429dae52e14SToby Isaac   PetscFunctionBegin;
1430dae52e14SToby Isaac   ierr = PetscFree(p);CHKERRQ(ierr);
1431dae52e14SToby Isaac   PetscFunctionReturn(0);
1432dae52e14SToby Isaac }
1433dae52e14SToby Isaac 
1434d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather_Ascii(PetscPartitioner part, PetscViewer viewer)
1435dae52e14SToby Isaac {
1436dae52e14SToby Isaac   PetscFunctionBegin;
1437dae52e14SToby Isaac   PetscFunctionReturn(0);
1438dae52e14SToby Isaac }
1439dae52e14SToby Isaac 
1440d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather(PetscPartitioner part, PetscViewer viewer)
1441dae52e14SToby Isaac {
1442dae52e14SToby Isaac   PetscBool      iascii;
1443dae52e14SToby Isaac   PetscErrorCode ierr;
1444dae52e14SToby Isaac 
1445dae52e14SToby Isaac   PetscFunctionBegin;
1446dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1447dae52e14SToby Isaac   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1448dae52e14SToby Isaac   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1449dae52e14SToby Isaac   if (iascii) {ierr = PetscPartitionerView_Gather_Ascii(part, viewer);CHKERRQ(ierr);}
1450dae52e14SToby Isaac   PetscFunctionReturn(0);
1451dae52e14SToby Isaac }
1452dae52e14SToby Isaac 
1453d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Gather(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1454dae52e14SToby Isaac {
1455dae52e14SToby Isaac   PetscInt       np;
1456dae52e14SToby Isaac   PetscErrorCode ierr;
1457dae52e14SToby Isaac 
1458dae52e14SToby Isaac   PetscFunctionBegin;
1459dae52e14SToby Isaac   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1460dae52e14SToby Isaac   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1461dae52e14SToby Isaac   ierr = PetscSectionSetDof(partSection,0,numVertices);CHKERRQ(ierr);
1462dae52e14SToby Isaac   for (np = 1; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, 0);CHKERRQ(ierr);}
1463dae52e14SToby Isaac   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1464dae52e14SToby Isaac   PetscFunctionReturn(0);
1465dae52e14SToby Isaac }
1466dae52e14SToby Isaac 
1467d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Gather(PetscPartitioner part)
1468dae52e14SToby Isaac {
1469dae52e14SToby Isaac   PetscFunctionBegin;
1470074d466cSStefano Zampini   part->noGraph        = PETSC_TRUE;
1471dae52e14SToby Isaac   part->ops->view      = PetscPartitionerView_Gather;
1472dae52e14SToby Isaac   part->ops->destroy   = PetscPartitionerDestroy_Gather;
1473dae52e14SToby Isaac   part->ops->partition = PetscPartitionerPartition_Gather;
1474dae52e14SToby Isaac   PetscFunctionReturn(0);
1475dae52e14SToby Isaac }
1476dae52e14SToby Isaac 
1477dae52e14SToby Isaac /*MC
1478dae52e14SToby Isaac   PETSCPARTITIONERGATHER = "gather" - A PetscPartitioner object
1479dae52e14SToby Isaac 
1480dae52e14SToby Isaac   Level: intermediate
1481dae52e14SToby Isaac 
1482dae52e14SToby Isaac .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1483dae52e14SToby Isaac M*/
1484dae52e14SToby Isaac 
1485dae52e14SToby Isaac PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Gather(PetscPartitioner part)
1486dae52e14SToby Isaac {
1487dae52e14SToby Isaac   PetscPartitioner_Gather *p;
1488dae52e14SToby Isaac   PetscErrorCode           ierr;
1489dae52e14SToby Isaac 
1490dae52e14SToby Isaac   PetscFunctionBegin;
1491dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1492dae52e14SToby Isaac   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1493dae52e14SToby Isaac   part->data = p;
1494dae52e14SToby Isaac 
1495dae52e14SToby Isaac   ierr = PetscPartitionerInitialize_Gather(part);CHKERRQ(ierr);
1496dae52e14SToby Isaac   PetscFunctionReturn(0);
1497dae52e14SToby Isaac }
1498dae52e14SToby Isaac 
1499dae52e14SToby Isaac 
1500d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Chaco(PetscPartitioner part)
150177623264SMatthew G. Knepley {
150277623264SMatthew G. Knepley   PetscPartitioner_Chaco *p = (PetscPartitioner_Chaco *) part->data;
150377623264SMatthew G. Knepley   PetscErrorCode          ierr;
150477623264SMatthew G. Knepley 
150577623264SMatthew G. Knepley   PetscFunctionBegin;
150677623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
150777623264SMatthew G. Knepley   PetscFunctionReturn(0);
150877623264SMatthew G. Knepley }
150977623264SMatthew G. Knepley 
1510d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco_Ascii(PetscPartitioner part, PetscViewer viewer)
151177623264SMatthew G. Knepley {
151277623264SMatthew G. Knepley   PetscFunctionBegin;
151377623264SMatthew G. Knepley   PetscFunctionReturn(0);
151477623264SMatthew G. Knepley }
151577623264SMatthew G. Knepley 
1516d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco(PetscPartitioner part, PetscViewer viewer)
151777623264SMatthew G. Knepley {
151877623264SMatthew G. Knepley   PetscBool      iascii;
151977623264SMatthew G. Knepley   PetscErrorCode ierr;
152077623264SMatthew G. Knepley 
152177623264SMatthew G. Knepley   PetscFunctionBegin;
152277623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
152377623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
152477623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
152577623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Chaco_Ascii(part, viewer);CHKERRQ(ierr);}
152677623264SMatthew G. Knepley   PetscFunctionReturn(0);
152777623264SMatthew G. Knepley }
152877623264SMatthew G. Knepley 
152970034214SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
153070034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
153170034214SMatthew G. Knepley #include <unistd.h>
153270034214SMatthew G. Knepley #endif
153311d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
153411d1e910SBarry Smith #include <chaco.h>
153511d1e910SBarry Smith #else
153611d1e910SBarry Smith /* Older versions of Chaco do not have an include file */
153770034214SMatthew G. Knepley PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
153870034214SMatthew G. Knepley                        float *ewgts, float *x, float *y, float *z, char *outassignname,
153970034214SMatthew G. Knepley                        char *outfilename, short *assignment, int architecture, int ndims_tot,
154070034214SMatthew G. Knepley                        int mesh_dims[3], double *goal, int global_method, int local_method,
154170034214SMatthew G. Knepley                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
154211d1e910SBarry Smith #endif
154370034214SMatthew G. Knepley extern int FREE_GRAPH;
154477623264SMatthew G. Knepley #endif
154570034214SMatthew G. Knepley 
1546d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Chaco(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
154770034214SMatthew G. Knepley {
154877623264SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
154970034214SMatthew G. Knepley   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
155070034214SMatthew G. Knepley   MPI_Comm       comm;
155170034214SMatthew G. Knepley   int            nvtxs          = numVertices; /* number of vertices in full graph */
155270034214SMatthew G. Knepley   int           *vwgts          = NULL;   /* weights for all vertices */
155370034214SMatthew G. Knepley   float         *ewgts          = NULL;   /* weights for all edges */
155470034214SMatthew G. Knepley   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
155570034214SMatthew G. Knepley   char          *outassignname  = NULL;   /*  name of assignment output file */
155670034214SMatthew G. Knepley   char          *outfilename    = NULL;   /* output file name */
155770034214SMatthew G. Knepley   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
155870034214SMatthew G. Knepley   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
155970034214SMatthew G. Knepley   int            mesh_dims[3];            /* dimensions of mesh of processors */
156070034214SMatthew G. Knepley   double        *goal          = NULL;    /* desired set sizes for each set */
156170034214SMatthew G. Knepley   int            global_method = 1;       /* global partitioning algorithm */
156270034214SMatthew G. Knepley   int            local_method  = 1;       /* local partitioning algorithm */
156370034214SMatthew G. Knepley   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
156470034214SMatthew G. Knepley   int            vmax          = 200;     /* how many vertices to coarsen down to? */
156570034214SMatthew G. Knepley   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
156670034214SMatthew G. Knepley   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
156770034214SMatthew G. Knepley   long           seed          = 123636512; /* for random graph mutations */
156811d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
156911d1e910SBarry Smith   int           *assignment;              /* Output partition */
157011d1e910SBarry Smith #else
157170034214SMatthew G. Knepley   short int     *assignment;              /* Output partition */
157211d1e910SBarry Smith #endif
157370034214SMatthew G. Knepley   int            fd_stdout, fd_pipe[2];
157470034214SMatthew G. Knepley   PetscInt      *points;
157570034214SMatthew G. Knepley   int            i, v, p;
157670034214SMatthew G. Knepley   PetscErrorCode ierr;
157770034214SMatthew G. Knepley 
157870034214SMatthew G. Knepley   PetscFunctionBegin;
157970034214SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
158007ed3857SLisandro Dalcin #if defined (PETSC_USE_DEBUG)
158107ed3857SLisandro Dalcin   {
158207ed3857SLisandro Dalcin     int ival,isum;
158307ed3857SLisandro Dalcin     PetscBool distributed;
158407ed3857SLisandro Dalcin 
158507ed3857SLisandro Dalcin     ival = (numVertices > 0);
158607ed3857SLisandro Dalcin     ierr = MPI_Allreduce(&ival, &isum, 1, MPI_INT, MPI_SUM, comm);CHKERRQ(ierr);
158707ed3857SLisandro Dalcin     distributed = (isum > 1) ? PETSC_TRUE : PETSC_FALSE;
158807ed3857SLisandro Dalcin     if (distributed) SETERRQ(comm, PETSC_ERR_SUP, "Chaco cannot partition a distributed graph");
158907ed3857SLisandro Dalcin   }
159007ed3857SLisandro Dalcin #endif
159170034214SMatthew G. Knepley   if (!numVertices) {
159277623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
159377623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
159470034214SMatthew G. Knepley     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
159570034214SMatthew G. Knepley     PetscFunctionReturn(0);
159670034214SMatthew G. Knepley   }
159770034214SMatthew G. Knepley   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
159870034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
159970034214SMatthew G. Knepley 
160070034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
160170034214SMatthew G. Knepley     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
160270034214SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
160370034214SMatthew G. Knepley   }
160477623264SMatthew G. Knepley   mesh_dims[0] = nparts;
160570034214SMatthew G. Knepley   mesh_dims[1] = 1;
160670034214SMatthew G. Knepley   mesh_dims[2] = 1;
160770034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &assignment);CHKERRQ(ierr);
160870034214SMatthew G. Knepley   /* Chaco outputs to stdout. We redirect this to a buffer. */
160970034214SMatthew G. Knepley   /* TODO: check error codes for UNIX calls */
161070034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
161170034214SMatthew G. Knepley   {
161270034214SMatthew G. Knepley     int piperet;
161370034214SMatthew G. Knepley     piperet = pipe(fd_pipe);
161470034214SMatthew G. Knepley     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
161570034214SMatthew G. Knepley     fd_stdout = dup(1);
161670034214SMatthew G. Knepley     close(1);
161770034214SMatthew G. Knepley     dup2(fd_pipe[1], 1);
161870034214SMatthew G. Knepley   }
161970034214SMatthew G. Knepley #endif
162070034214SMatthew G. Knepley   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
162170034214SMatthew G. Knepley                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
162270034214SMatthew G. Knepley                    vmax, ndims, eigtol, seed);
162370034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
162470034214SMatthew G. Knepley   {
162570034214SMatthew G. Knepley     char msgLog[10000];
162670034214SMatthew G. Knepley     int  count;
162770034214SMatthew G. Knepley 
162870034214SMatthew G. Knepley     fflush(stdout);
162970034214SMatthew G. Knepley     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
163070034214SMatthew G. Knepley     if (count < 0) count = 0;
163170034214SMatthew G. Knepley     msgLog[count] = 0;
163270034214SMatthew G. Knepley     close(1);
163370034214SMatthew G. Knepley     dup2(fd_stdout, 1);
163470034214SMatthew G. Knepley     close(fd_stdout);
163570034214SMatthew G. Knepley     close(fd_pipe[0]);
163670034214SMatthew G. Knepley     close(fd_pipe[1]);
163770034214SMatthew G. Knepley     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
163870034214SMatthew G. Knepley   }
163907ed3857SLisandro Dalcin #else
164007ed3857SLisandro Dalcin   if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", "error in stdout");
164170034214SMatthew G. Knepley #endif
164270034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
164377623264SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
164470034214SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {
164577623264SMatthew G. Knepley     ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);
164670034214SMatthew G. Knepley   }
164777623264SMatthew G. Knepley   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
164870034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
164977623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
165070034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
165170034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
165270034214SMatthew G. Knepley     }
165370034214SMatthew G. Knepley   }
165470034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
165570034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
165670034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
165770034214SMatthew G. Knepley     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
165870034214SMatthew G. Knepley   }
165970034214SMatthew G. Knepley   ierr = PetscFree(assignment);CHKERRQ(ierr);
166070034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
166170034214SMatthew G. Knepley   PetscFunctionReturn(0);
166277623264SMatthew G. Knepley #else
166377623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
166470034214SMatthew G. Knepley #endif
166577623264SMatthew G. Knepley }
166677623264SMatthew G. Knepley 
1667d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Chaco(PetscPartitioner part)
166877623264SMatthew G. Knepley {
166977623264SMatthew G. Knepley   PetscFunctionBegin;
1670074d466cSStefano Zampini   part->noGraph        = PETSC_FALSE;
167177623264SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Chaco;
167277623264SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Chaco;
167377623264SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Chaco;
167477623264SMatthew G. Knepley   PetscFunctionReturn(0);
167577623264SMatthew G. Knepley }
167677623264SMatthew G. Knepley 
167777623264SMatthew G. Knepley /*MC
167877623264SMatthew G. Knepley   PETSCPARTITIONERCHACO = "chaco" - A PetscPartitioner object using the Chaco library
167977623264SMatthew G. Knepley 
168077623264SMatthew G. Knepley   Level: intermediate
168177623264SMatthew G. Knepley 
168277623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
168377623264SMatthew G. Knepley M*/
168477623264SMatthew G. Knepley 
168577623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Chaco(PetscPartitioner part)
168677623264SMatthew G. Knepley {
168777623264SMatthew G. Knepley   PetscPartitioner_Chaco *p;
168877623264SMatthew G. Knepley   PetscErrorCode          ierr;
168977623264SMatthew G. Knepley 
169077623264SMatthew G. Knepley   PetscFunctionBegin;
169177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
169277623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
169377623264SMatthew G. Knepley   part->data = p;
169477623264SMatthew G. Knepley 
169577623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Chaco(part);CHKERRQ(ierr);
169677623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ChacoPartitionerCitation, &ChacoPartitionercite);CHKERRQ(ierr);
169777623264SMatthew G. Knepley   PetscFunctionReturn(0);
169877623264SMatthew G. Knepley }
169977623264SMatthew G. Knepley 
17005b440754SMatthew G. Knepley static const char *ptypes[] = {"kway", "rb"};
17015b440754SMatthew G. Knepley 
1702d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_ParMetis(PetscPartitioner part)
170377623264SMatthew G. Knepley {
170477623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
170577623264SMatthew G. Knepley   PetscErrorCode             ierr;
170677623264SMatthew G. Knepley 
170777623264SMatthew G. Knepley   PetscFunctionBegin;
170877623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
170977623264SMatthew G. Knepley   PetscFunctionReturn(0);
171077623264SMatthew G. Knepley }
171177623264SMatthew G. Knepley 
1712d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis_Ascii(PetscPartitioner part, PetscViewer viewer)
171377623264SMatthew G. Knepley {
17142abdaa70SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
171577623264SMatthew G. Knepley   PetscErrorCode             ierr;
171677623264SMatthew G. Knepley 
171777623264SMatthew G. Knepley   PetscFunctionBegin;
17182abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
17192abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "ParMetis type: %s\n", ptypes[p->ptype]);CHKERRQ(ierr);
17202abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "load imbalance ratio %g\n", (double) p->imbalanceRatio);CHKERRQ(ierr);
17212abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "debug flag %D\n", p->debugFlag);CHKERRQ(ierr);
17222abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
172377623264SMatthew G. Knepley   PetscFunctionReturn(0);
172477623264SMatthew G. Knepley }
172577623264SMatthew G. Knepley 
1726d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis(PetscPartitioner part, PetscViewer viewer)
172777623264SMatthew G. Knepley {
172877623264SMatthew G. Knepley   PetscBool      iascii;
172977623264SMatthew G. Knepley   PetscErrorCode ierr;
173077623264SMatthew G. Knepley 
173177623264SMatthew G. Knepley   PetscFunctionBegin;
173277623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
173377623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
173477623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
173577623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_ParMetis_Ascii(part, viewer);CHKERRQ(ierr);}
173677623264SMatthew G. Knepley   PetscFunctionReturn(0);
173777623264SMatthew G. Knepley }
173870034214SMatthew G. Knepley 
173944d8be81SLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_ParMetis(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
174044d8be81SLisandro Dalcin {
174144d8be81SLisandro Dalcin   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
174242678178SLisandro Dalcin   PetscInt                  p_randomSeed = -1; /* TODO: Add this to PetscPartitioner_ParMetis */
174344d8be81SLisandro Dalcin   PetscErrorCode            ierr;
174444d8be81SLisandro Dalcin 
174544d8be81SLisandro Dalcin   PetscFunctionBegin;
174644d8be81SLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner ParMetis Options");CHKERRQ(ierr);
174744d8be81SLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_parmetis_type", "Partitioning method", "", ptypes, 2, ptypes[p->ptype], &p->ptype, NULL);CHKERRQ(ierr);
17485b440754SMatthew G. Knepley   ierr = PetscOptionsReal("-petscpartitioner_parmetis_imbalance_ratio", "Load imbalance ratio limit", "", p->imbalanceRatio, &p->imbalanceRatio, NULL);CHKERRQ(ierr);
17495b440754SMatthew G. Knepley   ierr = PetscOptionsInt("-petscpartitioner_parmetis_debug", "Debugging flag", "", p->debugFlag, &p->debugFlag, NULL);CHKERRQ(ierr);
175042678178SLisandro Dalcin   ierr = PetscOptionsInt("-petscpartitioner_parmetis_seed", "Random seed", "", p_randomSeed, &p_randomSeed, NULL);CHKERRQ(ierr);
175144d8be81SLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
175244d8be81SLisandro Dalcin   PetscFunctionReturn(0);
175344d8be81SLisandro Dalcin }
175444d8be81SLisandro Dalcin 
175570034214SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
175670034214SMatthew G. Knepley #include <parmetis.h>
175777623264SMatthew G. Knepley #endif
175870034214SMatthew G. Knepley 
1759d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_ParMetis(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
176070034214SMatthew G. Knepley {
176177623264SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
17625b440754SMatthew G. Knepley   PetscPartitioner_ParMetis *pm = (PetscPartitioner_ParMetis *) part->data;
176370034214SMatthew G. Knepley   MPI_Comm       comm;
1764deea36a5SMatthew G. Knepley   PetscSection   section;
176570034214SMatthew G. Knepley   PetscInt       nvtxs       = numVertices; /* The number of vertices in full graph */
176670034214SMatthew G. Knepley   PetscInt      *vtxdist;                   /* Distribution of vertices across processes */
176770034214SMatthew G. Knepley   PetscInt      *xadj        = start;       /* Start of edge list for each vertex */
176870034214SMatthew G. Knepley   PetscInt      *adjncy      = adjacency;   /* Edge lists for all vertices */
176970034214SMatthew G. Knepley   PetscInt      *vwgt        = NULL;        /* Vertex weights */
177070034214SMatthew G. Knepley   PetscInt      *adjwgt      = NULL;        /* Edge weights */
177170034214SMatthew G. Knepley   PetscInt       wgtflag     = 0;           /* Indicates which weights are present */
177270034214SMatthew G. Knepley   PetscInt       numflag     = 0;           /* Indicates initial offset (0 or 1) */
177370034214SMatthew G. Knepley   PetscInt       ncon        = 1;           /* The number of weights per vertex */
17745b440754SMatthew G. Knepley   PetscInt       metis_ptype = pm->ptype;   /* kway or recursive bisection */
1775fb83b9f2SMichael Gegg   real_t        *tpwgts;                    /* The fraction of vertex weights assigned to each partition */
1776fb83b9f2SMichael Gegg   real_t        *ubvec;                     /* The balance intolerance for vertex weights */
1777b3ce585bSLisandro Dalcin   PetscInt       options[64];               /* Options */
177870034214SMatthew G. Knepley   /* Outputs */
1779b3ce585bSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
1780b3ce585bSLisandro Dalcin   PetscMPIInt    size, rank, p;
178142678178SLisandro Dalcin   PetscInt       pm_randomSeed = -1;
178270034214SMatthew G. Knepley   PetscErrorCode ierr;
178370034214SMatthew G. Knepley 
178470034214SMatthew G. Knepley   PetscFunctionBegin;
178542678178SLisandro Dalcin   ierr = PetscOptionsGetInt(((PetscObject)part)->options,((PetscObject)part)->prefix,"-petscpartitioner_parmetis_seed", &pm_randomSeed, NULL);CHKERRQ(ierr);
178677623264SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) part, &comm);CHKERRQ(ierr);
1787b3ce585bSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
178870034214SMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
178970034214SMatthew G. Knepley   /* Calculate vertex distribution */
1790b3ce585bSLisandro Dalcin   ierr = PetscMalloc5(size+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment,nvtxs,&vwgt);CHKERRQ(ierr);
179170034214SMatthew G. Knepley   vtxdist[0] = 0;
179270034214SMatthew G. Knepley   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
1793b3ce585bSLisandro Dalcin   for (p = 2; p <= size; ++p) {
179470034214SMatthew G. Knepley     vtxdist[p] += vtxdist[p-1];
179570034214SMatthew G. Knepley   }
179644d8be81SLisandro Dalcin   /* Calculate partition weights */
179770034214SMatthew G. Knepley   for (p = 0; p < nparts; ++p) {
179870034214SMatthew G. Knepley     tpwgts[p] = 1.0/nparts;
179970034214SMatthew G. Knepley   }
18005b440754SMatthew G. Knepley   ubvec[0] = pm->imbalanceRatio;
1801deea36a5SMatthew G. Knepley   /* Weight cells by dofs on cell by default */
1802e87a4003SBarry Smith   ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
1803deea36a5SMatthew G. Knepley   if (section) {
1804deea36a5SMatthew G. Knepley     PetscInt cStart, cEnd, dof;
180570034214SMatthew G. Knepley 
1806deea36a5SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1807deea36a5SMatthew G. Knepley     for (v = cStart; v < cEnd; ++v) {
1808deea36a5SMatthew G. Knepley       ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr);
1809925b1076SLisandro Dalcin       /* WARNING: Assumes that meshes with overlap have the overlapped cells at the end of the stratum. */
1810925b1076SLisandro Dalcin       /* To do this properly, we should use the cell numbering created in DMPlexCreatePartitionerGraph. */
1811925b1076SLisandro Dalcin       if (v-cStart < numVertices) vwgt[v-cStart] = PetscMax(dof, 1);
1812deea36a5SMatthew G. Knepley     }
1813deea36a5SMatthew G. Knepley   } else {
1814deea36a5SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) vwgt[v] = 1;
1815cd0de0f2SShri   }
181644d8be81SLisandro Dalcin   wgtflag |= 2; /* have weights on graph vertices */
1817cd0de0f2SShri 
181870034214SMatthew G. Knepley   if (nparts == 1) {
18199fc93327SToby Isaac     ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));CHKERRQ(ierr);
182070034214SMatthew G. Knepley   } else {
1821b3ce585bSLisandro Dalcin     for (p = 0; !vtxdist[p+1] && p < size; ++p);
1822b3ce585bSLisandro Dalcin     if (vtxdist[p+1] == vtxdist[size]) {
1823b3ce585bSLisandro Dalcin       if (rank == p) {
182444d8be81SLisandro Dalcin         ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
182542678178SLisandro Dalcin         options[METIS_OPTION_DBGLVL] = pm->debugFlag;
182642678178SLisandro Dalcin         options[METIS_OPTION_SEED]   = pm_randomSeed;
182744d8be81SLisandro Dalcin         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
182844d8be81SLisandro Dalcin         if (metis_ptype == 1) {
182944d8be81SLisandro Dalcin           PetscStackPush("METIS_PartGraphRecursive");
183072379da4SMatthew G. Knepley           ierr = METIS_PartGraphRecursive(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
183144d8be81SLisandro Dalcin           PetscStackPop;
183244d8be81SLisandro Dalcin           if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphRecursive()");
183344d8be81SLisandro Dalcin         } else {
183444d8be81SLisandro Dalcin           /*
183544d8be81SLisandro Dalcin            It would be nice to activate the two options below, but they would need some actual testing.
183644d8be81SLisandro Dalcin            - Turning on these options may exercise path of the METIS code that have bugs and may break production runs.
183744d8be81SLisandro Dalcin            - If CONTIG is set to 1, METIS will exit with error if the graph is disconnected, despite the manual saying the option is ignored in such case.
183844d8be81SLisandro Dalcin           */
183944d8be81SLisandro Dalcin           /* options[METIS_OPTION_CONTIG]  = 1; */ /* try to produce partitions that are contiguous */
184044d8be81SLisandro Dalcin           /* options[METIS_OPTION_MINCONN] = 1; */ /* minimize the maximum degree of the subdomain graph */
184170034214SMatthew G. Knepley           PetscStackPush("METIS_PartGraphKway");
184272379da4SMatthew G. Knepley           ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
184370034214SMatthew G. Knepley           PetscStackPop;
184470034214SMatthew G. Knepley           if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
184570034214SMatthew G. Knepley         }
184644d8be81SLisandro Dalcin       }
184770034214SMatthew G. Knepley     } else {
184842678178SLisandro Dalcin       options[0] = 1; /*use options */
18495b440754SMatthew G. Knepley       options[1] = pm->debugFlag;
185042678178SLisandro Dalcin       options[2] = (pm_randomSeed == -1) ? 15 : pm_randomSeed; /* default is GLOBAL_SEED=15 from `libparmetis/defs.h` */
185170034214SMatthew G. Knepley       PetscStackPush("ParMETIS_V3_PartKway");
185272379da4SMatthew G. Knepley       ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment, &comm);
185370034214SMatthew G. Knepley       PetscStackPop;
1854c717d290SMatthew G. Knepley       if (ierr != METIS_OK) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error %d in ParMETIS_V3_PartKway()", ierr);
185570034214SMatthew G. Knepley     }
185670034214SMatthew G. Knepley   }
185770034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
185877623264SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
185977623264SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
186077623264SMatthew G. Knepley   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
186170034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
186277623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
186370034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
186470034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
186570034214SMatthew G. Knepley     }
186670034214SMatthew G. Knepley   }
186770034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
186870034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
1869cd0de0f2SShri   ierr = PetscFree5(vtxdist,tpwgts,ubvec,assignment,vwgt);CHKERRQ(ierr);
18709b80ac48SMatthew G. Knepley   PetscFunctionReturn(0);
187170034214SMatthew G. Knepley #else
187277623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
187370034214SMatthew G. Knepley #endif
187470034214SMatthew G. Knepley }
187570034214SMatthew G. Knepley 
1876d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_ParMetis(PetscPartitioner part)
187777623264SMatthew G. Knepley {
187877623264SMatthew G. Knepley   PetscFunctionBegin;
1879074d466cSStefano Zampini   part->noGraph             = PETSC_FALSE;
188077623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_ParMetis;
188144d8be81SLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_ParMetis;
188277623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_ParMetis;
188377623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_ParMetis;
188477623264SMatthew G. Knepley   PetscFunctionReturn(0);
188577623264SMatthew G. Knepley }
188677623264SMatthew G. Knepley 
188777623264SMatthew G. Knepley /*MC
188877623264SMatthew G. Knepley   PETSCPARTITIONERPARMETIS = "parmetis" - A PetscPartitioner object using the ParMetis library
188977623264SMatthew G. Knepley 
189077623264SMatthew G. Knepley   Level: intermediate
189177623264SMatthew G. Knepley 
189277623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
189377623264SMatthew G. Knepley M*/
189477623264SMatthew G. Knepley 
189577623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_ParMetis(PetscPartitioner part)
189677623264SMatthew G. Knepley {
189777623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p;
189877623264SMatthew G. Knepley   PetscErrorCode          ierr;
189977623264SMatthew G. Knepley 
190077623264SMatthew G. Knepley   PetscFunctionBegin;
190177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
190277623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
190377623264SMatthew G. Knepley   part->data = p;
190477623264SMatthew G. Knepley 
19055b440754SMatthew G. Knepley   p->ptype          = 0;
19065b440754SMatthew G. Knepley   p->imbalanceRatio = 1.05;
19075b440754SMatthew G. Knepley   p->debugFlag      = 0;
19085b440754SMatthew G. Knepley 
190977623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_ParMetis(part);CHKERRQ(ierr);
191077623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ParMetisPartitionerCitation, &ParMetisPartitionercite);CHKERRQ(ierr);
191170034214SMatthew G. Knepley   PetscFunctionReturn(0);
191270034214SMatthew G. Knepley }
191370034214SMatthew G. Knepley 
1914137cd93aSLisandro Dalcin PetscBool PTScotchPartitionercite = PETSC_FALSE;
1915137cd93aSLisandro Dalcin const char PTScotchPartitionerCitation[] =
1916137cd93aSLisandro Dalcin   "@article{PTSCOTCH,\n"
1917137cd93aSLisandro Dalcin   "  author  = {C. Chevalier and F. Pellegrini},\n"
1918137cd93aSLisandro Dalcin   "  title   = {{PT-SCOTCH}: a tool for efficient parallel graph ordering},\n"
1919137cd93aSLisandro Dalcin   "  journal = {Parallel Computing},\n"
1920137cd93aSLisandro Dalcin   "  volume  = {34},\n"
1921137cd93aSLisandro Dalcin   "  number  = {6},\n"
1922137cd93aSLisandro Dalcin   "  pages   = {318--331},\n"
1923137cd93aSLisandro Dalcin   "  year    = {2008},\n"
1924137cd93aSLisandro Dalcin   "  doi     = {https://doi.org/10.1016/j.parco.2007.12.001}\n"
1925137cd93aSLisandro Dalcin   "}\n";
1926137cd93aSLisandro Dalcin 
1927137cd93aSLisandro Dalcin typedef struct {
1928137cd93aSLisandro Dalcin   PetscInt  strategy;
1929137cd93aSLisandro Dalcin   PetscReal imbalance;
1930137cd93aSLisandro Dalcin } PetscPartitioner_PTScotch;
1931137cd93aSLisandro Dalcin 
1932137cd93aSLisandro Dalcin static const char *const
1933137cd93aSLisandro Dalcin PTScotchStrategyList[] = {
1934137cd93aSLisandro Dalcin   "DEFAULT",
1935137cd93aSLisandro Dalcin   "QUALITY",
1936137cd93aSLisandro Dalcin   "SPEED",
1937137cd93aSLisandro Dalcin   "BALANCE",
1938137cd93aSLisandro Dalcin   "SAFETY",
1939137cd93aSLisandro Dalcin   "SCALABILITY",
1940137cd93aSLisandro Dalcin   "RECURSIVE",
1941137cd93aSLisandro Dalcin   "REMAP"
1942137cd93aSLisandro Dalcin };
1943137cd93aSLisandro Dalcin 
1944137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
1945137cd93aSLisandro Dalcin 
1946137cd93aSLisandro Dalcin EXTERN_C_BEGIN
1947137cd93aSLisandro Dalcin #include <ptscotch.h>
1948137cd93aSLisandro Dalcin EXTERN_C_END
1949137cd93aSLisandro Dalcin 
1950137cd93aSLisandro Dalcin #define CHKERRPTSCOTCH(ierr) do { if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error calling PT-Scotch library"); } while(0)
1951137cd93aSLisandro Dalcin 
1952137cd93aSLisandro Dalcin static int PTScotch_Strategy(PetscInt strategy)
1953137cd93aSLisandro Dalcin {
1954137cd93aSLisandro Dalcin   switch (strategy) {
1955137cd93aSLisandro Dalcin   case  0: return SCOTCH_STRATDEFAULT;
1956137cd93aSLisandro Dalcin   case  1: return SCOTCH_STRATQUALITY;
1957137cd93aSLisandro Dalcin   case  2: return SCOTCH_STRATSPEED;
1958137cd93aSLisandro Dalcin   case  3: return SCOTCH_STRATBALANCE;
1959137cd93aSLisandro Dalcin   case  4: return SCOTCH_STRATSAFETY;
1960137cd93aSLisandro Dalcin   case  5: return SCOTCH_STRATSCALABILITY;
1961137cd93aSLisandro Dalcin   case  6: return SCOTCH_STRATRECURSIVE;
1962137cd93aSLisandro Dalcin   case  7: return SCOTCH_STRATREMAP;
1963137cd93aSLisandro Dalcin   default: return SCOTCH_STRATDEFAULT;
1964137cd93aSLisandro Dalcin   }
1965137cd93aSLisandro Dalcin }
1966137cd93aSLisandro Dalcin 
1967137cd93aSLisandro Dalcin 
1968137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_Seq(SCOTCH_Num strategy, double imbalance, SCOTCH_Num n, SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
1969137cd93aSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num part[])
1970137cd93aSLisandro Dalcin {
1971137cd93aSLisandro Dalcin   SCOTCH_Graph   grafdat;
1972137cd93aSLisandro Dalcin   SCOTCH_Strat   stradat;
1973137cd93aSLisandro Dalcin   SCOTCH_Num     vertnbr = n;
1974137cd93aSLisandro Dalcin   SCOTCH_Num     edgenbr = xadj[n];
1975137cd93aSLisandro Dalcin   SCOTCH_Num*    velotab = vtxwgt;
1976137cd93aSLisandro Dalcin   SCOTCH_Num*    edlotab = adjwgt;
1977137cd93aSLisandro Dalcin   SCOTCH_Num     flagval = strategy;
1978137cd93aSLisandro Dalcin   double         kbalval = imbalance;
1979137cd93aSLisandro Dalcin   PetscErrorCode ierr;
1980137cd93aSLisandro Dalcin 
1981137cd93aSLisandro Dalcin   PetscFunctionBegin;
1982d99a0000SVaclav Hapla   {
1983d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
1984d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
1985d99a0000SVaclav Hapla     if (!flg) velotab = NULL;
1986d99a0000SVaclav Hapla   }
1987137cd93aSLisandro Dalcin   ierr = SCOTCH_graphInit(&grafdat);CHKERRPTSCOTCH(ierr);
1988137cd93aSLisandro Dalcin   ierr = SCOTCH_graphBuild(&grafdat, 0, vertnbr, xadj, xadj + 1, velotab, NULL, edgenbr, adjncy, edlotab);CHKERRPTSCOTCH(ierr);
1989137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
1990137cd93aSLisandro Dalcin   ierr = SCOTCH_stratGraphMapBuild(&stradat, flagval, nparts, kbalval);CHKERRPTSCOTCH(ierr);
1991137cd93aSLisandro Dalcin #if defined(PETSC_USE_DEBUG)
1992137cd93aSLisandro Dalcin   ierr = SCOTCH_graphCheck(&grafdat);CHKERRPTSCOTCH(ierr);
1993137cd93aSLisandro Dalcin #endif
1994137cd93aSLisandro Dalcin   ierr = SCOTCH_graphPart(&grafdat, nparts, &stradat, part);CHKERRPTSCOTCH(ierr);
1995137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
1996137cd93aSLisandro Dalcin   SCOTCH_graphExit(&grafdat);
1997137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1998137cd93aSLisandro Dalcin }
1999137cd93aSLisandro Dalcin 
2000137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_MPI(SCOTCH_Num strategy, double imbalance, SCOTCH_Num vtxdist[], SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
2001137cd93aSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num part[], MPI_Comm comm)
2002137cd93aSLisandro Dalcin {
2003137cd93aSLisandro Dalcin   PetscMPIInt     procglbnbr;
2004137cd93aSLisandro Dalcin   PetscMPIInt     proclocnum;
2005137cd93aSLisandro Dalcin   SCOTCH_Arch     archdat;
2006137cd93aSLisandro Dalcin   SCOTCH_Dgraph   grafdat;
2007137cd93aSLisandro Dalcin   SCOTCH_Dmapping mappdat;
2008137cd93aSLisandro Dalcin   SCOTCH_Strat    stradat;
2009137cd93aSLisandro Dalcin   SCOTCH_Num      vertlocnbr;
2010137cd93aSLisandro Dalcin   SCOTCH_Num      edgelocnbr;
2011137cd93aSLisandro Dalcin   SCOTCH_Num*     veloloctab = vtxwgt;
2012137cd93aSLisandro Dalcin   SCOTCH_Num*     edloloctab = adjwgt;
2013137cd93aSLisandro Dalcin   SCOTCH_Num      flagval = strategy;
2014137cd93aSLisandro Dalcin   double          kbalval = imbalance;
2015137cd93aSLisandro Dalcin   PetscErrorCode  ierr;
2016137cd93aSLisandro Dalcin 
2017137cd93aSLisandro Dalcin   PetscFunctionBegin;
2018d99a0000SVaclav Hapla   {
2019d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
2020d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
2021d99a0000SVaclav Hapla     if (!flg) veloloctab = NULL;
2022d99a0000SVaclav Hapla   }
2023137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &procglbnbr);CHKERRQ(ierr);
2024137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &proclocnum);CHKERRQ(ierr);
2025137cd93aSLisandro Dalcin   vertlocnbr = vtxdist[proclocnum + 1] - vtxdist[proclocnum];
2026137cd93aSLisandro Dalcin   edgelocnbr = xadj[vertlocnbr];
2027137cd93aSLisandro Dalcin 
2028137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphInit(&grafdat, comm);CHKERRPTSCOTCH(ierr);
2029137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphBuild(&grafdat, 0, vertlocnbr, vertlocnbr, xadj, xadj + 1, veloloctab, NULL, edgelocnbr, edgelocnbr, adjncy, NULL, edloloctab);CHKERRPTSCOTCH(ierr);
2030137cd93aSLisandro Dalcin #if defined(PETSC_USE_DEBUG)
2031137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphCheck(&grafdat);CHKERRPTSCOTCH(ierr);
2032137cd93aSLisandro Dalcin #endif
2033137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
2034137cd93aSLisandro Dalcin   ierr = SCOTCH_stratDgraphMapBuild(&stradat, flagval, procglbnbr, nparts, kbalval);CHKERRQ(ierr);
2035137cd93aSLisandro Dalcin   ierr = SCOTCH_archInit(&archdat);CHKERRPTSCOTCH(ierr);
2036137cd93aSLisandro Dalcin   ierr = SCOTCH_archCmplt(&archdat, nparts);CHKERRPTSCOTCH(ierr);
2037137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapInit(&grafdat, &mappdat, &archdat, part);CHKERRPTSCOTCH(ierr);
2038cb87ef4cSFlorian Wechsung 
2039137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapCompute(&grafdat, &mappdat, &stradat);CHKERRPTSCOTCH(ierr);
2040137cd93aSLisandro Dalcin   SCOTCH_dgraphMapExit(&grafdat, &mappdat);
2041137cd93aSLisandro Dalcin   SCOTCH_archExit(&archdat);
2042137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
2043137cd93aSLisandro Dalcin   SCOTCH_dgraphExit(&grafdat);
2044137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2045137cd93aSLisandro Dalcin }
2046137cd93aSLisandro Dalcin 
2047137cd93aSLisandro Dalcin #endif /* PETSC_HAVE_PTSCOTCH */
2048137cd93aSLisandro Dalcin 
2049137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerDestroy_PTScotch(PetscPartitioner part)
2050137cd93aSLisandro Dalcin {
2051137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2052137cd93aSLisandro Dalcin   PetscErrorCode             ierr;
2053137cd93aSLisandro Dalcin 
2054137cd93aSLisandro Dalcin   PetscFunctionBegin;
2055137cd93aSLisandro Dalcin   ierr = PetscFree(p);CHKERRQ(ierr);
2056137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2057137cd93aSLisandro Dalcin }
2058137cd93aSLisandro Dalcin 
2059137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch_Ascii(PetscPartitioner part, PetscViewer viewer)
2060137cd93aSLisandro Dalcin {
2061137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2062137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
2063137cd93aSLisandro Dalcin 
2064137cd93aSLisandro Dalcin   PetscFunctionBegin;
2065137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
2066137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer, "using partitioning strategy %s\n",PTScotchStrategyList[p->strategy]);CHKERRQ(ierr);
2067137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer, "using load imbalance ratio %g\n",(double)p->imbalance);CHKERRQ(ierr);
2068137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
2069137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2070137cd93aSLisandro Dalcin }
2071137cd93aSLisandro Dalcin 
2072137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch(PetscPartitioner part, PetscViewer viewer)
2073137cd93aSLisandro Dalcin {
2074137cd93aSLisandro Dalcin   PetscBool      iascii;
2075137cd93aSLisandro Dalcin   PetscErrorCode ierr;
2076137cd93aSLisandro Dalcin 
2077137cd93aSLisandro Dalcin   PetscFunctionBegin;
2078137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
2079137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2080137cd93aSLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
2081137cd93aSLisandro Dalcin   if (iascii) {ierr = PetscPartitionerView_PTScotch_Ascii(part, viewer);CHKERRQ(ierr);}
2082137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2083137cd93aSLisandro Dalcin }
2084137cd93aSLisandro Dalcin 
2085137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_PTScotch(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
2086137cd93aSLisandro Dalcin {
2087137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2088137cd93aSLisandro Dalcin   const char *const         *slist = PTScotchStrategyList;
2089137cd93aSLisandro Dalcin   PetscInt                  nlist = (PetscInt)(sizeof(PTScotchStrategyList)/sizeof(PTScotchStrategyList[0]));
2090137cd93aSLisandro Dalcin   PetscBool                 flag;
2091137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
2092137cd93aSLisandro Dalcin 
2093137cd93aSLisandro Dalcin   PetscFunctionBegin;
2094137cd93aSLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner PTScotch Options");CHKERRQ(ierr);
2095137cd93aSLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_ptscotch_strategy","Partitioning strategy","",slist,nlist,slist[p->strategy],&p->strategy,&flag);CHKERRQ(ierr);
2096137cd93aSLisandro Dalcin   ierr = PetscOptionsReal("-petscpartitioner_ptscotch_imbalance","Load imbalance ratio","",p->imbalance,&p->imbalance,&flag);CHKERRQ(ierr);
2097137cd93aSLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
2098137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2099137cd93aSLisandro Dalcin }
2100137cd93aSLisandro Dalcin 
2101137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerPartition_PTScotch(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
2102137cd93aSLisandro Dalcin {
2103137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
2104137cd93aSLisandro Dalcin   MPI_Comm       comm       = PetscObjectComm((PetscObject)part);
2105137cd93aSLisandro Dalcin   PetscInt       nvtxs      = numVertices; /* The number of vertices in full graph */
2106137cd93aSLisandro Dalcin   PetscInt      *vtxdist;                  /* Distribution of vertices across processes */
2107137cd93aSLisandro Dalcin   PetscInt      *xadj       = start;       /* Start of edge list for each vertex */
2108137cd93aSLisandro Dalcin   PetscInt      *adjncy     = adjacency;   /* Edge lists for all vertices */
2109137cd93aSLisandro Dalcin   PetscInt      *vwgt       = NULL;        /* Vertex weights */
2110137cd93aSLisandro Dalcin   PetscInt      *adjwgt     = NULL;        /* Edge weights */
2111137cd93aSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
2112137cd93aSLisandro Dalcin   PetscMPIInt    size, rank, p;
2113137cd93aSLisandro Dalcin   PetscErrorCode ierr;
2114137cd93aSLisandro Dalcin 
2115137cd93aSLisandro Dalcin   PetscFunctionBegin;
2116137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
2117137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
211899b53901SStefano Zampini   ierr = PetscMalloc2(size+1,&vtxdist,PetscMax(nvtxs,1),&assignment);CHKERRQ(ierr);
2119137cd93aSLisandro Dalcin 
2120137cd93aSLisandro Dalcin   /* Calculate vertex distribution */
2121137cd93aSLisandro Dalcin   vtxdist[0] = 0;
2122137cd93aSLisandro Dalcin   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
2123137cd93aSLisandro Dalcin   for (p = 2; p <= size; ++p) {
2124137cd93aSLisandro Dalcin     vtxdist[p] += vtxdist[p-1];
2125137cd93aSLisandro Dalcin   }
2126137cd93aSLisandro Dalcin 
2127137cd93aSLisandro Dalcin   if (nparts == 1) {
2128137cd93aSLisandro Dalcin     ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));CHKERRQ(ierr);
2129137cd93aSLisandro Dalcin   } else {
2130137cd93aSLisandro Dalcin     PetscSection section;
2131137cd93aSLisandro Dalcin     /* Weight cells by dofs on cell by default */
2132137cd93aSLisandro Dalcin     ierr = PetscMalloc1(PetscMax(nvtxs,1),&vwgt);CHKERRQ(ierr);
2133e87a4003SBarry Smith     ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
2134137cd93aSLisandro Dalcin     if (section) {
2135d5528e35SFlorian Wechsung       PetscInt vStart, eEnd, dof;
2136d5528e35SFlorian Wechsung       ierr = DMPlexGetHeightStratum(dm, 0, &vStart, &eEnd);CHKERRQ(ierr);
2137d5528e35SFlorian Wechsung       for (v = vStart; v < eEnd; ++v) {
2138137cd93aSLisandro Dalcin         ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr);
2139137cd93aSLisandro Dalcin         /* WARNING: Assumes that meshes with overlap have the overlapped cells at the end of the stratum. */
2140137cd93aSLisandro Dalcin         /* To do this properly, we should use the cell numbering created in DMPlexCreatePartitionerGraph. */
2141137cd93aSLisandro Dalcin         if (v-vStart < numVertices) vwgt[v-vStart] = PetscMax(dof, 1);
2142137cd93aSLisandro Dalcin       }
2143137cd93aSLisandro Dalcin     } else {
2144137cd93aSLisandro Dalcin       for (v = 0; v < nvtxs; ++v) vwgt[v] = 1;
2145137cd93aSLisandro Dalcin     }
2146137cd93aSLisandro Dalcin     {
2147137cd93aSLisandro Dalcin       PetscPartitioner_PTScotch *pts = (PetscPartitioner_PTScotch *) part->data;
2148137cd93aSLisandro Dalcin       int                       strat = PTScotch_Strategy(pts->strategy);
2149137cd93aSLisandro Dalcin       double                    imbal = (double)pts->imbalance;
2150137cd93aSLisandro Dalcin 
2151137cd93aSLisandro Dalcin       for (p = 0; !vtxdist[p+1] && p < size; ++p);
2152137cd93aSLisandro Dalcin       if (vtxdist[p+1] == vtxdist[size]) {
2153137cd93aSLisandro Dalcin         if (rank == p) {
2154137cd93aSLisandro Dalcin           ierr = PTScotch_PartGraph_Seq(strat, imbal, nvtxs, xadj, adjncy, vwgt, adjwgt, nparts, assignment);CHKERRQ(ierr);
2155137cd93aSLisandro Dalcin         }
2156137cd93aSLisandro Dalcin       } else {
2157137cd93aSLisandro Dalcin         ierr = PTScotch_PartGraph_MPI(strat, imbal, vtxdist, xadj, adjncy, vwgt, adjwgt, nparts, assignment, comm);CHKERRQ(ierr);
2158137cd93aSLisandro Dalcin       }
2159137cd93aSLisandro Dalcin     }
2160137cd93aSLisandro Dalcin     ierr = PetscFree(vwgt);CHKERRQ(ierr);
2161137cd93aSLisandro Dalcin   }
2162137cd93aSLisandro Dalcin 
2163137cd93aSLisandro Dalcin   /* Convert to PetscSection+IS */
2164137cd93aSLisandro Dalcin   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
2165137cd93aSLisandro Dalcin   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
2166137cd93aSLisandro Dalcin   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
2167137cd93aSLisandro Dalcin   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
2168137cd93aSLisandro Dalcin   for (p = 0, i = 0; p < nparts; ++p) {
2169137cd93aSLisandro Dalcin     for (v = 0; v < nvtxs; ++v) {
2170137cd93aSLisandro Dalcin       if (assignment[v] == p) points[i++] = v;
2171137cd93aSLisandro Dalcin     }
2172137cd93aSLisandro Dalcin   }
2173137cd93aSLisandro Dalcin   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2174137cd93aSLisandro Dalcin   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2175137cd93aSLisandro Dalcin 
2176137cd93aSLisandro Dalcin   ierr = PetscFree2(vtxdist,assignment);CHKERRQ(ierr);
2177137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2178137cd93aSLisandro Dalcin #else
2179137cd93aSLisandro Dalcin   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-ptscotch.");
2180137cd93aSLisandro Dalcin #endif
2181137cd93aSLisandro Dalcin }
2182137cd93aSLisandro Dalcin 
2183137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerInitialize_PTScotch(PetscPartitioner part)
2184137cd93aSLisandro Dalcin {
2185137cd93aSLisandro Dalcin   PetscFunctionBegin;
2186074d466cSStefano Zampini   part->noGraph             = PETSC_FALSE;
2187137cd93aSLisandro Dalcin   part->ops->view           = PetscPartitionerView_PTScotch;
2188137cd93aSLisandro Dalcin   part->ops->destroy        = PetscPartitionerDestroy_PTScotch;
2189137cd93aSLisandro Dalcin   part->ops->partition      = PetscPartitionerPartition_PTScotch;
2190137cd93aSLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_PTScotch;
2191137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2192137cd93aSLisandro Dalcin }
2193137cd93aSLisandro Dalcin 
2194137cd93aSLisandro Dalcin /*MC
2195137cd93aSLisandro Dalcin   PETSCPARTITIONERPTSCOTCH = "ptscotch" - A PetscPartitioner object using the PT-Scotch library
2196137cd93aSLisandro Dalcin 
2197137cd93aSLisandro Dalcin   Level: intermediate
2198137cd93aSLisandro Dalcin 
2199137cd93aSLisandro Dalcin .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
2200137cd93aSLisandro Dalcin M*/
2201137cd93aSLisandro Dalcin 
2202137cd93aSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_PTScotch(PetscPartitioner part)
2203137cd93aSLisandro Dalcin {
2204137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p;
2205137cd93aSLisandro Dalcin   PetscErrorCode          ierr;
2206137cd93aSLisandro Dalcin 
2207137cd93aSLisandro Dalcin   PetscFunctionBegin;
2208137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
2209137cd93aSLisandro Dalcin   ierr = PetscNewLog(part, &p);CHKERRQ(ierr);
2210137cd93aSLisandro Dalcin   part->data = p;
2211137cd93aSLisandro Dalcin 
2212137cd93aSLisandro Dalcin   p->strategy  = 0;
2213137cd93aSLisandro Dalcin   p->imbalance = 0.01;
2214137cd93aSLisandro Dalcin 
2215137cd93aSLisandro Dalcin   ierr = PetscPartitionerInitialize_PTScotch(part);CHKERRQ(ierr);
2216137cd93aSLisandro Dalcin   ierr = PetscCitationsRegister(PTScotchPartitionerCitation, &PTScotchPartitionercite);CHKERRQ(ierr);
2217137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2218137cd93aSLisandro Dalcin }
2219137cd93aSLisandro Dalcin 
2220137cd93aSLisandro Dalcin 
22215680f57bSMatthew G. Knepley /*@
22225680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
22235680f57bSMatthew G. Knepley 
22245680f57bSMatthew G. Knepley   Not collective
22255680f57bSMatthew G. Knepley 
22265680f57bSMatthew G. Knepley   Input Parameter:
22275680f57bSMatthew G. Knepley . dm - The DM
22285680f57bSMatthew G. Knepley 
22295680f57bSMatthew G. Knepley   Output Parameter:
22305680f57bSMatthew G. Knepley . part - The PetscPartitioner
22315680f57bSMatthew G. Knepley 
22325680f57bSMatthew G. Knepley   Level: developer
22335680f57bSMatthew G. Knepley 
223498599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
223598599a47SLawrence Mitchell 
223698599a47SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerCreate()
22375680f57bSMatthew G. Knepley @*/
22385680f57bSMatthew G. Knepley PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
22395680f57bSMatthew G. Knepley {
22405680f57bSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex *) dm->data;
22415680f57bSMatthew G. Knepley 
22425680f57bSMatthew G. Knepley   PetscFunctionBegin;
22435680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22445680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
22455680f57bSMatthew G. Knepley   *part = mesh->partitioner;
22465680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
22475680f57bSMatthew G. Knepley }
22485680f57bSMatthew G. Knepley 
224971bb2955SLawrence Mitchell /*@
225071bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
225171bb2955SLawrence Mitchell 
225271bb2955SLawrence Mitchell   logically collective on dm and part
225371bb2955SLawrence Mitchell 
225471bb2955SLawrence Mitchell   Input Parameters:
225571bb2955SLawrence Mitchell + dm - The DM
225671bb2955SLawrence Mitchell - part - The partitioner
225771bb2955SLawrence Mitchell 
225871bb2955SLawrence Mitchell   Level: developer
225971bb2955SLawrence Mitchell 
226071bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
226171bb2955SLawrence Mitchell 
226271bb2955SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate()
226371bb2955SLawrence Mitchell @*/
226471bb2955SLawrence Mitchell PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
226571bb2955SLawrence Mitchell {
226671bb2955SLawrence Mitchell   DM_Plex       *mesh = (DM_Plex *) dm->data;
226771bb2955SLawrence Mitchell   PetscErrorCode ierr;
226871bb2955SLawrence Mitchell 
226971bb2955SLawrence Mitchell   PetscFunctionBegin;
227071bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
227171bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
227271bb2955SLawrence Mitchell   ierr = PetscObjectReference((PetscObject)part);CHKERRQ(ierr);
227371bb2955SLawrence Mitchell   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
227471bb2955SLawrence Mitchell   mesh->partitioner = part;
227571bb2955SLawrence Mitchell   PetscFunctionReturn(0);
227671bb2955SLawrence Mitchell }
227771bb2955SLawrence Mitchell 
2278e8f14785SLisandro Dalcin static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
2279270bba0cSToby Isaac {
2280270bba0cSToby Isaac   PetscErrorCode ierr;
2281270bba0cSToby Isaac 
2282270bba0cSToby Isaac   PetscFunctionBegin;
22836a5a2ffdSToby Isaac   if (up) {
22846a5a2ffdSToby Isaac     PetscInt parent;
22856a5a2ffdSToby Isaac 
2286270bba0cSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
22876a5a2ffdSToby Isaac     if (parent != point) {
22886a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
22896a5a2ffdSToby Isaac 
2290270bba0cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
2291270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
2292270bba0cSToby Isaac         PetscInt cpoint = closure[2*i];
2293270bba0cSToby Isaac 
2294e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
22951b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
2296270bba0cSToby Isaac       }
2297270bba0cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
22986a5a2ffdSToby Isaac     }
22996a5a2ffdSToby Isaac   }
23006a5a2ffdSToby Isaac   if (down) {
23016a5a2ffdSToby Isaac     PetscInt numChildren;
23026a5a2ffdSToby Isaac     const PetscInt *children;
23036a5a2ffdSToby Isaac 
23046a5a2ffdSToby Isaac     ierr = DMPlexGetTreeChildren(dm,point,&numChildren,&children);CHKERRQ(ierr);
23056a5a2ffdSToby Isaac     if (numChildren) {
23066a5a2ffdSToby Isaac       PetscInt i;
23076a5a2ffdSToby Isaac 
23086a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
23096a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
23106a5a2ffdSToby Isaac 
2311e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
23121b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
23136a5a2ffdSToby Isaac       }
23146a5a2ffdSToby Isaac     }
23156a5a2ffdSToby Isaac   }
2316270bba0cSToby Isaac   PetscFunctionReturn(0);
2317270bba0cSToby Isaac }
2318270bba0cSToby Isaac 
2319825f8a23SLisandro Dalcin PETSC_INTERN PetscErrorCode DMPlexPartitionLabelClosure_Private(DM,DMLabel,PetscInt,PetscInt,const PetscInt[],IS*);
2320825f8a23SLisandro Dalcin 
2321825f8a23SLisandro Dalcin PetscErrorCode DMPlexPartitionLabelClosure_Private(DM dm, DMLabel label, PetscInt rank, PetscInt numPoints, const PetscInt points[], IS *closureIS)
2322825f8a23SLisandro Dalcin {
2323825f8a23SLisandro Dalcin   DM_Plex        *mesh = (DM_Plex *)dm->data;
2324825f8a23SLisandro Dalcin   PetscBool      hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
2325825f8a23SLisandro Dalcin   PetscInt       *closure = NULL, closureSize, nelems, *elems, off = 0, p, c;
2326825f8a23SLisandro Dalcin   PetscHSetI     ht;
2327825f8a23SLisandro Dalcin   PetscErrorCode ierr;
2328825f8a23SLisandro Dalcin 
2329825f8a23SLisandro Dalcin   PetscFunctionBegin;
2330825f8a23SLisandro Dalcin   ierr = PetscHSetICreate(&ht);CHKERRQ(ierr);
2331825f8a23SLisandro Dalcin   ierr = PetscHSetIResize(ht, numPoints*16);CHKERRQ(ierr);
2332825f8a23SLisandro Dalcin   for (p = 0; p < numPoints; ++p) {
2333825f8a23SLisandro Dalcin     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2334825f8a23SLisandro Dalcin     for (c = 0; c < closureSize*2; c += 2) {
2335825f8a23SLisandro Dalcin       ierr = PetscHSetIAdd(ht, closure[c]);CHKERRQ(ierr);
2336825f8a23SLisandro Dalcin       if (hasTree) {ierr = DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE);CHKERRQ(ierr);}
2337825f8a23SLisandro Dalcin     }
2338825f8a23SLisandro Dalcin   }
2339825f8a23SLisandro Dalcin   if (closure) {ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure);CHKERRQ(ierr);}
2340825f8a23SLisandro Dalcin   ierr = PetscHSetIGetSize(ht, &nelems);CHKERRQ(ierr);
2341825f8a23SLisandro Dalcin   ierr = PetscMalloc1(nelems, &elems);CHKERRQ(ierr);
2342825f8a23SLisandro Dalcin   ierr = PetscHSetIGetElems(ht, &off, elems);CHKERRQ(ierr);
2343825f8a23SLisandro Dalcin   ierr = PetscHSetIDestroy(&ht);CHKERRQ(ierr);
2344825f8a23SLisandro Dalcin   ierr = PetscSortInt(nelems, elems);CHKERRQ(ierr);
2345825f8a23SLisandro Dalcin   ierr = ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS);CHKERRQ(ierr);
2346825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
2347825f8a23SLisandro Dalcin }
2348825f8a23SLisandro Dalcin 
23495abbe4feSMichael Lange /*@
23505abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
23515abbe4feSMichael Lange 
23525abbe4feSMichael Lange   Input Parameters:
23535abbe4feSMichael Lange + dm     - The DM
23545abbe4feSMichael Lange - label  - DMLabel assinging ranks to remote roots
23555abbe4feSMichael Lange 
23565abbe4feSMichael Lange   Level: developer
23575abbe4feSMichael Lange 
23585abbe4feSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
23595abbe4feSMichael Lange @*/
23605abbe4feSMichael Lange PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
23619ffc88e4SToby Isaac {
2362825f8a23SLisandro Dalcin   IS              rankIS,   pointIS, closureIS;
23635abbe4feSMichael Lange   const PetscInt *ranks,   *points;
2364825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
23659ffc88e4SToby Isaac   PetscErrorCode  ierr;
23669ffc88e4SToby Isaac 
23679ffc88e4SToby Isaac   PetscFunctionBegin;
23685abbe4feSMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
23695abbe4feSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
23705abbe4feSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
23715abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
23725abbe4feSMichael Lange     const PetscInt rank = ranks[r];
23735abbe4feSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
23745abbe4feSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
23755abbe4feSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
2376825f8a23SLisandro Dalcin     ierr = DMPlexPartitionLabelClosure_Private(dm, label, rank, numPoints, points, &closureIS);CHKERRQ(ierr);
23775abbe4feSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
23785abbe4feSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2379825f8a23SLisandro Dalcin     ierr = DMLabelSetStratumIS(label, rank, closureIS);CHKERRQ(ierr);
2380825f8a23SLisandro Dalcin     ierr = ISDestroy(&closureIS);CHKERRQ(ierr);
23819ffc88e4SToby Isaac   }
23825abbe4feSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
23835abbe4feSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
23849ffc88e4SToby Isaac   PetscFunctionReturn(0);
23859ffc88e4SToby Isaac }
23869ffc88e4SToby Isaac 
238724d039d7SMichael Lange /*@
238824d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
238924d039d7SMichael Lange 
239024d039d7SMichael Lange   Input Parameters:
239124d039d7SMichael Lange + dm     - The DM
239224d039d7SMichael Lange - label  - DMLabel assinging ranks to remote roots
239324d039d7SMichael Lange 
239424d039d7SMichael Lange   Level: developer
239524d039d7SMichael Lange 
239624d039d7SMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
239724d039d7SMichael Lange @*/
239824d039d7SMichael Lange PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
239970034214SMatthew G. Knepley {
240024d039d7SMichael Lange   IS              rankIS,   pointIS;
240124d039d7SMichael Lange   const PetscInt *ranks,   *points;
240224d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
240324d039d7SMichael Lange   PetscInt       *adj = NULL;
240470034214SMatthew G. Knepley   PetscErrorCode  ierr;
240570034214SMatthew G. Knepley 
240670034214SMatthew G. Knepley   PetscFunctionBegin;
240724d039d7SMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
240824d039d7SMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
240924d039d7SMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
241024d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
241124d039d7SMichael Lange     const PetscInt rank = ranks[r];
241270034214SMatthew G. Knepley 
241324d039d7SMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
241424d039d7SMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
241524d039d7SMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
241670034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
241724d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
241824d039d7SMichael Lange       ierr = DMPlexGetAdjacency(dm, points[p], &adjSize, &adj);CHKERRQ(ierr);
241924d039d7SMichael Lange       for (a = 0; a < adjSize; ++a) {ierr = DMLabelSetValue(label, adj[a], rank);CHKERRQ(ierr);}
242070034214SMatthew G. Knepley     }
242124d039d7SMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
242224d039d7SMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
242370034214SMatthew G. Knepley   }
242424d039d7SMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
242524d039d7SMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
242624d039d7SMichael Lange   ierr = PetscFree(adj);CHKERRQ(ierr);
242724d039d7SMichael Lange   PetscFunctionReturn(0);
242870034214SMatthew G. Knepley }
242970034214SMatthew G. Knepley 
2430be200f8dSMichael Lange /*@
2431be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
2432be200f8dSMichael Lange 
2433be200f8dSMichael Lange   Input Parameters:
2434be200f8dSMichael Lange + dm     - The DM
2435be200f8dSMichael Lange - label  - DMLabel assinging ranks to remote roots
2436be200f8dSMichael Lange 
2437be200f8dSMichael Lange   Level: developer
2438be200f8dSMichael Lange 
2439be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
2440be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
2441be200f8dSMichael Lange 
2442be200f8dSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
2443be200f8dSMichael Lange @*/
2444be200f8dSMichael Lange PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
2445be200f8dSMichael Lange {
2446be200f8dSMichael Lange   MPI_Comm        comm;
2447be200f8dSMichael Lange   PetscMPIInt     rank;
2448be200f8dSMichael Lange   PetscSF         sfPoint;
24495d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
2450be200f8dSMichael Lange   IS              rankIS, pointIS;
2451be200f8dSMichael Lange   const PetscInt *ranks;
2452be200f8dSMichael Lange   PetscInt        numRanks, r;
2453be200f8dSMichael Lange   PetscErrorCode  ierr;
2454be200f8dSMichael Lange 
2455be200f8dSMichael Lange   PetscFunctionBegin;
2456be200f8dSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
2457be200f8dSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2458be200f8dSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
24595d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
24605d04f6ebSMichael Lange   ierr = DMLabelGather(label, sfPoint, &lblLeaves);CHKERRQ(ierr);
24615d04f6ebSMichael Lange   ierr = DMLabelGetValueIS(lblLeaves, &rankIS);CHKERRQ(ierr);
24625d04f6ebSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
24635d04f6ebSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
24645d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
24655d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
24665d04f6ebSMichael Lange     if (remoteRank == rank) continue;
24675d04f6ebSMichael Lange     ierr = DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS);CHKERRQ(ierr);
24685d04f6ebSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
24695d04f6ebSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
24705d04f6ebSMichael Lange   }
24715d04f6ebSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
24725d04f6ebSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
24735d04f6ebSMichael Lange   ierr = DMLabelDestroy(&lblLeaves);CHKERRQ(ierr);
2474be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
2475be200f8dSMichael Lange   ierr = DMLabelDistribute(label, sfPoint, &lblRoots);CHKERRQ(ierr);
2476be200f8dSMichael Lange   ierr = DMLabelGetValueIS(lblRoots, &rankIS);CHKERRQ(ierr);
2477be200f8dSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
2478be200f8dSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
2479be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
2480be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
2481be200f8dSMichael Lange     if (remoteRank == rank) continue;
2482be200f8dSMichael Lange     ierr = DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS);CHKERRQ(ierr);
2483be200f8dSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
2484be200f8dSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2485be200f8dSMichael Lange   }
2486be200f8dSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
2487be200f8dSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
2488be200f8dSMichael Lange   ierr = DMLabelDestroy(&lblRoots);CHKERRQ(ierr);
2489be200f8dSMichael Lange   PetscFunctionReturn(0);
2490be200f8dSMichael Lange }
2491be200f8dSMichael Lange 
24921fd9873aSMichael Lange /*@
24931fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
24941fd9873aSMichael Lange 
24951fd9873aSMichael Lange   Input Parameters:
24961fd9873aSMichael Lange + dm        - The DM
24971fd9873aSMichael Lange . rootLabel - DMLabel assinging ranks to local roots
24981fd9873aSMichael Lange . processSF - A star forest mapping into the local index on each remote rank
24991fd9873aSMichael Lange 
25001fd9873aSMichael Lange   Output Parameter:
25011fd9873aSMichael Lange - leafLabel - DMLabel assinging ranks to remote roots
25021fd9873aSMichael Lange 
25031fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
25041fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
25051fd9873aSMichael Lange 
25061fd9873aSMichael Lange   Level: developer
25071fd9873aSMichael Lange 
25081fd9873aSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
25091fd9873aSMichael Lange @*/
25101fd9873aSMichael Lange PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
25111fd9873aSMichael Lange {
25121fd9873aSMichael Lange   MPI_Comm           comm;
2513874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
2514874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
25151fd9873aSMichael Lange   PetscSF            sfPoint;
2516874ddda9SLisandro Dalcin   PetscSection       rootSection;
25171fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
25181fd9873aSMichael Lange   const PetscSFNode *remote;
25191fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
25201fd9873aSMichael Lange   IS                 valueIS;
2521874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
25221fd9873aSMichael Lange   PetscErrorCode     ierr;
25231fd9873aSMichael Lange 
25241fd9873aSMichael Lange   PetscFunctionBegin;
25251fd9873aSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
25261fd9873aSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
25279852e123SBarry Smith   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
25281fd9873aSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
25291fd9873aSMichael Lange 
25301fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
25311fd9873aSMichael Lange   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
25329852e123SBarry Smith   ierr = PetscSectionSetChart(rootSection, 0, size);CHKERRQ(ierr);
25331fd9873aSMichael Lange   ierr = DMLabelGetValueIS(rootLabel, &valueIS);CHKERRQ(ierr);
25341fd9873aSMichael Lange   ierr = ISGetLocalSize(valueIS, &numNeighbors);CHKERRQ(ierr);
25351fd9873aSMichael Lange   ierr = ISGetIndices(valueIS, &neighbors);CHKERRQ(ierr);
25361fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
25371fd9873aSMichael Lange     ierr = DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints);CHKERRQ(ierr);
25381fd9873aSMichael Lange     ierr = PetscSectionAddDof(rootSection, neighbors[n], numPoints);CHKERRQ(ierr);
25391fd9873aSMichael Lange   }
25401fd9873aSMichael Lange   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
2541874ddda9SLisandro Dalcin   ierr = PetscSectionGetStorageSize(rootSection, &rootSize);CHKERRQ(ierr);
2542874ddda9SLisandro Dalcin   ierr = PetscMalloc1(rootSize, &rootPoints);CHKERRQ(ierr);
25431fd9873aSMichael Lange   ierr = PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote);CHKERRQ(ierr);
25441fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
25451fd9873aSMichael Lange     IS              pointIS;
25461fd9873aSMichael Lange     const PetscInt *points;
25471fd9873aSMichael Lange 
25481fd9873aSMichael Lange     ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
25491fd9873aSMichael Lange     ierr = DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS);CHKERRQ(ierr);
25501fd9873aSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
25511fd9873aSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
25521fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
2553f8987ae8SMichael Lange       if (local) {ierr = PetscFindInt(points[p], nleaves, local, &l);CHKERRQ(ierr);}
2554f8987ae8SMichael Lange       else       {l = -1;}
25551fd9873aSMichael Lange       if (l >= 0) {rootPoints[off+p] = remote[l];}
25561fd9873aSMichael Lange       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
25571fd9873aSMichael Lange     }
25581fd9873aSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
25591fd9873aSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
25601fd9873aSMichael Lange   }
2561874ddda9SLisandro Dalcin 
2562874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
2563874ddda9SLisandro Dalcin   if (!processSF) {
2564874ddda9SLisandro Dalcin     PetscInt64  counter = 0;
2565874ddda9SLisandro Dalcin     PetscBool   locOverflow = PETSC_FALSE;
2566874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
2567874ddda9SLisandro Dalcin 
2568874ddda9SLisandro Dalcin     ierr = PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls);CHKERRQ(ierr);
2569874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
2570874ddda9SLisandro Dalcin       ierr = PetscSectionGetDof(rootSection, neighbors[n], &dof);CHKERRQ(ierr);
2571874ddda9SLisandro Dalcin       ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
2572874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
2573874ddda9SLisandro Dalcin       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2574874ddda9SLisandro Dalcin       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2575874ddda9SLisandro Dalcin #endif
2576874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt) dof;
2577874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt) off;
2578874ddda9SLisandro Dalcin     }
2579874ddda9SLisandro Dalcin     ierr = MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm);CHKERRQ(ierr);
2580874ddda9SLisandro Dalcin     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
2581874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
2582874ddda9SLisandro Dalcin     ierr = MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm);CHKERRQ(ierr);
2583874ddda9SLisandro Dalcin     if (!mpiOverflow) {
2584874ddda9SLisandro Dalcin       leafSize = (PetscInt) counter;
2585874ddda9SLisandro Dalcin       ierr = PetscMalloc1(leafSize, &leafPoints);CHKERRQ(ierr);
2586874ddda9SLisandro Dalcin       ierr = MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm);CHKERRQ(ierr);
2587874ddda9SLisandro Dalcin     }
2588874ddda9SLisandro Dalcin     ierr = PetscFree4(scounts, sdispls, rcounts, rdispls);CHKERRQ(ierr);
2589874ddda9SLisandro Dalcin   }
2590874ddda9SLisandro Dalcin 
2591874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
2592874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
2593874ddda9SLisandro Dalcin     PetscSF      procSF;
2594874ddda9SLisandro Dalcin     PetscSFNode  *remote;
2595874ddda9SLisandro Dalcin     PetscSection leafSection;
2596874ddda9SLisandro Dalcin 
2597874ddda9SLisandro Dalcin     if (processSF) {
2598874ddda9SLisandro Dalcin       ierr = PetscObjectReference((PetscObject)processSF);CHKERRQ(ierr);
2599874ddda9SLisandro Dalcin       procSF = processSF;
2600874ddda9SLisandro Dalcin     } else {
2601874ddda9SLisandro Dalcin       ierr = PetscMalloc1(size, &remote);CHKERRQ(ierr);
2602874ddda9SLisandro Dalcin       for (r = 0; r < size; ++r) { remote[r].rank  = r; remote[r].index = rank; }
2603874ddda9SLisandro Dalcin       ierr = PetscSFCreate(comm, &procSF);CHKERRQ(ierr);
2604874ddda9SLisandro Dalcin       ierr = PetscSFSetGraph(procSF, size, size, NULL, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
2605874ddda9SLisandro Dalcin     }
2606874ddda9SLisandro Dalcin 
2607874ddda9SLisandro Dalcin     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection);CHKERRQ(ierr);
26081fd9873aSMichael Lange     ierr = DMPlexDistributeData(dm, processSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints);CHKERRQ(ierr);
2609874ddda9SLisandro Dalcin     ierr = PetscSectionGetStorageSize(leafSection, &leafSize);CHKERRQ(ierr);
2610874ddda9SLisandro Dalcin     ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
2611874ddda9SLisandro Dalcin     ierr = PetscSFDestroy(&procSF);CHKERRQ(ierr);
2612874ddda9SLisandro Dalcin   }
2613874ddda9SLisandro Dalcin 
2614874ddda9SLisandro Dalcin   for (p = 0; p < leafSize; p++) {
26151fd9873aSMichael Lange     ierr = DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank);CHKERRQ(ierr);
26161fd9873aSMichael Lange   }
2617874ddda9SLisandro Dalcin 
2618874ddda9SLisandro Dalcin   ierr = ISRestoreIndices(valueIS, &neighbors);CHKERRQ(ierr);
2619874ddda9SLisandro Dalcin   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
26201fd9873aSMichael Lange   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
2621874ddda9SLisandro Dalcin   ierr = PetscFree(rootPoints);CHKERRQ(ierr);
26221fd9873aSMichael Lange   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
26231fd9873aSMichael Lange   PetscFunctionReturn(0);
26241fd9873aSMichael Lange }
26251fd9873aSMichael Lange 
2626aa3148a8SMichael Lange /*@
2627aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
2628aa3148a8SMichael Lange 
2629aa3148a8SMichael Lange   Input Parameters:
2630aa3148a8SMichael Lange + dm    - The DM
2631aa3148a8SMichael Lange . label - DMLabel assinging ranks to remote roots
2632aa3148a8SMichael Lange 
2633aa3148a8SMichael Lange   Output Parameter:
2634aa3148a8SMichael Lange - sf    - The star forest communication context encapsulating the defined mapping
2635aa3148a8SMichael Lange 
2636aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
2637aa3148a8SMichael Lange 
2638aa3148a8SMichael Lange   Level: developer
2639aa3148a8SMichael Lange 
2640aa3148a8SMichael Lange .seealso: DMPlexDistribute(), DMPlexCreateOverlap
2641aa3148a8SMichael Lange @*/
2642aa3148a8SMichael Lange PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
2643aa3148a8SMichael Lange {
26449852e123SBarry Smith   PetscMPIInt     rank, size;
264543f7d02bSMichael Lange   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0;
2646aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
264743f7d02bSMichael Lange   IS              remoteRootIS;
264843f7d02bSMichael Lange   const PetscInt *remoteRoots;
2649aa3148a8SMichael Lange   PetscErrorCode ierr;
2650aa3148a8SMichael Lange 
2651aa3148a8SMichael Lange   PetscFunctionBegin;
265243f7d02bSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
26539852e123SBarry Smith   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
2654aa3148a8SMichael Lange 
26559852e123SBarry Smith   for (numRemote = 0, n = 0; n < size; ++n) {
2656aa3148a8SMichael Lange     ierr = DMLabelGetStratumSize(label, n, &numPoints);CHKERRQ(ierr);
2657aa3148a8SMichael Lange     numRemote += numPoints;
2658aa3148a8SMichael Lange   }
2659aa3148a8SMichael Lange   ierr = PetscMalloc1(numRemote, &remotePoints);CHKERRQ(ierr);
266043f7d02bSMichael Lange   /* Put owned points first */
266143f7d02bSMichael Lange   ierr = DMLabelGetStratumSize(label, rank, &numPoints);CHKERRQ(ierr);
266243f7d02bSMichael Lange   if (numPoints > 0) {
266343f7d02bSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &remoteRootIS);CHKERRQ(ierr);
266443f7d02bSMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
266543f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
266643f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
266743f7d02bSMichael Lange       remotePoints[idx].rank = rank;
266843f7d02bSMichael Lange       idx++;
266943f7d02bSMichael Lange     }
267043f7d02bSMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
267143f7d02bSMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
267243f7d02bSMichael Lange   }
267343f7d02bSMichael Lange   /* Now add remote points */
26749852e123SBarry Smith   for (n = 0; n < size; ++n) {
2675aa3148a8SMichael Lange     ierr = DMLabelGetStratumSize(label, n, &numPoints);CHKERRQ(ierr);
267643f7d02bSMichael Lange     if (numPoints <= 0 || n == rank) continue;
2677aa3148a8SMichael Lange     ierr = DMLabelGetStratumIS(label, n, &remoteRootIS);CHKERRQ(ierr);
2678aa3148a8SMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
2679aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
2680aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
2681aa3148a8SMichael Lange       remotePoints[idx].rank = n;
2682aa3148a8SMichael Lange       idx++;
2683aa3148a8SMichael Lange     }
2684aa3148a8SMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
2685aa3148a8SMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
2686aa3148a8SMichael Lange   }
2687aa3148a8SMichael Lange   ierr = PetscSFCreate(PetscObjectComm((PetscObject) dm), sf);CHKERRQ(ierr);
2688aa3148a8SMichael Lange   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2689aa3148a8SMichael Lange   ierr = PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
269070034214SMatthew G. Knepley   PetscFunctionReturn(0);
269170034214SMatthew G. Knepley }
2692cb87ef4cSFlorian Wechsung 
26936a3739e5SFlorian Wechsung /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
26946a3739e5SFlorian Wechsung  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
26956a3739e5SFlorian Wechsung  * them out in that case. */
26966a3739e5SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
26977a82c785SFlorian Wechsung /*@C
26987f57c1a4SFlorian Wechsung 
26997f57c1a4SFlorian Wechsung   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).
27007f57c1a4SFlorian Wechsung 
27017f57c1a4SFlorian Wechsung   Input parameters:
27027f57c1a4SFlorian Wechsung   + dm                - The DMPlex object.
27037f57c1a4SFlorian Wechsung   + n                 - The number of points.
27047f57c1a4SFlorian Wechsung   + pointsToRewrite   - The points in the SF whose ownership will change.
27057f57c1a4SFlorian Wechsung   + targetOwners      - New owner for each element in pointsToRewrite.
27067f57c1a4SFlorian Wechsung   + degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.
27077f57c1a4SFlorian Wechsung 
27087f57c1a4SFlorian Wechsung   Level: developer
27097f57c1a4SFlorian Wechsung 
27107f57c1a4SFlorian Wechsung @*/
27117f57c1a4SFlorian Wechsung static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
27127f57c1a4SFlorian Wechsung {
27137f57c1a4SFlorian Wechsung   PetscInt      ierr, pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
27147f57c1a4SFlorian Wechsung   PetscInt     *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
27157f57c1a4SFlorian Wechsung   PetscSFNode  *leafLocationsNew;
27167f57c1a4SFlorian Wechsung   const         PetscSFNode *iremote;
27177f57c1a4SFlorian Wechsung   const         PetscInt *ilocal;
27187f57c1a4SFlorian Wechsung   PetscBool    *isLeaf;
27197f57c1a4SFlorian Wechsung   PetscSF       sf;
27207f57c1a4SFlorian Wechsung   MPI_Comm      comm;
27215a30b08bSFlorian Wechsung   PetscMPIInt   rank, size;
27227f57c1a4SFlorian Wechsung 
27237f57c1a4SFlorian Wechsung   PetscFunctionBegin;
27247f57c1a4SFlorian Wechsung   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
27257f57c1a4SFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
27267f57c1a4SFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
27277f57c1a4SFlorian Wechsung   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
27287f57c1a4SFlorian Wechsung 
27297f57c1a4SFlorian Wechsung   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
27307f57c1a4SFlorian Wechsung   ierr = PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote); CHKERRQ(ierr);
27317f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isLeaf);CHKERRQ(ierr);
27327f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
27337f57c1a4SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
27347f57c1a4SFlorian Wechsung   }
27357f57c1a4SFlorian Wechsung   for (i=0; i<nleafs; i++) {
27367f57c1a4SFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
27377f57c1a4SFlorian Wechsung   }
27387f57c1a4SFlorian Wechsung 
27397f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart+1, &cumSumDegrees);CHKERRQ(ierr);
27407f57c1a4SFlorian Wechsung   cumSumDegrees[0] = 0;
27417f57c1a4SFlorian Wechsung   for (i=1; i<=pEnd-pStart; i++) {
27427f57c1a4SFlorian Wechsung     cumSumDegrees[i] = cumSumDegrees[i-1] + degrees[i-1];
27437f57c1a4SFlorian Wechsung   }
27447f57c1a4SFlorian Wechsung   sumDegrees = cumSumDegrees[pEnd-pStart];
27457f57c1a4SFlorian Wechsung   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
27467f57c1a4SFlorian Wechsung 
27477f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(sumDegrees, &locationsOfLeafs);CHKERRQ(ierr);
27487f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &rankOnLeafs);CHKERRQ(ierr);
27497f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
27507f57c1a4SFlorian Wechsung     rankOnLeafs[i] = rank;
27517f57c1a4SFlorian Wechsung   }
27527f57c1a4SFlorian Wechsung   ierr = PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);CHKERRQ(ierr);
27537f57c1a4SFlorian Wechsung   ierr = PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);CHKERRQ(ierr);
27547f57c1a4SFlorian Wechsung   ierr = PetscFree(rankOnLeafs);CHKERRQ(ierr);
27557f57c1a4SFlorian Wechsung 
27567f57c1a4SFlorian Wechsung   /* get the remote local points of my leaves */
27577f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs);CHKERRQ(ierr);
27587f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &points);CHKERRQ(ierr);
27597f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
27607f57c1a4SFlorian Wechsung     points[i] = pStart+i;
27617f57c1a4SFlorian Wechsung   }
27627f57c1a4SFlorian Wechsung   ierr = PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs);CHKERRQ(ierr);
27637f57c1a4SFlorian Wechsung   ierr = PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs);CHKERRQ(ierr);
27647f57c1a4SFlorian Wechsung   ierr = PetscFree(points);CHKERRQ(ierr);
27657f57c1a4SFlorian Wechsung   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
27667f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &newOwners);CHKERRQ(ierr);
27677f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &newNumbers);CHKERRQ(ierr);
27687f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
27697f57c1a4SFlorian Wechsung     newOwners[i] = -1;
27707f57c1a4SFlorian Wechsung     newNumbers[i] = -1;
27717f57c1a4SFlorian Wechsung   }
27727f57c1a4SFlorian Wechsung   {
27737f57c1a4SFlorian Wechsung     PetscInt oldNumber, newNumber, oldOwner, newOwner;
27747f57c1a4SFlorian Wechsung     for (i=0; i<n; i++) {
27757f57c1a4SFlorian Wechsung       oldNumber = pointsToRewrite[i];
27767f57c1a4SFlorian Wechsung       newNumber = -1;
27777f57c1a4SFlorian Wechsung       oldOwner = rank;
27787f57c1a4SFlorian Wechsung       newOwner = targetOwners[i];
27797f57c1a4SFlorian Wechsung       if (oldOwner == newOwner) {
27807f57c1a4SFlorian Wechsung         newNumber = oldNumber;
27817f57c1a4SFlorian Wechsung       } else {
27827f57c1a4SFlorian Wechsung         for (j=0; j<degrees[oldNumber]; j++) {
27837f57c1a4SFlorian Wechsung           if (locationsOfLeafs[cumSumDegrees[oldNumber]+j] == newOwner) {
27847f57c1a4SFlorian Wechsung             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber]+j];
27857f57c1a4SFlorian Wechsung             break;
27867f57c1a4SFlorian Wechsung           }
27877f57c1a4SFlorian Wechsung         }
27887f57c1a4SFlorian Wechsung       }
27897f57c1a4SFlorian Wechsung       if (newNumber == -1) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
27907f57c1a4SFlorian Wechsung 
27917f57c1a4SFlorian Wechsung       newOwners[oldNumber] = newOwner;
27927f57c1a4SFlorian Wechsung       newNumbers[oldNumber] = newNumber;
27937f57c1a4SFlorian Wechsung     }
27947f57c1a4SFlorian Wechsung   }
27957f57c1a4SFlorian Wechsung   ierr = PetscFree(cumSumDegrees);CHKERRQ(ierr);
27967f57c1a4SFlorian Wechsung   ierr = PetscFree(locationsOfLeafs);CHKERRQ(ierr);
27977f57c1a4SFlorian Wechsung   ierr = PetscFree(remoteLocalPointOfLeafs);CHKERRQ(ierr);
27987f57c1a4SFlorian Wechsung 
27997f57c1a4SFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners);CHKERRQ(ierr);
28007f57c1a4SFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners);CHKERRQ(ierr);
28017f57c1a4SFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers);CHKERRQ(ierr);
28027f57c1a4SFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers);CHKERRQ(ierr);
28037f57c1a4SFlorian Wechsung 
28047f57c1a4SFlorian Wechsung   /* Now count how many leafs we have on each processor. */
28057f57c1a4SFlorian Wechsung   leafCounter=0;
28067f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28077f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
28087f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
28097f57c1a4SFlorian Wechsung         leafCounter++;
28107f57c1a4SFlorian Wechsung       }
28117f57c1a4SFlorian Wechsung     } else {
28127f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
28137f57c1a4SFlorian Wechsung         leafCounter++;
28147f57c1a4SFlorian Wechsung       }
28157f57c1a4SFlorian Wechsung     }
28167f57c1a4SFlorian Wechsung   }
28177f57c1a4SFlorian Wechsung 
28187f57c1a4SFlorian Wechsung   /* Now set up the new sf by creating the leaf arrays */
28197f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(leafCounter, &leafsNew);CHKERRQ(ierr);
28207f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(leafCounter, &leafLocationsNew);CHKERRQ(ierr);
28217f57c1a4SFlorian Wechsung 
28227f57c1a4SFlorian Wechsung   leafCounter = 0;
28237f57c1a4SFlorian Wechsung   counter = 0;
28247f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28257f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
28267f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
28277f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
28287f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = newOwners[i];
28297f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = newNumbers[i];
28307f57c1a4SFlorian Wechsung         leafCounter++;
28317f57c1a4SFlorian Wechsung       }
28327f57c1a4SFlorian Wechsung     } else {
28337f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
28347f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
28357f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = iremote[counter].rank;
28367f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = iremote[counter].index;
28377f57c1a4SFlorian Wechsung         leafCounter++;
28387f57c1a4SFlorian Wechsung       }
28397f57c1a4SFlorian Wechsung     }
28407f57c1a4SFlorian Wechsung     if (isLeaf[i]) {
28417f57c1a4SFlorian Wechsung       counter++;
28427f57c1a4SFlorian Wechsung     }
28437f57c1a4SFlorian Wechsung   }
28447f57c1a4SFlorian Wechsung 
28457f57c1a4SFlorian Wechsung   ierr = PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
28467f57c1a4SFlorian Wechsung   ierr = PetscFree(newOwners);CHKERRQ(ierr);
28477f57c1a4SFlorian Wechsung   ierr = PetscFree(newNumbers);CHKERRQ(ierr);
28487f57c1a4SFlorian Wechsung   ierr = PetscFree(isLeaf);CHKERRQ(ierr);
28497f57c1a4SFlorian Wechsung   PetscFunctionReturn(0);
28507f57c1a4SFlorian Wechsung }
28517f57c1a4SFlorian Wechsung 
2852125d2a8fSFlorian Wechsung static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
2853125d2a8fSFlorian Wechsung {
28545a30b08bSFlorian Wechsung   PetscInt *distribution, min, max, sum, i, ierr;
28555a30b08bSFlorian Wechsung   PetscMPIInt rank, size;
2856125d2a8fSFlorian Wechsung   PetscFunctionBegin;
2857125d2a8fSFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
2858125d2a8fSFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2859125d2a8fSFlorian Wechsung   ierr = PetscCalloc1(size, &distribution);CHKERRQ(ierr);
2860125d2a8fSFlorian Wechsung   for (i=0; i<n; i++) {
2861125d2a8fSFlorian Wechsung     if (part) distribution[part[i]] += vtxwgt[skip*i];
2862125d2a8fSFlorian Wechsung     else distribution[rank] += vtxwgt[skip*i];
2863125d2a8fSFlorian Wechsung   }
2864125d2a8fSFlorian Wechsung   ierr = MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
2865125d2a8fSFlorian Wechsung   min = distribution[0];
2866125d2a8fSFlorian Wechsung   max = distribution[0];
2867125d2a8fSFlorian Wechsung   sum = distribution[0];
2868125d2a8fSFlorian Wechsung   for (i=1; i<size; i++) {
2869125d2a8fSFlorian Wechsung     if (distribution[i]<min) min=distribution[i];
2870125d2a8fSFlorian Wechsung     if (distribution[i]>max) max=distribution[i];
2871125d2a8fSFlorian Wechsung     sum += distribution[i];
2872125d2a8fSFlorian Wechsung   }
2873125d2a8fSFlorian Wechsung   ierr = PetscViewerASCIIPrintf(viewer, "Min: %D, Avg: %D, Max: %D, Balance: %f\n", min, sum/size, max, (max*1.*size)/sum);CHKERRQ(ierr);
2874125d2a8fSFlorian Wechsung   ierr = PetscFree(distribution);CHKERRQ(ierr);
2875125d2a8fSFlorian Wechsung   PetscFunctionReturn(0);
2876125d2a8fSFlorian Wechsung }
2877125d2a8fSFlorian Wechsung 
28786a3739e5SFlorian Wechsung #endif
28796a3739e5SFlorian Wechsung 
2880cb87ef4cSFlorian Wechsung /*@
28815dc86ac1SFlorian Wechsung   DMPlexRebalanceSharedPoints - Redistribute points in the plex that are shared in order to achieve better balancing. This routine updates the PointSF of the DM inplace.
2882cb87ef4cSFlorian Wechsung 
2883cb87ef4cSFlorian Wechsung   Input parameters:
2884ed44d270SFlorian Wechsung   + dm               - The DMPlex object.
28857f57c1a4SFlorian Wechsung   + entityDepth      - depth of the entity to balance (0 -> balance vertices).
28867f57c1a4SFlorian Wechsung   + useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
28877f57c1a4SFlorian Wechsung   + parallel         - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.
2888cb87ef4cSFlorian Wechsung 
28898b879b41SFlorian Wechsung   Output parameters:
28908b879b41SFlorian Wechsung   + success          - whether the graph partitioning was successful or not. If not, try useInitialGuess=True and parallel=True.
28918b879b41SFlorian Wechsung 
2892cb87ef4cSFlorian Wechsung   Level: user
2893cb87ef4cSFlorian Wechsung 
2894cb87ef4cSFlorian Wechsung @*/
2895cb87ef4cSFlorian Wechsung 
28968b879b41SFlorian Wechsung PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
2897cb87ef4cSFlorian Wechsung {
289841525646SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
2899cb87ef4cSFlorian Wechsung   PetscSF     sf;
29000faf6628SFlorian Wechsung   PetscInt    ierr, i, j, idx, jdx;
29017f57c1a4SFlorian Wechsung   PetscInt    eBegin, eEnd, nroots, nleafs, pStart, pEnd;
29027f57c1a4SFlorian Wechsung   const       PetscInt *degrees, *ilocal;
29037f57c1a4SFlorian Wechsung   const       PetscSFNode *iremote;
2904cb87ef4cSFlorian Wechsung   PetscBool   *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
2905cf818975SFlorian Wechsung   PetscInt    numExclusivelyOwned, numNonExclusivelyOwned;
2906cb87ef4cSFlorian Wechsung   PetscMPIInt rank, size;
29077f57c1a4SFlorian Wechsung   PetscInt    *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
29085dc86ac1SFlorian Wechsung   const       PetscInt *cumSumVertices;
2909cb87ef4cSFlorian Wechsung   PetscInt    offset, counter;
29107f57c1a4SFlorian Wechsung   PetscInt    lenadjncy;
2911cb87ef4cSFlorian Wechsung   PetscInt    *xadj, *adjncy, *vtxwgt;
2912cb87ef4cSFlorian Wechsung   PetscInt    lenxadj;
2913cb87ef4cSFlorian Wechsung   PetscInt    *adjwgt = NULL;
2914cb87ef4cSFlorian Wechsung   PetscInt    *part, *options;
2915cf818975SFlorian Wechsung   PetscInt    nparts, wgtflag, numflag, ncon, edgecut;
2916cb87ef4cSFlorian Wechsung   real_t      *ubvec;
2917cb87ef4cSFlorian Wechsung   PetscInt    *firstVertices, *renumbering;
2918cb87ef4cSFlorian Wechsung   PetscInt    failed, failedGlobal;
2919cb87ef4cSFlorian Wechsung   MPI_Comm    comm;
29204baf1206SFlorian Wechsung   Mat         A, Apre;
292112617df9SFlorian Wechsung   const char *prefix = NULL;
29227d197802SFlorian Wechsung   PetscViewer       viewer;
29237d197802SFlorian Wechsung   PetscViewerFormat format;
29245a30b08bSFlorian Wechsung   PetscLayout layout;
292512617df9SFlorian Wechsung 
292612617df9SFlorian Wechsung   PetscFunctionBegin;
29278b879b41SFlorian Wechsung   if (success) *success = PETSC_FALSE;
29287f57c1a4SFlorian Wechsung   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
29297f57c1a4SFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
29307f57c1a4SFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
29317f57c1a4SFlorian Wechsung   if (size==1) PetscFunctionReturn(0);
29327f57c1a4SFlorian Wechsung 
293341525646SFlorian Wechsung   ierr = PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
293441525646SFlorian Wechsung 
29355a30b08bSFlorian Wechsung   ierr = PetscOptionsGetViewer(comm,((PetscObject)dm)->options, prefix,"-dm_rebalance_partition_view",&viewer,&format,NULL);CHKERRQ(ierr);
29365dc86ac1SFlorian Wechsung   if (viewer) {
29375a30b08bSFlorian Wechsung     ierr = PetscViewerPushFormat(viewer,format);CHKERRQ(ierr);
29387d197802SFlorian Wechsung   }
29397d197802SFlorian Wechsung 
2940ed44d270SFlorian Wechsung   /* Figure out all points in the plex that we are interested in balancing. */
2941d5528e35SFlorian Wechsung   ierr = DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd);CHKERRQ(ierr);
2942cb87ef4cSFlorian Wechsung   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2943cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &toBalance);CHKERRQ(ierr);
2944cf818975SFlorian Wechsung 
2945cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
29465a7e692eSFlorian Wechsung     toBalance[i] = (PetscBool)(i-pStart>=eBegin && i-pStart<eEnd);
2947cb87ef4cSFlorian Wechsung   }
2948cb87ef4cSFlorian Wechsung 
2949cf818975SFlorian Wechsung   /* There are three types of points:
2950cf818975SFlorian Wechsung    * exclusivelyOwned: points that are owned by this process and only seen by this process
2951cf818975SFlorian Wechsung    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
2952cf818975SFlorian Wechsung    * leaf: a point that is seen by this process but owned by a different process
2953cf818975SFlorian Wechsung    */
2954cb87ef4cSFlorian Wechsung   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
2955cb87ef4cSFlorian Wechsung   ierr = PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote); CHKERRQ(ierr);
2956cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isLeaf);CHKERRQ(ierr);
2957cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isNonExclusivelyOwned);CHKERRQ(ierr);
2958cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isExclusivelyOwned);CHKERRQ(ierr);
2959cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
2960cb87ef4cSFlorian Wechsung     isNonExclusivelyOwned[i] = PETSC_FALSE;
2961cb87ef4cSFlorian Wechsung     isExclusivelyOwned[i] = PETSC_FALSE;
2962cf818975SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
2963cb87ef4cSFlorian Wechsung   }
2964cf818975SFlorian Wechsung 
2965cf818975SFlorian Wechsung   /* start by marking all the leafs */
2966cb87ef4cSFlorian Wechsung   for (i=0; i<nleafs; i++) {
2967cb87ef4cSFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
2968cb87ef4cSFlorian Wechsung   }
2969cb87ef4cSFlorian Wechsung 
2970cf818975SFlorian Wechsung   /* for an owned point, we can figure out whether another processor sees it or
2971cf818975SFlorian Wechsung    * not by calculating its degree */
29727f57c1a4SFlorian Wechsung   ierr = PetscSFComputeDegreeBegin(sf, &degrees);CHKERRQ(ierr);
29737f57c1a4SFlorian Wechsung   ierr = PetscSFComputeDegreeEnd(sf, &degrees);CHKERRQ(ierr);
2974cf818975SFlorian Wechsung 
2975cb87ef4cSFlorian Wechsung   numExclusivelyOwned = 0;
2976cb87ef4cSFlorian Wechsung   numNonExclusivelyOwned = 0;
2977cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
2978cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
29797f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
2980cb87ef4cSFlorian Wechsung         isNonExclusivelyOwned[i] = PETSC_TRUE;
2981cb87ef4cSFlorian Wechsung         numNonExclusivelyOwned += 1;
2982cb87ef4cSFlorian Wechsung       } else {
2983cb87ef4cSFlorian Wechsung         if (!isLeaf[i]) {
2984cb87ef4cSFlorian Wechsung           isExclusivelyOwned[i] = PETSC_TRUE;
2985cb87ef4cSFlorian Wechsung           numExclusivelyOwned += 1;
2986cb87ef4cSFlorian Wechsung         }
2987cb87ef4cSFlorian Wechsung       }
2988cb87ef4cSFlorian Wechsung     }
2989cb87ef4cSFlorian Wechsung   }
2990cb87ef4cSFlorian Wechsung 
2991cf818975SFlorian Wechsung   /* We are going to build a graph with one vertex per core representing the
2992cf818975SFlorian Wechsung    * exclusively owned points and then one vertex per nonExclusively owned
2993cf818975SFlorian Wechsung    * point. */
2994cb87ef4cSFlorian Wechsung 
29955dc86ac1SFlorian Wechsung   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
29965dc86ac1SFlorian Wechsung   ierr = PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned);CHKERRQ(ierr);
29975dc86ac1SFlorian Wechsung   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
29985dc86ac1SFlorian Wechsung   ierr = PetscLayoutGetRanges(layout, &cumSumVertices);CHKERRQ(ierr);
29995dc86ac1SFlorian Wechsung 
3000cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &globalNumbersOfLocalOwnedVertices);CHKERRQ(ierr);
3001cb87ef4cSFlorian Wechsung   offset = cumSumVertices[rank];
3002cb87ef4cSFlorian Wechsung   counter = 0;
3003cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
3004cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
30057f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
3006cb87ef4cSFlorian Wechsung         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
3007cb87ef4cSFlorian Wechsung         counter++;
3008cb87ef4cSFlorian Wechsung       }
3009cb87ef4cSFlorian Wechsung     }
3010cb87ef4cSFlorian Wechsung   }
3011cb87ef4cSFlorian Wechsung 
3012cb87ef4cSFlorian Wechsung   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
3013cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &leafGlobalNumbers);CHKERRQ(ierr);
3014cb87ef4cSFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers);CHKERRQ(ierr);
3015cb87ef4cSFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers);CHKERRQ(ierr);
3016cb87ef4cSFlorian Wechsung 
30170faf6628SFlorian Wechsung   /* Now start building the data structure for ParMETIS */
3018cb87ef4cSFlorian Wechsung 
30194baf1206SFlorian Wechsung   ierr = MatCreate(comm, &Apre);CHKERRQ(ierr);
30204baf1206SFlorian Wechsung   ierr = MatSetType(Apre, MATPREALLOCATOR);CHKERRQ(ierr);
30214baf1206SFlorian Wechsung   ierr = MatSetSizes(Apre, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);CHKERRQ(ierr);
30224baf1206SFlorian Wechsung   ierr = MatSetUp(Apre);CHKERRQ(ierr);
30238c9a1619SFlorian Wechsung 
30248c9a1619SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
30258c9a1619SFlorian Wechsung     if (toBalance[i]) {
30260faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
30270faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
30280faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
30290faf6628SFlorian Wechsung       else continue;
30300faf6628SFlorian Wechsung       ierr = MatSetValue(Apre, idx, jdx, 1, INSERT_VALUES);CHKERRQ(ierr);
30310faf6628SFlorian Wechsung       ierr = MatSetValue(Apre, jdx, idx, 1, INSERT_VALUES);CHKERRQ(ierr);
30324baf1206SFlorian Wechsung     }
30334baf1206SFlorian Wechsung   }
30344baf1206SFlorian Wechsung 
30354baf1206SFlorian Wechsung   ierr = MatAssemblyBegin(Apre, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
30364baf1206SFlorian Wechsung   ierr = MatAssemblyEnd(Apre, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
30374baf1206SFlorian Wechsung 
30384baf1206SFlorian Wechsung   ierr = MatCreate(comm, &A);CHKERRQ(ierr);
30394baf1206SFlorian Wechsung   ierr = MatSetType(A, MATMPIAIJ);CHKERRQ(ierr);
30404baf1206SFlorian Wechsung   ierr = MatSetSizes(A, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);CHKERRQ(ierr);
30414baf1206SFlorian Wechsung   ierr = MatPreallocatorPreallocate(Apre, PETSC_FALSE, A);CHKERRQ(ierr);
30424baf1206SFlorian Wechsung   ierr = MatDestroy(&Apre);CHKERRQ(ierr);
30434baf1206SFlorian Wechsung 
30444baf1206SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
30454baf1206SFlorian Wechsung     if (toBalance[i]) {
30460faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
30470faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
30480faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
30490faf6628SFlorian Wechsung       else continue;
30500faf6628SFlorian Wechsung       ierr = MatSetValue(A, idx, jdx, 1, INSERT_VALUES);CHKERRQ(ierr);
30510faf6628SFlorian Wechsung       ierr = MatSetValue(A, jdx, idx, 1, INSERT_VALUES);CHKERRQ(ierr);
30520941debbSFlorian Wechsung     }
30530941debbSFlorian Wechsung   }
30548c9a1619SFlorian Wechsung 
30558c9a1619SFlorian Wechsung   ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
30568c9a1619SFlorian Wechsung   ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
30574baf1206SFlorian Wechsung   ierr = PetscFree(leafGlobalNumbers);CHKERRQ(ierr);
30584baf1206SFlorian Wechsung   ierr = PetscFree(globalNumbersOfLocalOwnedVertices);CHKERRQ(ierr);
30594baf1206SFlorian Wechsung 
306041525646SFlorian Wechsung   nparts = size;
306141525646SFlorian Wechsung   wgtflag = 2;
306241525646SFlorian Wechsung   numflag = 0;
306341525646SFlorian Wechsung   ncon = 2;
306441525646SFlorian Wechsung   real_t *tpwgts;
306541525646SFlorian Wechsung   ierr = PetscMalloc1(ncon * nparts, &tpwgts);CHKERRQ(ierr);
306641525646SFlorian Wechsung   for (i=0; i<ncon*nparts; i++) {
306741525646SFlorian Wechsung     tpwgts[i] = 1./(nparts);
306841525646SFlorian Wechsung   }
306941525646SFlorian Wechsung 
307041525646SFlorian Wechsung   ierr = PetscMalloc1(ncon, &ubvec);CHKERRQ(ierr);
307141525646SFlorian Wechsung   ubvec[0] = 1.01;
30725a30b08bSFlorian Wechsung   ubvec[1] = 1.01;
30738c9a1619SFlorian Wechsung   lenadjncy = 0;
30748c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
30758c9a1619SFlorian Wechsung     PetscInt temp=0;
30768c9a1619SFlorian Wechsung     ierr = MatGetRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);CHKERRQ(ierr);
30778c9a1619SFlorian Wechsung     lenadjncy += temp;
30788c9a1619SFlorian Wechsung     ierr = MatRestoreRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);CHKERRQ(ierr);
30798c9a1619SFlorian Wechsung   }
30808c9a1619SFlorian Wechsung   ierr = PetscMalloc1(lenadjncy, &adjncy);CHKERRQ(ierr);
30817407ba93SFlorian Wechsung   lenxadj = 2 + numNonExclusivelyOwned;
30820941debbSFlorian Wechsung   ierr = PetscMalloc1(lenxadj, &xadj);CHKERRQ(ierr);
30830941debbSFlorian Wechsung   xadj[0] = 0;
30848c9a1619SFlorian Wechsung   counter = 0;
30858c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
30862953a68cSFlorian Wechsung     PetscInt        temp=0;
30872953a68cSFlorian Wechsung     const PetscInt *cols;
30888c9a1619SFlorian Wechsung     ierr = MatGetRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);CHKERRQ(ierr);
3089694ea26eSFlorian Wechsung     ierr = PetscMemcpy(&adjncy[counter], cols, temp*sizeof(PetscInt));CHKERRQ(ierr);
30908c9a1619SFlorian Wechsung     counter += temp;
30910941debbSFlorian Wechsung     xadj[i+1] = counter;
30928c9a1619SFlorian Wechsung     ierr = MatRestoreRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);CHKERRQ(ierr);
30938c9a1619SFlorian Wechsung   }
30948c9a1619SFlorian Wechsung 
3095cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(cumSumVertices[rank+1]-cumSumVertices[rank], &part);CHKERRQ(ierr);
309641525646SFlorian Wechsung   ierr = PetscMalloc1(ncon*(1 + numNonExclusivelyOwned), &vtxwgt);CHKERRQ(ierr);
309741525646SFlorian Wechsung   vtxwgt[0] = numExclusivelyOwned;
309841525646SFlorian Wechsung   if (ncon>1) vtxwgt[1] = 1;
309941525646SFlorian Wechsung   for (i=0; i<numNonExclusivelyOwned; i++) {
310041525646SFlorian Wechsung     vtxwgt[ncon*(i+1)] = 1;
310141525646SFlorian Wechsung     if (ncon>1) vtxwgt[ncon*(i+1)+1] = 0;
310241525646SFlorian Wechsung   }
31038c9a1619SFlorian Wechsung 
31045dc86ac1SFlorian Wechsung   if (viewer) {
31057d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %D on interface of mesh distribution.\n", entityDepth);CHKERRQ(ierr);
31067d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %D\n", cumSumVertices[size]);CHKERRQ(ierr);
310712617df9SFlorian Wechsung   }
310841525646SFlorian Wechsung   if (parallel) {
31095a30b08bSFlorian Wechsung     ierr = PetscMalloc1(4, &options);CHKERRQ(ierr);
31105a30b08bSFlorian Wechsung     options[0] = 1;
31115a30b08bSFlorian Wechsung     options[1] = 0; /* Verbosity */
31125a30b08bSFlorian Wechsung     options[2] = 0; /* Seed */
31135a30b08bSFlorian Wechsung     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
31145dc86ac1SFlorian Wechsung     if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n");CHKERRQ(ierr); }
31158c9a1619SFlorian Wechsung     if (useInitialGuess) {
31165dc86ac1SFlorian Wechsung       if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n");CHKERRQ(ierr); }
31178c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_RefineKway");
31185dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_RefineKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
311906b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
31208c9a1619SFlorian Wechsung       PetscStackPop;
31218c9a1619SFlorian Wechsung     } else {
31228c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_PartKway");
31235dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_PartKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
31248c9a1619SFlorian Wechsung       PetscStackPop;
312506b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
31268c9a1619SFlorian Wechsung     }
3127ef74bcceSFlorian Wechsung     ierr = PetscFree(options);CHKERRQ(ierr);
312841525646SFlorian Wechsung   } else {
31295dc86ac1SFlorian Wechsung     if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n");CHKERRQ(ierr); }
313041525646SFlorian Wechsung     Mat As;
313141525646SFlorian Wechsung     PetscInt numRows;
313241525646SFlorian Wechsung     PetscInt *partGlobal;
313341525646SFlorian Wechsung     ierr = MatCreateRedundantMatrix(A, size, MPI_COMM_NULL, MAT_INITIAL_MATRIX, &As);CHKERRQ(ierr);
3134cb87ef4cSFlorian Wechsung 
313541525646SFlorian Wechsung     PetscInt *numExclusivelyOwnedAll;
313641525646SFlorian Wechsung     ierr = PetscMalloc1(size, &numExclusivelyOwnedAll);CHKERRQ(ierr);
313741525646SFlorian Wechsung     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
31382953a68cSFlorian Wechsung     ierr = MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,numExclusivelyOwnedAll,1,MPIU_INT,comm);CHKERRQ(ierr);
3139cb87ef4cSFlorian Wechsung 
314041525646SFlorian Wechsung     ierr = MatGetSize(As, &numRows, NULL);CHKERRQ(ierr);
314141525646SFlorian Wechsung     ierr = PetscMalloc1(numRows, &partGlobal);CHKERRQ(ierr);
31425dc86ac1SFlorian Wechsung     if (!rank) {
314341525646SFlorian Wechsung       PetscInt *adjncy_g, *xadj_g, *vtxwgt_g;
314441525646SFlorian Wechsung       lenadjncy = 0;
314541525646SFlorian Wechsung 
314641525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
314741525646SFlorian Wechsung         PetscInt temp=0;
314841525646SFlorian Wechsung         ierr = MatGetRow(As, i, &temp, NULL, NULL);CHKERRQ(ierr);
314941525646SFlorian Wechsung         lenadjncy += temp;
315041525646SFlorian Wechsung         ierr = MatRestoreRow(As, i, &temp, NULL, NULL);CHKERRQ(ierr);
315141525646SFlorian Wechsung       }
315241525646SFlorian Wechsung       ierr = PetscMalloc1(lenadjncy, &adjncy_g);CHKERRQ(ierr);
315341525646SFlorian Wechsung       lenxadj = 1 + numRows;
315441525646SFlorian Wechsung       ierr = PetscMalloc1(lenxadj, &xadj_g);CHKERRQ(ierr);
315541525646SFlorian Wechsung       xadj_g[0] = 0;
315641525646SFlorian Wechsung       counter = 0;
315741525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
31582953a68cSFlorian Wechsung         PetscInt        temp=0;
31592953a68cSFlorian Wechsung         const PetscInt *cols;
316041525646SFlorian Wechsung         ierr = MatGetRow(As, i, &temp, &cols, NULL);CHKERRQ(ierr);
3161694ea26eSFlorian Wechsung         ierr = PetscMemcpy(&adjncy_g[counter], cols, temp*sizeof(PetscInt));CHKERRQ(ierr);
316241525646SFlorian Wechsung         counter += temp;
316341525646SFlorian Wechsung         xadj_g[i+1] = counter;
316441525646SFlorian Wechsung         ierr = MatRestoreRow(As, i, &temp, &cols, NULL);CHKERRQ(ierr);
316541525646SFlorian Wechsung       }
316641525646SFlorian Wechsung       ierr = PetscMalloc1(2*numRows, &vtxwgt_g);CHKERRQ(ierr);
316741525646SFlorian Wechsung       for (i=0; i<size; i++){
316841525646SFlorian Wechsung         vtxwgt_g[ncon*cumSumVertices[i]] = numExclusivelyOwnedAll[i];
316941525646SFlorian Wechsung         if (ncon>1) vtxwgt_g[ncon*cumSumVertices[i]+1] = 1;
317041525646SFlorian Wechsung         for (j=cumSumVertices[i]+1; j<cumSumVertices[i+1]; j++) {
317141525646SFlorian Wechsung           vtxwgt_g[ncon*j] = 1;
317241525646SFlorian Wechsung           if (ncon>1) vtxwgt_g[2*j+1] = 0;
317341525646SFlorian Wechsung         }
317441525646SFlorian Wechsung       }
317541525646SFlorian Wechsung       ierr = PetscMalloc1(64, &options);CHKERRQ(ierr);
317641525646SFlorian Wechsung       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
317706b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
317841525646SFlorian Wechsung       options[METIS_OPTION_CONTIG] = 1;
317941525646SFlorian Wechsung       PetscStackPush("METIS_PartGraphKway");
318006b3913eSFlorian Wechsung       ierr = METIS_PartGraphKway(&numRows, &ncon, xadj_g, adjncy_g, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
318141525646SFlorian Wechsung       PetscStackPop;
318206b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
3183ef74bcceSFlorian Wechsung       ierr = PetscFree(options);CHKERRQ(ierr);
318441525646SFlorian Wechsung       ierr = PetscFree(xadj_g);CHKERRQ(ierr);
318541525646SFlorian Wechsung       ierr = PetscFree(adjncy_g);CHKERRQ(ierr);
318641525646SFlorian Wechsung       ierr = PetscFree(vtxwgt_g);CHKERRQ(ierr);
318741525646SFlorian Wechsung     }
318841525646SFlorian Wechsung     ierr = PetscFree(numExclusivelyOwnedAll);CHKERRQ(ierr);
318941525646SFlorian Wechsung 
31905dc86ac1SFlorian Wechsung     /* Now scatter the parts array. */
31915dc86ac1SFlorian Wechsung     {
319281a13b52SFlorian Wechsung       PetscMPIInt *counts, *mpiCumSumVertices;
31935dc86ac1SFlorian Wechsung       ierr = PetscMalloc1(size, &counts);CHKERRQ(ierr);
319481a13b52SFlorian Wechsung       ierr = PetscMalloc1(size+1, &mpiCumSumVertices);CHKERRQ(ierr);
31955dc86ac1SFlorian Wechsung       for(i=0; i<size; i++) {
319681a13b52SFlorian Wechsung         ierr = PetscMPIIntCast(cumSumVertices[i+1] - cumSumVertices[i], &(counts[i]));CHKERRQ(ierr);
319741525646SFlorian Wechsung       }
319881a13b52SFlorian Wechsung       for(i=0; i<=size; i++) {
319981a13b52SFlorian Wechsung         ierr = PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i]));CHKERRQ(ierr);
320081a13b52SFlorian Wechsung       }
320181a13b52SFlorian Wechsung       ierr = MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm);CHKERRQ(ierr);
32025dc86ac1SFlorian Wechsung       ierr = PetscFree(counts);CHKERRQ(ierr);
320381a13b52SFlorian Wechsung       ierr = PetscFree(mpiCumSumVertices);CHKERRQ(ierr);
32045dc86ac1SFlorian Wechsung     }
32055dc86ac1SFlorian Wechsung 
320641525646SFlorian Wechsung     ierr = PetscFree(partGlobal);CHKERRQ(ierr);
32072953a68cSFlorian Wechsung     ierr = MatDestroy(&As);CHKERRQ(ierr);
320841525646SFlorian Wechsung   }
3209cb87ef4cSFlorian Wechsung 
32102953a68cSFlorian Wechsung   ierr = MatDestroy(&A);CHKERRQ(ierr);
3211cb87ef4cSFlorian Wechsung   ierr = PetscFree(ubvec);CHKERRQ(ierr);
3212cb87ef4cSFlorian Wechsung   ierr = PetscFree(tpwgts);CHKERRQ(ierr);
3213cb87ef4cSFlorian Wechsung 
3214cb87ef4cSFlorian Wechsung   /* Now rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
3215cb87ef4cSFlorian Wechsung 
3216cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(size, &firstVertices);CHKERRQ(ierr);
3217cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(size, &renumbering);CHKERRQ(ierr);
3218cb87ef4cSFlorian Wechsung   firstVertices[rank] = part[0];
32192953a68cSFlorian Wechsung   ierr = MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,firstVertices,1,MPIU_INT,comm);CHKERRQ(ierr);
3220cb87ef4cSFlorian Wechsung   for (i=0; i<size; i++) {
3221cb87ef4cSFlorian Wechsung     renumbering[firstVertices[i]] = i;
3222cb87ef4cSFlorian Wechsung   }
3223cb87ef4cSFlorian Wechsung   for (i=0; i<cumSumVertices[rank+1]-cumSumVertices[rank]; i++) {
3224cb87ef4cSFlorian Wechsung     part[i] = renumbering[part[i]];
3225cb87ef4cSFlorian Wechsung   }
3226cb87ef4cSFlorian Wechsung   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
3227cb87ef4cSFlorian Wechsung   failed = (PetscInt)(part[0] != rank);
32282953a68cSFlorian Wechsung   ierr = MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
3229cb87ef4cSFlorian Wechsung 
32307f57c1a4SFlorian Wechsung   ierr = PetscFree(firstVertices);CHKERRQ(ierr);
32317f57c1a4SFlorian Wechsung   ierr = PetscFree(renumbering);CHKERRQ(ierr);
32327f57c1a4SFlorian Wechsung 
3233cb87ef4cSFlorian Wechsung   if (failedGlobal > 0) {
32347f57c1a4SFlorian Wechsung     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
32357f57c1a4SFlorian Wechsung     ierr = PetscFree(xadj);CHKERRQ(ierr);
32367f57c1a4SFlorian Wechsung     ierr = PetscFree(adjncy);CHKERRQ(ierr);
32377f57c1a4SFlorian Wechsung     ierr = PetscFree(vtxwgt);CHKERRQ(ierr);
32387f57c1a4SFlorian Wechsung     ierr = PetscFree(toBalance);CHKERRQ(ierr);
32397f57c1a4SFlorian Wechsung     ierr = PetscFree(isLeaf);CHKERRQ(ierr);
32407f57c1a4SFlorian Wechsung     ierr = PetscFree(isNonExclusivelyOwned);CHKERRQ(ierr);
32417f57c1a4SFlorian Wechsung     ierr = PetscFree(isExclusivelyOwned);CHKERRQ(ierr);
32427f57c1a4SFlorian Wechsung     ierr = PetscFree(part);CHKERRQ(ierr);
32437f57c1a4SFlorian Wechsung     if (viewer) {
324406b3913eSFlorian Wechsung       ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
324506b3913eSFlorian Wechsung       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
32467f57c1a4SFlorian Wechsung     }
32477f57c1a4SFlorian Wechsung     ierr = PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
32488b879b41SFlorian Wechsung     PetscFunctionReturn(0);
3249cb87ef4cSFlorian Wechsung   }
3250cb87ef4cSFlorian Wechsung 
32517407ba93SFlorian Wechsung   /*Let's check how well we did distributing points*/
32525dc86ac1SFlorian Wechsung   if (viewer) {
32537d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Comparing number of owned entities of depth %D on each process before rebalancing, after rebalancing, and after consistency checks.\n", entityDepth);CHKERRQ(ierr);
3254125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Initial.     ");CHKERRQ(ierr);
3255125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, NULL, viewer);CHKERRQ(ierr);
3256125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Rebalanced.  ");CHKERRQ(ierr);
3257125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);CHKERRQ(ierr);
32587407ba93SFlorian Wechsung   }
32597407ba93SFlorian Wechsung 
3260cb87ef4cSFlorian Wechsung   /* Now check that every vertex is owned by a process that it is actually connected to. */
326141525646SFlorian Wechsung   for (i=1; i<=numNonExclusivelyOwned; i++) {
3262cb87ef4cSFlorian Wechsung     PetscInt loc = 0;
326341525646SFlorian Wechsung     ierr = PetscFindInt(cumSumVertices[part[i]], xadj[i+1]-xadj[i], &adjncy[xadj[i]], &loc);CHKERRQ(ierr);
32647407ba93SFlorian Wechsung     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
3265cb87ef4cSFlorian Wechsung     if (loc<0) {
326641525646SFlorian Wechsung       part[i] = rank;
3267cb87ef4cSFlorian Wechsung     }
3268cb87ef4cSFlorian Wechsung   }
3269cb87ef4cSFlorian Wechsung 
32707407ba93SFlorian Wechsung   /* Let's see how significant the influences of the previous fixing up step was.*/
32715dc86ac1SFlorian Wechsung   if (viewer) {
3272125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "After.       ");CHKERRQ(ierr);
3273125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);CHKERRQ(ierr);
32747407ba93SFlorian Wechsung   }
32757407ba93SFlorian Wechsung 
32765dc86ac1SFlorian Wechsung   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3277cb87ef4cSFlorian Wechsung   ierr = PetscFree(xadj);CHKERRQ(ierr);
3278cb87ef4cSFlorian Wechsung   ierr = PetscFree(adjncy);CHKERRQ(ierr);
327941525646SFlorian Wechsung   ierr = PetscFree(vtxwgt);CHKERRQ(ierr);
3280cb87ef4cSFlorian Wechsung 
32817f57c1a4SFlorian Wechsung   /* Almost done, now rewrite the SF to reflect the new ownership. */
3282cf818975SFlorian Wechsung   {
32837f57c1a4SFlorian Wechsung     PetscInt *pointsToRewrite;
328406b3913eSFlorian Wechsung     ierr = PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite);CHKERRQ(ierr);
32857f57c1a4SFlorian Wechsung     counter = 0;
3286cb87ef4cSFlorian Wechsung     for(i=0; i<pEnd-pStart; i++) {
3287cb87ef4cSFlorian Wechsung       if (toBalance[i]) {
3288cb87ef4cSFlorian Wechsung         if (isNonExclusivelyOwned[i]) {
32897f57c1a4SFlorian Wechsung           pointsToRewrite[counter] = i + pStart;
3290cb87ef4cSFlorian Wechsung           counter++;
3291cb87ef4cSFlorian Wechsung         }
3292cb87ef4cSFlorian Wechsung       }
3293cb87ef4cSFlorian Wechsung     }
32947f57c1a4SFlorian Wechsung     ierr = DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part+1, degrees);CHKERRQ(ierr);
32957f57c1a4SFlorian Wechsung     ierr = PetscFree(pointsToRewrite);CHKERRQ(ierr);
3296cf818975SFlorian Wechsung   }
3297cb87ef4cSFlorian Wechsung 
3298cb87ef4cSFlorian Wechsung   ierr = PetscFree(toBalance);CHKERRQ(ierr);
3299cb87ef4cSFlorian Wechsung   ierr = PetscFree(isLeaf);CHKERRQ(ierr);
3300cf818975SFlorian Wechsung   ierr = PetscFree(isNonExclusivelyOwned);CHKERRQ(ierr);
3301cf818975SFlorian Wechsung   ierr = PetscFree(isExclusivelyOwned);CHKERRQ(ierr);
33027f57c1a4SFlorian Wechsung   ierr = PetscFree(part);CHKERRQ(ierr);
33035dc86ac1SFlorian Wechsung   if (viewer) {
330406b3913eSFlorian Wechsung     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
330506b3913eSFlorian Wechsung     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
33067d197802SFlorian Wechsung   }
33078b879b41SFlorian Wechsung   if (success) *success = PETSC_TRUE;
330841525646SFlorian Wechsung   ierr = PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
3309240408d3SFlorian Wechsung #else
33105f441e9bSFlorian Wechsung   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
331141525646SFlorian Wechsung #endif
3312cb87ef4cSFlorian Wechsung   PetscFunctionReturn(0);
3313cb87ef4cSFlorian Wechsung }
3314