xref: /petsc/src/dm/impls/plex/plexpartition.c (revision d57f96a3fd9a23aa7b16a2dbaa80e66caf2c1685)
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"
16a8d69d7bSBarry Smith                                "  doi       = {https://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 
32bbbc8e51SStefano 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);
204580bdb30SBarry Smith       ierr = PetscArraycpy(edges, &graph[start], numEdges);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 
236bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
237bbbc8e51SStefano Zampini {
238bbbc8e51SStefano Zampini   Mat            conn, CSR;
239bbbc8e51SStefano Zampini   IS             fis, cis, cis_own;
240bbbc8e51SStefano Zampini   PetscSF        sfPoint;
241bbbc8e51SStefano Zampini   const PetscInt *rows, *cols, *ii, *jj;
242bbbc8e51SStefano Zampini   PetscInt       *idxs,*idxs2;
243bbbc8e51SStefano Zampini   PetscInt       dim, depth, floc, cloc, i, M, N, c, m, cStart, cEnd, fStart, fEnd;
244bbbc8e51SStefano Zampini   PetscMPIInt    rank;
245bbbc8e51SStefano Zampini   PetscBool      flg;
246bbbc8e51SStefano Zampini   PetscErrorCode ierr;
247bbbc8e51SStefano Zampini 
248bbbc8e51SStefano Zampini   PetscFunctionBegin;
249bbbc8e51SStefano Zampini   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
250bbbc8e51SStefano Zampini   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
251bbbc8e51SStefano Zampini   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
252bbbc8e51SStefano Zampini   if (dim != depth) {
253bbbc8e51SStefano Zampini     /* We do not handle the uninterpolated case here */
254bbbc8e51SStefano Zampini     ierr = DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);CHKERRQ(ierr);
255bbbc8e51SStefano Zampini     /* DMPlexCreateNeighborCSR does not make a numbering */
256bbbc8e51SStefano Zampini     if (globalNumbering) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);CHKERRQ(ierr);}
257bbbc8e51SStefano Zampini     /* Different behavior for empty graphs */
258bbbc8e51SStefano Zampini     if (!*numVertices) {
259bbbc8e51SStefano Zampini       ierr = PetscMalloc1(1, offsets);CHKERRQ(ierr);
260bbbc8e51SStefano Zampini       (*offsets)[0] = 0;
261bbbc8e51SStefano Zampini     }
262bbbc8e51SStefano Zampini     /* Broken in parallel */
263bbbc8e51SStefano Zampini     if (rank && *numVertices) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
264bbbc8e51SStefano Zampini     PetscFunctionReturn(0);
265bbbc8e51SStefano Zampini   }
266bbbc8e51SStefano Zampini   /* Interpolated and parallel case */
267bbbc8e51SStefano Zampini 
268bbbc8e51SStefano Zampini   /* numbering */
269bbbc8e51SStefano Zampini   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
270bbbc8e51SStefano Zampini   ierr = DMPlexGetHeightStratum(dm, height, &cStart, &cEnd);CHKERRQ(ierr);
271bbbc8e51SStefano Zampini   ierr = DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);CHKERRQ(ierr);
272bbbc8e51SStefano Zampini   ierr = DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, &N, sfPoint, &cis);CHKERRQ(ierr);
273bbbc8e51SStefano Zampini   ierr = DMPlexCreateNumbering_Internal(dm, fStart, fEnd, 0, &M, sfPoint, &fis);CHKERRQ(ierr);
274bbbc8e51SStefano Zampini   if (globalNumbering) {
275bbbc8e51SStefano Zampini     ierr = ISDuplicate(cis, globalNumbering);CHKERRQ(ierr);
276bbbc8e51SStefano Zampini   }
277bbbc8e51SStefano Zampini 
278bbbc8e51SStefano Zampini   /* get positive global ids and local sizes for facets and cells */
279bbbc8e51SStefano Zampini   ierr = ISGetLocalSize(fis, &m);CHKERRQ(ierr);
280bbbc8e51SStefano Zampini   ierr = ISGetIndices(fis, &rows);CHKERRQ(ierr);
281bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs);CHKERRQ(ierr);
282bbbc8e51SStefano Zampini   for (i = 0, floc = 0; i < m; i++) {
283bbbc8e51SStefano Zampini     const PetscInt p = rows[i];
284bbbc8e51SStefano Zampini 
285bbbc8e51SStefano Zampini     if (p < 0) {
286bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
287bbbc8e51SStefano Zampini     } else {
288bbbc8e51SStefano Zampini       idxs[i] = p;
289bbbc8e51SStefano Zampini       floc   += 1;
290bbbc8e51SStefano Zampini     }
291bbbc8e51SStefano Zampini   }
292bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(fis, &rows);CHKERRQ(ierr);
293bbbc8e51SStefano Zampini   ierr = ISDestroy(&fis);CHKERRQ(ierr);
294bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr);
295bbbc8e51SStefano Zampini 
296bbbc8e51SStefano Zampini   ierr = ISGetLocalSize(cis, &m);CHKERRQ(ierr);
297bbbc8e51SStefano Zampini   ierr = ISGetIndices(cis, &cols);CHKERRQ(ierr);
298bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs);CHKERRQ(ierr);
299bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs2);CHKERRQ(ierr);
300bbbc8e51SStefano Zampini   for (i = 0, cloc = 0; i < m; i++) {
301bbbc8e51SStefano Zampini     const PetscInt p = cols[i];
302bbbc8e51SStefano Zampini 
303bbbc8e51SStefano Zampini     if (p < 0) {
304bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
305bbbc8e51SStefano Zampini     } else {
306bbbc8e51SStefano Zampini       idxs[i]       = p;
307bbbc8e51SStefano Zampini       idxs2[cloc++] = p;
308bbbc8e51SStefano Zampini     }
309bbbc8e51SStefano Zampini   }
310bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(cis, &cols);CHKERRQ(ierr);
311bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis);CHKERRQ(ierr);
312bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr);
313bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own);CHKERRQ(ierr);
314bbbc8e51SStefano Zampini 
315bbbc8e51SStefano Zampini   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
316bbbc8e51SStefano Zampini   ierr = MatCreate(PetscObjectComm((PetscObject)dm), &conn);CHKERRQ(ierr);
317bbbc8e51SStefano Zampini   ierr = MatSetSizes(conn, floc, cloc, M, N);CHKERRQ(ierr);
318bbbc8e51SStefano Zampini   ierr = MatSetType(conn, MATMPIAIJ);CHKERRQ(ierr);
319bbbc8e51SStefano Zampini   ierr = DMPlexGetMaxSizes(dm, NULL, &m);CHKERRQ(ierr);
320bbbc8e51SStefano Zampini   ierr = MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL);CHKERRQ(ierr);
321bbbc8e51SStefano Zampini 
322bbbc8e51SStefano Zampini   /* Assemble matrix */
323bbbc8e51SStefano Zampini   ierr = ISGetIndices(fis, &rows);CHKERRQ(ierr);
324bbbc8e51SStefano Zampini   ierr = ISGetIndices(cis, &cols);CHKERRQ(ierr);
325bbbc8e51SStefano Zampini   for (c = cStart; c < cEnd; c++) {
326bbbc8e51SStefano Zampini     const PetscInt *cone;
327bbbc8e51SStefano Zampini     PetscInt        coneSize, row, col, f;
328bbbc8e51SStefano Zampini 
329bbbc8e51SStefano Zampini     col  = cols[c-cStart];
330bbbc8e51SStefano Zampini     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
331bbbc8e51SStefano Zampini     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
332bbbc8e51SStefano Zampini     for (f = 0; f < coneSize; f++) {
333bbbc8e51SStefano Zampini       const PetscScalar v = 1.0;
334bbbc8e51SStefano Zampini       const PetscInt *children;
335bbbc8e51SStefano Zampini       PetscInt        numChildren, ch;
336bbbc8e51SStefano Zampini 
337bbbc8e51SStefano Zampini       row  = rows[cone[f]-fStart];
338bbbc8e51SStefano Zampini       ierr = MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);CHKERRQ(ierr);
339bbbc8e51SStefano Zampini 
340bbbc8e51SStefano Zampini       /* non-conforming meshes */
341bbbc8e51SStefano Zampini       ierr = DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children);CHKERRQ(ierr);
342bbbc8e51SStefano Zampini       for (ch = 0; ch < numChildren; ch++) {
343bbbc8e51SStefano Zampini         const PetscInt child = children[ch];
344bbbc8e51SStefano Zampini 
345bbbc8e51SStefano Zampini         if (child < fStart || child >= fEnd) continue;
346bbbc8e51SStefano Zampini         row  = rows[child-fStart];
347bbbc8e51SStefano Zampini         ierr = MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);CHKERRQ(ierr);
348bbbc8e51SStefano Zampini       }
349bbbc8e51SStefano Zampini     }
350bbbc8e51SStefano Zampini   }
351bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(fis, &rows);CHKERRQ(ierr);
352bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(cis, &cols);CHKERRQ(ierr);
353bbbc8e51SStefano Zampini   ierr = ISDestroy(&fis);CHKERRQ(ierr);
354bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis);CHKERRQ(ierr);
355bbbc8e51SStefano Zampini   ierr = MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
356bbbc8e51SStefano Zampini   ierr = MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
357bbbc8e51SStefano Zampini 
358bbbc8e51SStefano Zampini   /* Get parallel CSR by doing conn^T * conn */
359bbbc8e51SStefano Zampini   ierr = MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR);CHKERRQ(ierr);
360bbbc8e51SStefano Zampini   ierr = MatDestroy(&conn);CHKERRQ(ierr);
361bbbc8e51SStefano Zampini 
362bbbc8e51SStefano Zampini   /* extract local part of the CSR */
363bbbc8e51SStefano Zampini   ierr = MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn);CHKERRQ(ierr);
364bbbc8e51SStefano Zampini   ierr = MatDestroy(&CSR);CHKERRQ(ierr);
365bbbc8e51SStefano Zampini   ierr = MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);CHKERRQ(ierr);
366bbbc8e51SStefano Zampini   if (!flg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
367bbbc8e51SStefano Zampini 
368bbbc8e51SStefano Zampini   /* get back requested output */
369bbbc8e51SStefano Zampini   if (numVertices) *numVertices = m;
370bbbc8e51SStefano Zampini   if (offsets) {
371bbbc8e51SStefano Zampini     ierr = PetscCalloc1(m+1, &idxs);CHKERRQ(ierr);
372bbbc8e51SStefano Zampini     for (i = 1; i < m+1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
373bbbc8e51SStefano Zampini     *offsets = idxs;
374bbbc8e51SStefano Zampini   }
375bbbc8e51SStefano Zampini   if (adjacency) {
376bbbc8e51SStefano Zampini     ierr = PetscMalloc1(ii[m] - m, &idxs);CHKERRQ(ierr);
377bbbc8e51SStefano Zampini     ierr = ISGetIndices(cis_own, &rows);CHKERRQ(ierr);
378bbbc8e51SStefano Zampini     for (i = 0, c = 0; i < m; i++) {
379bbbc8e51SStefano Zampini       PetscInt j, g = rows[i];
380bbbc8e51SStefano Zampini 
381bbbc8e51SStefano Zampini       for (j = ii[i]; j < ii[i+1]; j++) {
382bbbc8e51SStefano Zampini         if (jj[j] == g) continue; /* again, self-connectivity */
383bbbc8e51SStefano Zampini         idxs[c++] = jj[j];
384bbbc8e51SStefano Zampini       }
385bbbc8e51SStefano Zampini     }
386bbbc8e51SStefano Zampini     if (c != ii[m] - m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %D != %D",c,ii[m]-m);
387bbbc8e51SStefano Zampini     ierr = ISRestoreIndices(cis_own, &rows);CHKERRQ(ierr);
388bbbc8e51SStefano Zampini     *adjacency = idxs;
389bbbc8e51SStefano Zampini   }
390bbbc8e51SStefano Zampini 
391bbbc8e51SStefano Zampini   /* cleanup */
392bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis_own);CHKERRQ(ierr);
393bbbc8e51SStefano Zampini   ierr = MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);CHKERRQ(ierr);
394bbbc8e51SStefano Zampini   if (!flg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
395bbbc8e51SStefano Zampini   ierr = MatDestroy(&conn);CHKERRQ(ierr);
396bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
397bbbc8e51SStefano Zampini }
398bbbc8e51SStefano Zampini 
399bbbc8e51SStefano Zampini /*@C
400bbbc8e51SStefano Zampini   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
401bbbc8e51SStefano Zampini 
402bbbc8e51SStefano Zampini   Input Parameters:
403bbbc8e51SStefano Zampini + dm      - The mesh DM dm
404bbbc8e51SStefano Zampini - height  - Height of the strata from which to construct the graph
405bbbc8e51SStefano Zampini 
406bbbc8e51SStefano Zampini   Output Parameter:
407bbbc8e51SStefano Zampini + numVertices     - Number of vertices in the graph
408bbbc8e51SStefano Zampini . offsets         - Point offsets in the graph
409bbbc8e51SStefano Zampini . adjacency       - Point connectivity in the graph
410bbbc8e51SStefano 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.
411bbbc8e51SStefano Zampini 
412bbbc8e51SStefano Zampini   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
413bbbc8e51SStefano Zampini   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
414bbbc8e51SStefano Zampini 
415bbbc8e51SStefano Zampini   Level: developer
416bbbc8e51SStefano Zampini 
417bbbc8e51SStefano Zampini .seealso: PetscPartitionerGetType(), PetscPartitionerCreate(), DMSetAdjacency()
418bbbc8e51SStefano Zampini @*/
419bbbc8e51SStefano Zampini PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
420bbbc8e51SStefano Zampini {
421bbbc8e51SStefano Zampini   PetscErrorCode ierr;
422bbbc8e51SStefano Zampini   PetscBool      usemat = PETSC_FALSE;
423bbbc8e51SStefano Zampini 
424bbbc8e51SStefano Zampini   PetscFunctionBegin;
425bbbc8e51SStefano Zampini   ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_csr_via_mat", &usemat, NULL);CHKERRQ(ierr);
426bbbc8e51SStefano Zampini   if (usemat) {
427bbbc8e51SStefano Zampini     ierr = DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering);CHKERRQ(ierr);
428bbbc8e51SStefano Zampini   } else {
429bbbc8e51SStefano Zampini     ierr = DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering);CHKERRQ(ierr);
430bbbc8e51SStefano Zampini   }
431bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
432bbbc8e51SStefano Zampini }
433bbbc8e51SStefano Zampini 
434d5577e40SMatthew G. Knepley /*@C
435d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
436d5577e40SMatthew G. Knepley 
437d5577e40SMatthew G. Knepley   Collective
438d5577e40SMatthew G. Knepley 
439d5577e40SMatthew G. Knepley   Input Arguments:
440d5577e40SMatthew G. Knepley + dm - The DMPlex
441d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
442d5577e40SMatthew G. Knepley 
443d5577e40SMatthew G. Knepley   Output Arguments:
444d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
445d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
446d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
447d5577e40SMatthew G. Knepley 
448d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
449d5577e40SMatthew G. Knepley 
450d5577e40SMatthew G. Knepley   Level: advanced
451d5577e40SMatthew G. Knepley 
452d5577e40SMatthew G. Knepley .seealso: DMPlexCreate()
453d5577e40SMatthew G. Knepley @*/
45470034214SMatthew G. Knepley PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
45570034214SMatthew G. Knepley {
45670034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
45770034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
45870034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
45970034214SMatthew G. Knepley   PetscInt      *off, *adj;
46070034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
46170034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
46270034214SMatthew G. Knepley   PetscErrorCode ierr;
46370034214SMatthew G. Knepley 
46470034214SMatthew G. Knepley   PetscFunctionBegin;
46570034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
466c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
46770034214SMatthew G. Knepley   cellDim = dim - cellHeight;
46870034214SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
46970034214SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
47070034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
47170034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
47270034214SMatthew G. Knepley     if (offsets)   *offsets   = NULL;
47370034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
47470034214SMatthew G. Knepley     PetscFunctionReturn(0);
47570034214SMatthew G. Knepley   }
47670034214SMatthew G. Knepley   numCells  = cEnd - cStart;
47770034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
47870034214SMatthew G. Knepley   if (dim == depth) {
47970034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
48070034214SMatthew G. Knepley 
48170034214SMatthew G. Knepley     ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
48270034214SMatthew G. Knepley     /* Count neighboring cells */
48370034214SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr);
48470034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
48570034214SMatthew G. Knepley       const PetscInt *support;
48670034214SMatthew G. Knepley       PetscInt        supportSize;
48770034214SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
48870034214SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
48970034214SMatthew G. Knepley       if (supportSize == 2) {
4909ffc88e4SToby Isaac         PetscInt numChildren;
4919ffc88e4SToby Isaac 
4929ffc88e4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
4939ffc88e4SToby Isaac         if (!numChildren) {
49470034214SMatthew G. Knepley           ++off[support[0]-cStart+1];
49570034214SMatthew G. Knepley           ++off[support[1]-cStart+1];
49670034214SMatthew G. Knepley         }
49770034214SMatthew G. Knepley       }
4989ffc88e4SToby Isaac     }
49970034214SMatthew G. Knepley     /* Prefix sum */
50070034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
50170034214SMatthew G. Knepley     if (adjacency) {
50270034214SMatthew G. Knepley       PetscInt *tmp;
50370034214SMatthew G. Knepley 
50470034214SMatthew G. Knepley       ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
505854ce69bSBarry Smith       ierr = PetscMalloc1(numCells+1, &tmp);CHKERRQ(ierr);
506580bdb30SBarry Smith       ierr = PetscArraycpy(tmp, off, numCells+1);CHKERRQ(ierr);
50770034214SMatthew G. Knepley       /* Get neighboring cells */
50870034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
50970034214SMatthew G. Knepley         const PetscInt *support;
51070034214SMatthew G. Knepley         PetscInt        supportSize;
51170034214SMatthew G. Knepley         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
51270034214SMatthew G. Knepley         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
51370034214SMatthew G. Knepley         if (supportSize == 2) {
5149ffc88e4SToby Isaac           PetscInt numChildren;
5159ffc88e4SToby Isaac 
5169ffc88e4SToby Isaac           ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
5179ffc88e4SToby Isaac           if (!numChildren) {
51870034214SMatthew G. Knepley             adj[tmp[support[0]-cStart]++] = support[1];
51970034214SMatthew G. Knepley             adj[tmp[support[1]-cStart]++] = support[0];
52070034214SMatthew G. Knepley           }
52170034214SMatthew G. Knepley         }
5229ffc88e4SToby Isaac       }
52370034214SMatthew G. Knepley #if defined(PETSC_USE_DEBUG)
52470034214SMatthew 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);
52570034214SMatthew G. Knepley #endif
52670034214SMatthew G. Knepley       ierr = PetscFree(tmp);CHKERRQ(ierr);
52770034214SMatthew G. Knepley     }
52870034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
52970034214SMatthew G. Knepley     if (offsets)   *offsets   = off;
53070034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
53170034214SMatthew G. Knepley     PetscFunctionReturn(0);
53270034214SMatthew G. Knepley   }
53370034214SMatthew G. Knepley   /* Setup face recognition */
53470034214SMatthew G. Knepley   if (faceDepth == 1) {
53570034214SMatthew 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 */
53670034214SMatthew G. Knepley 
53770034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
53870034214SMatthew G. Knepley       PetscInt corners;
53970034214SMatthew G. Knepley 
54070034214SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
54170034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
54270034214SMatthew G. Knepley         PetscInt nFV;
54370034214SMatthew G. Knepley 
54470034214SMatthew G. Knepley         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
54570034214SMatthew G. Knepley         cornersSeen[corners] = 1;
54670034214SMatthew G. Knepley 
54770034214SMatthew G. Knepley         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
54870034214SMatthew G. Knepley 
54970034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
55070034214SMatthew G. Knepley       }
55170034214SMatthew G. Knepley     }
55270034214SMatthew G. Knepley   }
55370034214SMatthew G. Knepley   ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
55470034214SMatthew G. Knepley   /* Count neighboring cells */
55570034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
55670034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
55770034214SMatthew G. Knepley 
5588b0b4c70SToby Isaac     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
55970034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
56070034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
56170034214SMatthew G. Knepley       PetscInt        cellPair[2];
56270034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
56370034214SMatthew G. Knepley       PetscInt        meetSize = 0;
56470034214SMatthew G. Knepley       const PetscInt *meet    = NULL;
56570034214SMatthew G. Knepley 
56670034214SMatthew G. Knepley       cellPair[0] = cell; cellPair[1] = neighborCells[n];
56770034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
56870034214SMatthew G. Knepley       if (!found) {
56970034214SMatthew G. Knepley         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
57070034214SMatthew G. Knepley         if (meetSize) {
57170034214SMatthew G. Knepley           PetscInt f;
57270034214SMatthew G. Knepley 
57370034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
57470034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
57570034214SMatthew G. Knepley               found = PETSC_TRUE;
57670034214SMatthew G. Knepley               break;
57770034214SMatthew G. Knepley             }
57870034214SMatthew G. Knepley           }
57970034214SMatthew G. Knepley         }
58070034214SMatthew G. Knepley         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
58170034214SMatthew G. Knepley       }
58270034214SMatthew G. Knepley       if (found) ++off[cell-cStart+1];
58370034214SMatthew G. Knepley     }
58470034214SMatthew G. Knepley   }
58570034214SMatthew G. Knepley   /* Prefix sum */
58670034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
58770034214SMatthew G. Knepley 
58870034214SMatthew G. Knepley   if (adjacency) {
58970034214SMatthew G. Knepley     ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
59070034214SMatthew G. Knepley     /* Get neighboring cells */
59170034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
59270034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
59370034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
59470034214SMatthew G. Knepley 
5958b0b4c70SToby Isaac       ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
59670034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
59770034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
59870034214SMatthew G. Knepley         PetscInt        cellPair[2];
59970034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
60070034214SMatthew G. Knepley         PetscInt        meetSize = 0;
60170034214SMatthew G. Knepley         const PetscInt *meet    = NULL;
60270034214SMatthew G. Knepley 
60370034214SMatthew G. Knepley         cellPair[0] = cell; cellPair[1] = neighborCells[n];
60470034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
60570034214SMatthew G. Knepley         if (!found) {
60670034214SMatthew G. Knepley           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
60770034214SMatthew G. Knepley           if (meetSize) {
60870034214SMatthew G. Knepley             PetscInt f;
60970034214SMatthew G. Knepley 
61070034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
61170034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
61270034214SMatthew G. Knepley                 found = PETSC_TRUE;
61370034214SMatthew G. Knepley                 break;
61470034214SMatthew G. Knepley               }
61570034214SMatthew G. Knepley             }
61670034214SMatthew G. Knepley           }
61770034214SMatthew G. Knepley           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
61870034214SMatthew G. Knepley         }
61970034214SMatthew G. Knepley         if (found) {
62070034214SMatthew G. Knepley           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
62170034214SMatthew G. Knepley           ++cellOffset;
62270034214SMatthew G. Knepley         }
62370034214SMatthew G. Knepley       }
62470034214SMatthew G. Knepley     }
62570034214SMatthew G. Knepley   }
62670034214SMatthew G. Knepley   ierr = PetscFree(neighborCells);CHKERRQ(ierr);
62770034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
62870034214SMatthew G. Knepley   if (offsets)   *offsets   = off;
62970034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
63070034214SMatthew G. Knepley   PetscFunctionReturn(0);
63170034214SMatthew G. Knepley }
63270034214SMatthew G. Knepley 
63377623264SMatthew G. Knepley /*@C
63477623264SMatthew G. Knepley   PetscPartitionerRegister - Adds a new PetscPartitioner implementation
63577623264SMatthew G. Knepley 
63677623264SMatthew G. Knepley   Not Collective
63777623264SMatthew G. Knepley 
63877623264SMatthew G. Knepley   Input Parameters:
63977623264SMatthew G. Knepley + name        - The name of a new user-defined creation routine
64077623264SMatthew G. Knepley - create_func - The creation routine itself
64177623264SMatthew G. Knepley 
64277623264SMatthew G. Knepley   Notes:
64377623264SMatthew G. Knepley   PetscPartitionerRegister() may be called multiple times to add several user-defined PetscPartitioners
64477623264SMatthew G. Knepley 
64577623264SMatthew G. Knepley   Sample usage:
64677623264SMatthew G. Knepley .vb
64777623264SMatthew G. Knepley     PetscPartitionerRegister("my_part", MyPetscPartitionerCreate);
64877623264SMatthew G. Knepley .ve
64977623264SMatthew G. Knepley 
65077623264SMatthew G. Knepley   Then, your PetscPartitioner type can be chosen with the procedural interface via
65177623264SMatthew G. Knepley .vb
65277623264SMatthew G. Knepley     PetscPartitionerCreate(MPI_Comm, PetscPartitioner *);
65377623264SMatthew G. Knepley     PetscPartitionerSetType(PetscPartitioner, "my_part");
65477623264SMatthew G. Knepley .ve
65577623264SMatthew G. Knepley    or at runtime via the option
65677623264SMatthew G. Knepley .vb
65777623264SMatthew G. Knepley     -petscpartitioner_type my_part
65877623264SMatthew G. Knepley .ve
65977623264SMatthew G. Knepley 
66077623264SMatthew G. Knepley   Level: advanced
66177623264SMatthew G. Knepley 
66277623264SMatthew G. Knepley .seealso: PetscPartitionerRegisterAll(), PetscPartitionerRegisterDestroy()
66377623264SMatthew G. Knepley 
66477623264SMatthew G. Knepley @*/
66577623264SMatthew G. Knepley PetscErrorCode PetscPartitionerRegister(const char sname[], PetscErrorCode (*function)(PetscPartitioner))
66677623264SMatthew G. Knepley {
66777623264SMatthew G. Knepley   PetscErrorCode ierr;
66877623264SMatthew G. Knepley 
66977623264SMatthew G. Knepley   PetscFunctionBegin;
67077623264SMatthew G. Knepley   ierr = PetscFunctionListAdd(&PetscPartitionerList, sname, function);CHKERRQ(ierr);
67177623264SMatthew G. Knepley   PetscFunctionReturn(0);
67277623264SMatthew G. Knepley }
67377623264SMatthew G. Knepley 
67477623264SMatthew G. Knepley /*@C
67577623264SMatthew G. Knepley   PetscPartitionerSetType - Builds a particular PetscPartitioner
67677623264SMatthew G. Knepley 
677d083f849SBarry Smith   Collective on part
67877623264SMatthew G. Knepley 
67977623264SMatthew G. Knepley   Input Parameters:
68077623264SMatthew G. Knepley + part - The PetscPartitioner object
68177623264SMatthew G. Knepley - name - The kind of partitioner
68277623264SMatthew G. Knepley 
68377623264SMatthew G. Knepley   Options Database Key:
68477623264SMatthew G. Knepley . -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types
68577623264SMatthew G. Knepley 
68677623264SMatthew G. Knepley   Level: intermediate
68777623264SMatthew G. Knepley 
68877623264SMatthew G. Knepley .seealso: PetscPartitionerGetType(), PetscPartitionerCreate()
68977623264SMatthew G. Knepley @*/
69077623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name)
69177623264SMatthew G. Knepley {
69277623264SMatthew G. Knepley   PetscErrorCode (*r)(PetscPartitioner);
69377623264SMatthew G. Knepley   PetscBool      match;
69477623264SMatthew G. Knepley   PetscErrorCode ierr;
69577623264SMatthew G. Knepley 
69677623264SMatthew G. Knepley   PetscFunctionBegin;
69777623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
69877623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) part, name, &match);CHKERRQ(ierr);
69977623264SMatthew G. Knepley   if (match) PetscFunctionReturn(0);
70077623264SMatthew G. Knepley 
7010f51fdf8SToby Isaac   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
70277623264SMatthew G. Knepley   ierr = PetscFunctionListFind(PetscPartitionerList, name, &r);CHKERRQ(ierr);
70377623264SMatthew G. Knepley   if (!r) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name);
70477623264SMatthew G. Knepley 
70577623264SMatthew G. Knepley   if (part->ops->destroy) {
70677623264SMatthew G. Knepley     ierr = (*part->ops->destroy)(part);CHKERRQ(ierr);
70777623264SMatthew G. Knepley   }
708074d466cSStefano Zampini   part->noGraph = PETSC_FALSE;
709*d57f96a3SLisandro Dalcin   ierr = PetscMemzero(part->ops, sizeof(*part->ops));CHKERRQ(ierr);
71077623264SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) part, name);CHKERRQ(ierr);
711*d57f96a3SLisandro Dalcin   ierr = (*r)(part);CHKERRQ(ierr);
71277623264SMatthew G. Knepley   PetscFunctionReturn(0);
71377623264SMatthew G. Knepley }
71477623264SMatthew G. Knepley 
71577623264SMatthew G. Knepley /*@C
71677623264SMatthew G. Knepley   PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object.
71777623264SMatthew G. Knepley 
71877623264SMatthew G. Knepley   Not Collective
71977623264SMatthew G. Knepley 
72077623264SMatthew G. Knepley   Input Parameter:
72177623264SMatthew G. Knepley . part - The PetscPartitioner
72277623264SMatthew G. Knepley 
72377623264SMatthew G. Knepley   Output Parameter:
72477623264SMatthew G. Knepley . name - The PetscPartitioner type name
72577623264SMatthew G. Knepley 
72677623264SMatthew G. Knepley   Level: intermediate
72777623264SMatthew G. Knepley 
72877623264SMatthew G. Knepley .seealso: PetscPartitionerSetType(), PetscPartitionerCreate()
72977623264SMatthew G. Knepley @*/
73077623264SMatthew G. Knepley PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name)
73177623264SMatthew G. Knepley {
73277623264SMatthew G. Knepley   PetscErrorCode ierr;
73377623264SMatthew G. Knepley 
73477623264SMatthew G. Knepley   PetscFunctionBegin;
73577623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
73677623264SMatthew G. Knepley   PetscValidPointer(name, 2);
7370f51fdf8SToby Isaac   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
73877623264SMatthew G. Knepley   *name = ((PetscObject) part)->type_name;
73977623264SMatthew G. Knepley   PetscFunctionReturn(0);
74077623264SMatthew G. Knepley }
74177623264SMatthew G. Knepley 
74277623264SMatthew G. Knepley /*@C
74377623264SMatthew G. Knepley   PetscPartitionerView - Views a PetscPartitioner
74477623264SMatthew G. Knepley 
745d083f849SBarry Smith   Collective on part
74677623264SMatthew G. Knepley 
74777623264SMatthew G. Knepley   Input Parameter:
74877623264SMatthew G. Knepley + part - the PetscPartitioner object to view
74977623264SMatthew G. Knepley - v    - the viewer
75077623264SMatthew G. Knepley 
75177623264SMatthew G. Knepley   Level: developer
75277623264SMatthew G. Knepley 
75377623264SMatthew G. Knepley .seealso: PetscPartitionerDestroy()
75477623264SMatthew G. Knepley @*/
75577623264SMatthew G. Knepley PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v)
75677623264SMatthew G. Knepley {
757ffc59708SMatthew G. Knepley   PetscMPIInt    size;
7582abdaa70SMatthew G. Knepley   PetscBool      isascii;
75977623264SMatthew G. Knepley   PetscErrorCode ierr;
76077623264SMatthew G. Knepley 
76177623264SMatthew G. Knepley   PetscFunctionBegin;
76277623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
76377623264SMatthew G. Knepley   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v);CHKERRQ(ierr);}
7642abdaa70SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
7652abdaa70SMatthew G. Knepley   if (isascii) {
7662abdaa70SMatthew G. Knepley     ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
767ffc59708SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "Graph Partitioner: %d MPI Process%s\n", size, size > 1 ? "es" : "");CHKERRQ(ierr);
7682abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "  type: %s\n", part->hdr.type_name);CHKERRQ(ierr);
7692abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr);
7702abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "edge cut: %D\n", part->edgeCut);CHKERRQ(ierr);
7712abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "balance:  %.2g\n", part->balance);CHKERRQ(ierr);
7722abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr);
7732abdaa70SMatthew G. Knepley   }
77477623264SMatthew G. Knepley   if (part->ops->view) {ierr = (*part->ops->view)(part, v);CHKERRQ(ierr);}
77577623264SMatthew G. Knepley   PetscFunctionReturn(0);
77677623264SMatthew G. Knepley }
77777623264SMatthew G. Knepley 
778a0058e54SToby Isaac static PetscErrorCode PetscPartitionerGetDefaultType(const char *currentType, const char **defaultType)
779a0058e54SToby Isaac {
780a0058e54SToby Isaac   PetscFunctionBegin;
781a0058e54SToby Isaac   if (!currentType) {
78256bf5a81SLisandro Dalcin #if defined(PETSC_HAVE_PARMETIS)
783a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERPARMETIS;
784137cd93aSLisandro Dalcin #elif defined(PETSC_HAVE_PTSCOTCH)
785137cd93aSLisandro Dalcin     *defaultType = PETSCPARTITIONERPTSCOTCH;
78656bf5a81SLisandro Dalcin #elif defined(PETSC_HAVE_CHACO)
78756bf5a81SLisandro Dalcin     *defaultType = PETSCPARTITIONERCHACO;
788a0058e54SToby Isaac #else
789a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERSIMPLE;
790a0058e54SToby Isaac #endif
791a0058e54SToby Isaac   } else {
792a0058e54SToby Isaac     *defaultType = currentType;
793a0058e54SToby Isaac   }
794a0058e54SToby Isaac   PetscFunctionReturn(0);
795a0058e54SToby Isaac }
796a0058e54SToby Isaac 
79777623264SMatthew G. Knepley /*@
79877623264SMatthew G. Knepley   PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database
79977623264SMatthew G. Knepley 
800d083f849SBarry Smith   Collective on part
80177623264SMatthew G. Knepley 
80277623264SMatthew G. Knepley   Input Parameter:
80377623264SMatthew G. Knepley . part - the PetscPartitioner object to set options for
80477623264SMatthew G. Knepley 
80577623264SMatthew G. Knepley   Level: developer
80677623264SMatthew G. Knepley 
80777623264SMatthew G. Knepley .seealso: PetscPartitionerView()
80877623264SMatthew G. Knepley @*/
80977623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part)
81077623264SMatthew G. Knepley {
8116bb9daa8SLisandro Dalcin   const char    *defaultType;
8126bb9daa8SLisandro Dalcin   char           name[256];
8136bb9daa8SLisandro Dalcin   PetscBool      flg;
81477623264SMatthew G. Knepley   PetscErrorCode ierr;
81577623264SMatthew G. Knepley 
81677623264SMatthew G. Knepley   PetscFunctionBegin;
81777623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
8186bb9daa8SLisandro Dalcin   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
8196bb9daa8SLisandro Dalcin   ierr = PetscPartitionerGetDefaultType(((PetscObject) part)->type_name,&defaultType);CHKERRQ(ierr);
82077623264SMatthew G. Knepley   ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr);
8216bb9daa8SLisandro Dalcin   ierr = PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, defaultType, name, sizeof(name), &flg);CHKERRQ(ierr);
8226bb9daa8SLisandro Dalcin   if (flg) {
8236bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, name);CHKERRQ(ierr);
8246bb9daa8SLisandro Dalcin   } else if (!((PetscObject) part)->type_name) {
8256bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, defaultType);CHKERRQ(ierr);
8266bb9daa8SLisandro Dalcin   }
8276bb9daa8SLisandro Dalcin   if (part->ops->setfromoptions) {
8286bb9daa8SLisandro Dalcin     ierr = (*part->ops->setfromoptions)(PetscOptionsObject,part);CHKERRQ(ierr);
8296bb9daa8SLisandro Dalcin   }
830783e1fb6SStefano Zampini   ierr = PetscViewerDestroy(&part->viewerGraph);CHKERRQ(ierr);
8310358368aSMatthew G. Knepley   ierr = PetscOptionsGetViewer(((PetscObject) part)->comm, ((PetscObject) part)->options, ((PetscObject) part)->prefix, "-petscpartitioner_view_graph", &part->viewerGraph, &part->formatGraph, &part->viewGraph);CHKERRQ(ierr);
83277623264SMatthew G. Knepley   /* process any options handlers added with PetscObjectAddOptionsHandler() */
8330633abcbSJed Brown   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) part);CHKERRQ(ierr);
83477623264SMatthew G. Knepley   ierr = PetscOptionsEnd();CHKERRQ(ierr);
83577623264SMatthew G. Knepley   PetscFunctionReturn(0);
83677623264SMatthew G. Knepley }
83777623264SMatthew G. Knepley 
83877623264SMatthew G. Knepley /*@C
83977623264SMatthew G. Knepley   PetscPartitionerSetUp - Construct data structures for the PetscPartitioner
84077623264SMatthew G. Knepley 
841d083f849SBarry Smith   Collective on part
84277623264SMatthew G. Knepley 
84377623264SMatthew G. Knepley   Input Parameter:
84477623264SMatthew G. Knepley . part - the PetscPartitioner object to setup
84577623264SMatthew G. Knepley 
84677623264SMatthew G. Knepley   Level: developer
84777623264SMatthew G. Knepley 
84877623264SMatthew G. Knepley .seealso: PetscPartitionerView(), PetscPartitionerDestroy()
84977623264SMatthew G. Knepley @*/
85077623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part)
85177623264SMatthew G. Knepley {
85277623264SMatthew G. Knepley   PetscErrorCode ierr;
85377623264SMatthew G. Knepley 
85477623264SMatthew G. Knepley   PetscFunctionBegin;
85577623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
85677623264SMatthew G. Knepley   if (part->ops->setup) {ierr = (*part->ops->setup)(part);CHKERRQ(ierr);}
85777623264SMatthew G. Knepley   PetscFunctionReturn(0);
85877623264SMatthew G. Knepley }
85977623264SMatthew G. Knepley 
86077623264SMatthew G. Knepley /*@
86177623264SMatthew G. Knepley   PetscPartitionerDestroy - Destroys a PetscPartitioner object
86277623264SMatthew G. Knepley 
863d083f849SBarry Smith   Collective on part
86477623264SMatthew G. Knepley 
86577623264SMatthew G. Knepley   Input Parameter:
86677623264SMatthew G. Knepley . part - the PetscPartitioner object to destroy
86777623264SMatthew G. Knepley 
86877623264SMatthew G. Knepley   Level: developer
86977623264SMatthew G. Knepley 
87077623264SMatthew G. Knepley .seealso: PetscPartitionerView()
87177623264SMatthew G. Knepley @*/
87277623264SMatthew G. Knepley PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part)
87377623264SMatthew G. Knepley {
87477623264SMatthew G. Knepley   PetscErrorCode ierr;
87577623264SMatthew G. Knepley 
87677623264SMatthew G. Knepley   PetscFunctionBegin;
87777623264SMatthew G. Knepley   if (!*part) PetscFunctionReturn(0);
87877623264SMatthew G. Knepley   PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1);
87977623264SMatthew G. Knepley 
88077623264SMatthew G. Knepley   if (--((PetscObject)(*part))->refct > 0) {*part = 0; PetscFunctionReturn(0);}
88177623264SMatthew G. Knepley   ((PetscObject) (*part))->refct = 0;
88277623264SMatthew G. Knepley 
8830358368aSMatthew G. Knepley   ierr = PetscViewerDestroy(&(*part)->viewerGraph);CHKERRQ(ierr);
88477623264SMatthew G. Knepley   if ((*part)->ops->destroy) {ierr = (*(*part)->ops->destroy)(*part);CHKERRQ(ierr);}
88577623264SMatthew G. Knepley   ierr = PetscHeaderDestroy(part);CHKERRQ(ierr);
88677623264SMatthew G. Knepley   PetscFunctionReturn(0);
88777623264SMatthew G. Knepley }
88877623264SMatthew G. Knepley 
88977623264SMatthew G. Knepley /*@
89077623264SMatthew G. Knepley   PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType().
89177623264SMatthew G. Knepley 
892d083f849SBarry Smith   Collective
89377623264SMatthew G. Knepley 
89477623264SMatthew G. Knepley   Input Parameter:
89577623264SMatthew G. Knepley . comm - The communicator for the PetscPartitioner object
89677623264SMatthew G. Knepley 
89777623264SMatthew G. Knepley   Output Parameter:
89877623264SMatthew G. Knepley . part - The PetscPartitioner object
89977623264SMatthew G. Knepley 
90077623264SMatthew G. Knepley   Level: beginner
90177623264SMatthew G. Knepley 
902dae52e14SToby Isaac .seealso: PetscPartitionerSetType(), PETSCPARTITIONERCHACO, PETSCPARTITIONERPARMETIS, PETSCPARTITIONERSHELL, PETSCPARTITIONERSIMPLE, PETSCPARTITIONERGATHER
90377623264SMatthew G. Knepley @*/
90477623264SMatthew G. Knepley PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
90577623264SMatthew G. Knepley {
90677623264SMatthew G. Knepley   PetscPartitioner p;
907a0058e54SToby Isaac   const char       *partitionerType = NULL;
90877623264SMatthew G. Knepley   PetscErrorCode   ierr;
90977623264SMatthew G. Knepley 
91077623264SMatthew G. Knepley   PetscFunctionBegin;
91177623264SMatthew G. Knepley   PetscValidPointer(part, 2);
91277623264SMatthew G. Knepley   *part = NULL;
91383cde681SMatthew G. Knepley   ierr = DMInitializePackage();CHKERRQ(ierr);
91477623264SMatthew G. Knepley 
91573107ff1SLisandro Dalcin   ierr = PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView);CHKERRQ(ierr);
916a0058e54SToby Isaac   ierr = PetscPartitionerGetDefaultType(NULL,&partitionerType);CHKERRQ(ierr);
917a0058e54SToby Isaac   ierr = PetscPartitionerSetType(p,partitionerType);CHKERRQ(ierr);
91877623264SMatthew G. Knepley 
91972379da4SMatthew G. Knepley   p->edgeCut = 0;
92072379da4SMatthew G. Knepley   p->balance = 0.0;
92172379da4SMatthew G. Knepley 
92277623264SMatthew G. Knepley   *part = p;
92377623264SMatthew G. Knepley   PetscFunctionReturn(0);
92477623264SMatthew G. Knepley }
92577623264SMatthew G. Knepley 
92677623264SMatthew G. Knepley /*@
92777623264SMatthew G. Knepley   PetscPartitionerPartition - Create a non-overlapping partition of the cells in the mesh
92877623264SMatthew G. Knepley 
929d083f849SBarry Smith   Collective on dm
93077623264SMatthew G. Knepley 
93177623264SMatthew G. Knepley   Input Parameters:
93277623264SMatthew G. Knepley + part    - The PetscPartitioner
933f8987ae8SMichael Lange - dm      - The mesh DM
93477623264SMatthew G. Knepley 
93577623264SMatthew G. Knepley   Output Parameters:
93677623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
937f8987ae8SMichael Lange - partition       - The list of points by partition
93877623264SMatthew G. Knepley 
9390358368aSMatthew G. Knepley   Options Database:
9400358368aSMatthew G. Knepley . -petscpartitioner_view_graph - View the graph we are partitioning
9410358368aSMatthew G. Knepley 
94277623264SMatthew G. Knepley   Note: Instead of cells, points at a given height can be partitioned by calling PetscPartitionerSetPointHeight()
94377623264SMatthew G. Knepley 
94477623264SMatthew G. Knepley   Level: developer
94577623264SMatthew G. Knepley 
94677623264SMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerSetPointHeight(), PetscPartitionerCreate()
9474b15ede2SMatthew G. Knepley @*/
948f8987ae8SMichael Lange PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, DM dm, PetscSection partSection, IS *partition)
94977623264SMatthew G. Knepley {
95077623264SMatthew G. Knepley   PetscMPIInt    size;
95177623264SMatthew G. Knepley   PetscErrorCode ierr;
95277623264SMatthew G. Knepley 
95377623264SMatthew G. Knepley   PetscFunctionBegin;
95477623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
95577623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
95677623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
95777623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
95877623264SMatthew G. Knepley   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
95977623264SMatthew G. Knepley   if (size == 1) {
96077623264SMatthew G. Knepley     PetscInt *points;
96177623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
96277623264SMatthew G. Knepley 
96377623264SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
96477623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr);
96577623264SMatthew G. Knepley     ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr);
96677623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
96777623264SMatthew G. Knepley     ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr);
96877623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
96977623264SMatthew G. Knepley     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
97077623264SMatthew G. Knepley     PetscFunctionReturn(0);
97177623264SMatthew G. Knepley   }
97277623264SMatthew G. Knepley   if (part->height == 0) {
973074d466cSStefano Zampini     PetscInt numVertices = 0;
97477623264SMatthew G. Knepley     PetscInt *start     = NULL;
97577623264SMatthew G. Knepley     PetscInt *adjacency = NULL;
9763fa7752dSToby Isaac     IS       globalNumbering;
97777623264SMatthew G. Knepley 
978074d466cSStefano Zampini     if (!part->noGraph || part->viewGraph) {
979074d466cSStefano Zampini       ierr = DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering);CHKERRQ(ierr);
98013911537SStefano Zampini     } else { /* only compute the number of owned local vertices */
981074d466cSStefano Zampini       const PetscInt *idxs;
982074d466cSStefano Zampini       PetscInt       p, pStart, pEnd;
983074d466cSStefano Zampini 
984074d466cSStefano Zampini       ierr = DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd);CHKERRQ(ierr);
985074d466cSStefano Zampini       ierr = DMPlexCreateNumbering_Internal(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering);CHKERRQ(ierr);
986074d466cSStefano Zampini       ierr = ISGetIndices(globalNumbering, &idxs);CHKERRQ(ierr);
987074d466cSStefano Zampini       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
988074d466cSStefano Zampini       ierr = ISRestoreIndices(globalNumbering, &idxs);CHKERRQ(ierr);
989074d466cSStefano Zampini     }
9900358368aSMatthew G. Knepley     if (part->viewGraph) {
9910358368aSMatthew G. Knepley       PetscViewer viewer = part->viewerGraph;
9920358368aSMatthew G. Knepley       PetscBool   isascii;
9930358368aSMatthew G. Knepley       PetscInt    v, i;
9940358368aSMatthew G. Knepley       PetscMPIInt rank;
9950358368aSMatthew G. Knepley 
9960358368aSMatthew G. Knepley       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) viewer), &rank);CHKERRQ(ierr);
9970358368aSMatthew G. Knepley       ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
9980358368aSMatthew G. Knepley       if (isascii) {
9990358368aSMatthew G. Knepley         ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
10000358368aSMatthew G. Knepley         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]Nv: %D\n", rank, numVertices);CHKERRQ(ierr);
10010358368aSMatthew G. Knepley         for (v = 0; v < numVertices; ++v) {
10020358368aSMatthew G. Knepley           const PetscInt s = start[v];
10030358368aSMatthew G. Knepley           const PetscInt e = start[v+1];
10040358368aSMatthew G. Knepley 
10050358368aSMatthew G. Knepley           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]  ", rank);CHKERRQ(ierr);
10060358368aSMatthew G. Knepley           for (i = s; i < e; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%D ", adjacency[i]);CHKERRQ(ierr);}
10070358368aSMatthew G. Knepley           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D-%D)\n", s, e);CHKERRQ(ierr);
10080358368aSMatthew G. Knepley         }
10090358368aSMatthew G. Knepley         ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
10100358368aSMatthew G. Knepley         ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
10110358368aSMatthew G. Knepley       }
10120358368aSMatthew G. Knepley     }
1013bbbc8e51SStefano Zampini     if (!part->ops->partition) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_WRONGSTATE, "PetscPartitioner has no partitioning method");
101477623264SMatthew G. Knepley     ierr = (*part->ops->partition)(part, dm, size, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
101577623264SMatthew G. Knepley     ierr = PetscFree(start);CHKERRQ(ierr);
101677623264SMatthew G. Knepley     ierr = PetscFree(adjacency);CHKERRQ(ierr);
10173fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
10183fa7752dSToby Isaac       const PetscInt *globalNum;
10193fa7752dSToby Isaac       const PetscInt *partIdx;
10203fa7752dSToby Isaac       PetscInt       *map, cStart, cEnd;
10213fa7752dSToby Isaac       PetscInt       *adjusted, i, localSize, offset;
10223fa7752dSToby Isaac       IS             newPartition;
10233fa7752dSToby Isaac 
10243fa7752dSToby Isaac       ierr = ISGetLocalSize(*partition,&localSize);CHKERRQ(ierr);
10253fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&adjusted);CHKERRQ(ierr);
10263fa7752dSToby Isaac       ierr = ISGetIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
10273fa7752dSToby Isaac       ierr = ISGetIndices(*partition,&partIdx);CHKERRQ(ierr);
10283fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&map);CHKERRQ(ierr);
10293fa7752dSToby Isaac       ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
10303fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
10313fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
10323fa7752dSToby Isaac       }
10333fa7752dSToby Isaac       for (i = 0; i < localSize; i++) {
10343fa7752dSToby Isaac         adjusted[i] = map[partIdx[i]];
10353fa7752dSToby Isaac       }
10363fa7752dSToby Isaac       ierr = PetscFree(map);CHKERRQ(ierr);
10373fa7752dSToby Isaac       ierr = ISRestoreIndices(*partition,&partIdx);CHKERRQ(ierr);
10383fa7752dSToby Isaac       ierr = ISRestoreIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
10393fa7752dSToby Isaac       ierr = ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition);CHKERRQ(ierr);
10403fa7752dSToby Isaac       ierr = ISDestroy(&globalNumbering);CHKERRQ(ierr);
10413fa7752dSToby Isaac       ierr = ISDestroy(partition);CHKERRQ(ierr);
10423fa7752dSToby Isaac       *partition = newPartition;
10433fa7752dSToby Isaac     }
104477623264SMatthew G. Knepley   } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height);
10452abdaa70SMatthew G. Knepley   ierr = PetscPartitionerViewFromOptions(part, NULL, "-petscpartitioner_view");CHKERRQ(ierr);
104677623264SMatthew G. Knepley   PetscFunctionReturn(0);
104777623264SMatthew G. Knepley }
104877623264SMatthew G. Knepley 
1049d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Shell(PetscPartitioner part)
105077623264SMatthew G. Knepley {
105177623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
105277623264SMatthew G. Knepley   PetscErrorCode          ierr;
105377623264SMatthew G. Knepley 
105477623264SMatthew G. Knepley   PetscFunctionBegin;
105577623264SMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
105677623264SMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
105777623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
105877623264SMatthew G. Knepley   PetscFunctionReturn(0);
105977623264SMatthew G. Knepley }
106077623264SMatthew G. Knepley 
1061d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell_Ascii(PetscPartitioner part, PetscViewer viewer)
106277623264SMatthew G. Knepley {
1063077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
106477623264SMatthew G. Knepley   PetscErrorCode          ierr;
106577623264SMatthew G. Knepley 
106677623264SMatthew G. Knepley   PetscFunctionBegin;
1067077101c0SMatthew G. Knepley   if (p->random) {
1068077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1069077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(viewer, "using random partition\n");CHKERRQ(ierr);
1070077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1071077101c0SMatthew G. Knepley   }
107277623264SMatthew G. Knepley   PetscFunctionReturn(0);
107377623264SMatthew G. Knepley }
107477623264SMatthew G. Knepley 
1075d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell(PetscPartitioner part, PetscViewer viewer)
107677623264SMatthew G. Knepley {
107777623264SMatthew G. Knepley   PetscBool      iascii;
107877623264SMatthew G. Knepley   PetscErrorCode ierr;
107977623264SMatthew G. Knepley 
108077623264SMatthew G. Knepley   PetscFunctionBegin;
108177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
108277623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
108377623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
108477623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Shell_Ascii(part, viewer);CHKERRQ(ierr);}
108577623264SMatthew G. Knepley   PetscFunctionReturn(0);
108677623264SMatthew G. Knepley }
108777623264SMatthew G. Knepley 
1088d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerSetFromOptions_Shell(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
1089077101c0SMatthew G. Knepley {
1090077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1091077101c0SMatthew G. Knepley   PetscErrorCode          ierr;
1092077101c0SMatthew G. Knepley 
1093077101c0SMatthew G. Knepley   PetscFunctionBegin;
1094077101c0SMatthew G. Knepley   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner Shell Options");CHKERRQ(ierr);
1095077101c0SMatthew G. Knepley   ierr = PetscOptionsBool("-petscpartitioner_shell_random", "Use a random partition", "PetscPartitionerView", PETSC_FALSE, &p->random, NULL);CHKERRQ(ierr);
1096077101c0SMatthew G. Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1097077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1098077101c0SMatthew G. Knepley }
1099077101c0SMatthew G. Knepley 
1100d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Shell(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
110177623264SMatthew G. Knepley {
110277623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
110377623264SMatthew G. Knepley   PetscInt                np;
110477623264SMatthew G. Knepley   PetscErrorCode          ierr;
110577623264SMatthew G. Knepley 
110677623264SMatthew G. Knepley   PetscFunctionBegin;
1107077101c0SMatthew G. Knepley   if (p->random) {
1108077101c0SMatthew G. Knepley     PetscRandom r;
1109aa1d5631SMatthew G. Knepley     PetscInt   *sizes, *points, v, p;
1110aa1d5631SMatthew G. Knepley     PetscMPIInt rank;
1111077101c0SMatthew G. Knepley 
1112aa1d5631SMatthew G. Knepley     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
1113077101c0SMatthew G. Knepley     ierr = PetscRandomCreate(PETSC_COMM_SELF, &r);CHKERRQ(ierr);
1114c717d290SMatthew G. Knepley     ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) nparts);CHKERRQ(ierr);
1115077101c0SMatthew G. Knepley     ierr = PetscRandomSetFromOptions(r);CHKERRQ(ierr);
1116077101c0SMatthew G. Knepley     ierr = PetscCalloc2(nparts, &sizes, numVertices, &points);CHKERRQ(ierr);
1117aa1d5631SMatthew G. Knepley     for (v = 0; v < numVertices; ++v) {points[v] = v;}
1118ac9a96f1SMichael Lange     for (p = 0; p < nparts; ++p) {sizes[p] = numVertices/nparts + (PetscInt) (p < numVertices % nparts);}
1119aa1d5631SMatthew G. Knepley     for (v = numVertices-1; v > 0; --v) {
1120077101c0SMatthew G. Knepley       PetscReal val;
1121aa1d5631SMatthew G. Knepley       PetscInt  w, tmp;
1122077101c0SMatthew G. Knepley 
1123aa1d5631SMatthew G. Knepley       ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) (v+1));CHKERRQ(ierr);
1124077101c0SMatthew G. Knepley       ierr = PetscRandomGetValueReal(r, &val);CHKERRQ(ierr);
1125aa1d5631SMatthew G. Knepley       w    = PetscFloorReal(val);
1126aa1d5631SMatthew G. Knepley       tmp       = points[v];
1127aa1d5631SMatthew G. Knepley       points[v] = points[w];
1128aa1d5631SMatthew G. Knepley       points[w] = tmp;
1129077101c0SMatthew G. Knepley     }
1130077101c0SMatthew G. Knepley     ierr = PetscRandomDestroy(&r);CHKERRQ(ierr);
1131077101c0SMatthew G. Knepley     ierr = PetscPartitionerShellSetPartition(part, nparts, sizes, points);CHKERRQ(ierr);
1132077101c0SMatthew G. Knepley     ierr = PetscFree2(sizes, points);CHKERRQ(ierr);
1133077101c0SMatthew G. Knepley   }
1134c717d290SMatthew G. Knepley   if (!p->section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Shell partitioner information not provided. Please call PetscPartitionerShellSetPartition()");
113577623264SMatthew G. Knepley   ierr = PetscSectionGetChart(p->section, NULL, &np);CHKERRQ(ierr);
113677623264SMatthew G. Knepley   if (nparts != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of requested partitions %d != configured partitions %d", nparts, np);
113777623264SMatthew G. Knepley   ierr = ISGetLocalSize(p->partition, &np);CHKERRQ(ierr);
113877623264SMatthew G. Knepley   if (numVertices != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input vertices %d != configured vertices %d", numVertices, np);
11395680f57bSMatthew G. Knepley   ierr = PetscSectionCopy(p->section, partSection);CHKERRQ(ierr);
114077623264SMatthew G. Knepley   *partition = p->partition;
114177623264SMatthew G. Knepley   ierr = PetscObjectReference((PetscObject) p->partition);CHKERRQ(ierr);
114277623264SMatthew G. Knepley   PetscFunctionReturn(0);
114377623264SMatthew G. Knepley }
114477623264SMatthew G. Knepley 
1145d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Shell(PetscPartitioner part)
114677623264SMatthew G. Knepley {
114777623264SMatthew G. Knepley   PetscFunctionBegin;
1148074d466cSStefano Zampini   part->noGraph             = PETSC_TRUE; /* PetscPartitionerShell cannot overload the partition call, so it is safe for now */
114977623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_Shell;
1150077101c0SMatthew G. Knepley   part->ops->setfromoptions = PetscPartitionerSetFromOptions_Shell;
115177623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_Shell;
115277623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_Shell;
115377623264SMatthew G. Knepley   PetscFunctionReturn(0);
115477623264SMatthew G. Knepley }
115577623264SMatthew G. Knepley 
115677623264SMatthew G. Knepley /*MC
115777623264SMatthew G. Knepley   PETSCPARTITIONERSHELL = "shell" - A PetscPartitioner object
115877623264SMatthew G. Knepley 
115977623264SMatthew G. Knepley   Level: intermediate
116077623264SMatthew G. Knepley 
116177623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
116277623264SMatthew G. Knepley M*/
116377623264SMatthew G. Knepley 
116477623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Shell(PetscPartitioner part)
116577623264SMatthew G. Knepley {
116677623264SMatthew G. Knepley   PetscPartitioner_Shell *p;
116777623264SMatthew G. Knepley   PetscErrorCode          ierr;
116877623264SMatthew G. Knepley 
116977623264SMatthew G. Knepley   PetscFunctionBegin;
117077623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
117177623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
117277623264SMatthew G. Knepley   part->data = p;
117377623264SMatthew G. Knepley 
117477623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Shell(part);CHKERRQ(ierr);
1175077101c0SMatthew G. Knepley   p->random = PETSC_FALSE;
117677623264SMatthew G. Knepley   PetscFunctionReturn(0);
117777623264SMatthew G. Knepley }
117877623264SMatthew G. Knepley 
11795680f57bSMatthew G. Knepley /*@C
11805680f57bSMatthew G. Knepley   PetscPartitionerShellSetPartition - Set an artifical partition for a mesh
11815680f57bSMatthew G. Knepley 
1182d083f849SBarry Smith   Collective on part
11835680f57bSMatthew G. Knepley 
11845680f57bSMatthew G. Knepley   Input Parameters:
11855680f57bSMatthew G. Knepley + part   - The PetscPartitioner
11869852e123SBarry Smith . size   - The number of partitions
11879852e123SBarry Smith . sizes  - array of size size (or NULL) providing the number of points in each partition
11889758bf69SToby 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.)
11895680f57bSMatthew G. Knepley 
11905680f57bSMatthew G. Knepley   Level: developer
11915680f57bSMatthew G. Knepley 
1192b7e49471SLawrence Mitchell   Notes:
1193b7e49471SLawrence Mitchell 
1194b7e49471SLawrence Mitchell     It is safe to free the sizes and points arrays after use in this routine.
1195b7e49471SLawrence Mitchell 
11965680f57bSMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerCreate()
11975680f57bSMatthew G. Knepley @*/
11989852e123SBarry Smith PetscErrorCode PetscPartitionerShellSetPartition(PetscPartitioner part, PetscInt size, const PetscInt sizes[], const PetscInt points[])
11995680f57bSMatthew G. Knepley {
12005680f57bSMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
12015680f57bSMatthew G. Knepley   PetscInt                proc, numPoints;
12025680f57bSMatthew G. Knepley   PetscErrorCode          ierr;
12035680f57bSMatthew G. Knepley 
12045680f57bSMatthew G. Knepley   PetscFunctionBegin;
12055680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
12065680f57bSMatthew G. Knepley   if (sizes)  {PetscValidPointer(sizes, 3);}
1207c717d290SMatthew G. Knepley   if (points) {PetscValidPointer(points, 4);}
12085680f57bSMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
12095680f57bSMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
12105680f57bSMatthew G. Knepley   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) part), &p->section);CHKERRQ(ierr);
12119852e123SBarry Smith   ierr = PetscSectionSetChart(p->section, 0, size);CHKERRQ(ierr);
12125680f57bSMatthew G. Knepley   if (sizes) {
12139852e123SBarry Smith     for (proc = 0; proc < size; ++proc) {
12145680f57bSMatthew G. Knepley       ierr = PetscSectionSetDof(p->section, proc, sizes[proc]);CHKERRQ(ierr);
12155680f57bSMatthew G. Knepley     }
12165680f57bSMatthew G. Knepley   }
12175680f57bSMatthew G. Knepley   ierr = PetscSectionSetUp(p->section);CHKERRQ(ierr);
12185680f57bSMatthew G. Knepley   ierr = PetscSectionGetStorageSize(p->section, &numPoints);CHKERRQ(ierr);
12195680f57bSMatthew G. Knepley   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), numPoints, points, PETSC_COPY_VALUES, &p->partition);CHKERRQ(ierr);
12205680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
12215680f57bSMatthew G. Knepley }
12225680f57bSMatthew G. Knepley 
1223077101c0SMatthew G. Knepley /*@
1224077101c0SMatthew G. Knepley   PetscPartitionerShellSetRandom - Set the flag to use a random partition
1225077101c0SMatthew G. Knepley 
1226d083f849SBarry Smith   Collective on part
1227077101c0SMatthew G. Knepley 
1228077101c0SMatthew G. Knepley   Input Parameters:
1229077101c0SMatthew G. Knepley + part   - The PetscPartitioner
1230077101c0SMatthew G. Knepley - random - The flag to use a random partition
1231077101c0SMatthew G. Knepley 
1232077101c0SMatthew G. Knepley   Level: intermediate
1233077101c0SMatthew G. Knepley 
1234077101c0SMatthew G. Knepley .seealso PetscPartitionerShellGetRandom(), PetscPartitionerCreate()
1235077101c0SMatthew G. Knepley @*/
1236077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellSetRandom(PetscPartitioner part, PetscBool random)
1237077101c0SMatthew G. Knepley {
1238077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1239077101c0SMatthew G. Knepley 
1240077101c0SMatthew G. Knepley   PetscFunctionBegin;
1241077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1242077101c0SMatthew G. Knepley   p->random = random;
1243077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1244077101c0SMatthew G. Knepley }
1245077101c0SMatthew G. Knepley 
1246077101c0SMatthew G. Knepley /*@
1247077101c0SMatthew G. Knepley   PetscPartitionerShellGetRandom - get the flag to use a random partition
1248077101c0SMatthew G. Knepley 
1249d083f849SBarry Smith   Collective on part
1250077101c0SMatthew G. Knepley 
1251077101c0SMatthew G. Knepley   Input Parameter:
1252077101c0SMatthew G. Knepley . part   - The PetscPartitioner
1253077101c0SMatthew G. Knepley 
1254077101c0SMatthew G. Knepley   Output Parameter
1255077101c0SMatthew G. Knepley . random - The flag to use a random partition
1256077101c0SMatthew G. Knepley 
1257077101c0SMatthew G. Knepley   Level: intermediate
1258077101c0SMatthew G. Knepley 
1259077101c0SMatthew G. Knepley .seealso PetscPartitionerShellSetRandom(), PetscPartitionerCreate()
1260077101c0SMatthew G. Knepley @*/
1261077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellGetRandom(PetscPartitioner part, PetscBool *random)
1262077101c0SMatthew G. Knepley {
1263077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1264077101c0SMatthew G. Knepley 
1265077101c0SMatthew G. Knepley   PetscFunctionBegin;
1266077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1267077101c0SMatthew G. Knepley   PetscValidPointer(random, 2);
1268077101c0SMatthew G. Knepley   *random = p->random;
1269077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1270077101c0SMatthew G. Knepley }
1271077101c0SMatthew G. Knepley 
1272d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Simple(PetscPartitioner part)
1273555a9cf8SMatthew G. Knepley {
1274555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p = (PetscPartitioner_Simple *) part->data;
1275555a9cf8SMatthew G. Knepley   PetscErrorCode          ierr;
1276555a9cf8SMatthew G. Knepley 
1277555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1278555a9cf8SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
1279555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1280555a9cf8SMatthew G. Knepley }
1281555a9cf8SMatthew G. Knepley 
1282d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple_Ascii(PetscPartitioner part, PetscViewer viewer)
1283555a9cf8SMatthew G. Knepley {
1284555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1285555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1286555a9cf8SMatthew G. Knepley }
1287555a9cf8SMatthew G. Knepley 
1288d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple(PetscPartitioner part, PetscViewer viewer)
1289555a9cf8SMatthew G. Knepley {
1290555a9cf8SMatthew G. Knepley   PetscBool      iascii;
1291555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1292555a9cf8SMatthew G. Knepley 
1293555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1294555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1295555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1296555a9cf8SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1297555a9cf8SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Simple_Ascii(part, viewer);CHKERRQ(ierr);}
1298555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1299555a9cf8SMatthew G. Knepley }
1300555a9cf8SMatthew G. Knepley 
1301d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Simple(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1302555a9cf8SMatthew G. Knepley {
1303cead94edSToby Isaac   MPI_Comm       comm;
1304555a9cf8SMatthew G. Knepley   PetscInt       np;
1305cead94edSToby Isaac   PetscMPIInt    size;
1306555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1307555a9cf8SMatthew G. Knepley 
1308555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
130904ba2274SStefano Zampini   comm = PetscObjectComm((PetscObject)part);
1310cead94edSToby Isaac   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1311555a9cf8SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1312555a9cf8SMatthew G. Knepley   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1313cead94edSToby Isaac   if (size == 1) {
1314cead94edSToby Isaac     for (np = 0; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, numVertices/nparts + ((numVertices % nparts) > np));CHKERRQ(ierr);}
131504ba2274SStefano Zampini   } else {
1316cead94edSToby Isaac     PetscMPIInt rank;
1317cead94edSToby Isaac     PetscInt nvGlobal, *offsets, myFirst, myLast;
1318cead94edSToby Isaac 
1319a679a563SToby Isaac     ierr = PetscMalloc1(size+1,&offsets);CHKERRQ(ierr);
1320cead94edSToby Isaac     offsets[0] = 0;
1321cead94edSToby Isaac     ierr = MPI_Allgather(&numVertices,1,MPIU_INT,&offsets[1],1,MPIU_INT,comm);CHKERRQ(ierr);
1322cead94edSToby Isaac     for (np = 2; np <= size; np++) {
1323cead94edSToby Isaac       offsets[np] += offsets[np-1];
1324cead94edSToby Isaac     }
1325cead94edSToby Isaac     nvGlobal = offsets[size];
1326cead94edSToby Isaac     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1327cead94edSToby Isaac     myFirst = offsets[rank];
1328cead94edSToby Isaac     myLast  = offsets[rank + 1] - 1;
1329cead94edSToby Isaac     ierr = PetscFree(offsets);CHKERRQ(ierr);
1330cead94edSToby Isaac     if (numVertices) {
1331cead94edSToby Isaac       PetscInt firstPart = 0, firstLargePart = 0;
1332cead94edSToby Isaac       PetscInt lastPart = 0, lastLargePart = 0;
1333cead94edSToby Isaac       PetscInt rem = nvGlobal % nparts;
1334cead94edSToby Isaac       PetscInt pSmall = nvGlobal/nparts;
1335cead94edSToby Isaac       PetscInt pBig = nvGlobal/nparts + 1;
1336cead94edSToby Isaac 
1337cead94edSToby Isaac 
1338cead94edSToby Isaac       if (rem) {
1339cead94edSToby Isaac         firstLargePart = myFirst / pBig;
1340cead94edSToby Isaac         lastLargePart  = myLast  / pBig;
1341cead94edSToby Isaac 
1342cead94edSToby Isaac         if (firstLargePart < rem) {
1343cead94edSToby Isaac           firstPart = firstLargePart;
134404ba2274SStefano Zampini         } else {
1345cead94edSToby Isaac           firstPart = rem + (myFirst - (rem * pBig)) / pSmall;
1346cead94edSToby Isaac         }
1347cead94edSToby Isaac         if (lastLargePart < rem) {
1348cead94edSToby Isaac           lastPart = lastLargePart;
134904ba2274SStefano Zampini         } else {
1350cead94edSToby Isaac           lastPart = rem + (myLast - (rem * pBig)) / pSmall;
1351cead94edSToby Isaac         }
135204ba2274SStefano Zampini       } else {
1353cead94edSToby Isaac         firstPart = myFirst / (nvGlobal/nparts);
1354cead94edSToby Isaac         lastPart  = myLast  / (nvGlobal/nparts);
1355cead94edSToby Isaac       }
1356cead94edSToby Isaac 
1357cead94edSToby Isaac       for (np = firstPart; np <= lastPart; np++) {
1358cead94edSToby Isaac         PetscInt PartStart =  np    * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np);
1359cead94edSToby Isaac         PetscInt PartEnd   = (np+1) * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np+1);
1360cead94edSToby Isaac 
1361cead94edSToby Isaac         PartStart = PetscMax(PartStart,myFirst);
1362cead94edSToby Isaac         PartEnd   = PetscMin(PartEnd,myLast+1);
1363cead94edSToby Isaac         ierr = PetscSectionSetDof(partSection,np,PartEnd-PartStart);CHKERRQ(ierr);
1364cead94edSToby Isaac       }
1365cead94edSToby Isaac     }
1366cead94edSToby Isaac   }
1367cead94edSToby Isaac   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1368555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1369555a9cf8SMatthew G. Knepley }
1370555a9cf8SMatthew G. Knepley 
1371d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Simple(PetscPartitioner part)
1372555a9cf8SMatthew G. Knepley {
1373555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1374074d466cSStefano Zampini   part->noGraph        = PETSC_TRUE;
1375555a9cf8SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Simple;
1376555a9cf8SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Simple;
1377555a9cf8SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Simple;
1378555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1379555a9cf8SMatthew G. Knepley }
1380555a9cf8SMatthew G. Knepley 
1381555a9cf8SMatthew G. Knepley /*MC
1382555a9cf8SMatthew G. Knepley   PETSCPARTITIONERSIMPLE = "simple" - A PetscPartitioner object
1383555a9cf8SMatthew G. Knepley 
1384555a9cf8SMatthew G. Knepley   Level: intermediate
1385555a9cf8SMatthew G. Knepley 
1386555a9cf8SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1387555a9cf8SMatthew G. Knepley M*/
1388555a9cf8SMatthew G. Knepley 
1389555a9cf8SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Simple(PetscPartitioner part)
1390555a9cf8SMatthew G. Knepley {
1391555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p;
1392555a9cf8SMatthew G. Knepley   PetscErrorCode           ierr;
1393555a9cf8SMatthew G. Knepley 
1394555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1395555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1396555a9cf8SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1397555a9cf8SMatthew G. Knepley   part->data = p;
1398555a9cf8SMatthew G. Knepley 
1399555a9cf8SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Simple(part);CHKERRQ(ierr);
1400555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1401555a9cf8SMatthew G. Knepley }
1402555a9cf8SMatthew G. Knepley 
1403d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Gather(PetscPartitioner part)
1404dae52e14SToby Isaac {
1405dae52e14SToby Isaac   PetscPartitioner_Gather *p = (PetscPartitioner_Gather *) part->data;
1406dae52e14SToby Isaac   PetscErrorCode          ierr;
1407dae52e14SToby Isaac 
1408dae52e14SToby Isaac   PetscFunctionBegin;
1409dae52e14SToby Isaac   ierr = PetscFree(p);CHKERRQ(ierr);
1410dae52e14SToby Isaac   PetscFunctionReturn(0);
1411dae52e14SToby Isaac }
1412dae52e14SToby Isaac 
1413d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather_Ascii(PetscPartitioner part, PetscViewer viewer)
1414dae52e14SToby Isaac {
1415dae52e14SToby Isaac   PetscFunctionBegin;
1416dae52e14SToby Isaac   PetscFunctionReturn(0);
1417dae52e14SToby Isaac }
1418dae52e14SToby Isaac 
1419d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather(PetscPartitioner part, PetscViewer viewer)
1420dae52e14SToby Isaac {
1421dae52e14SToby Isaac   PetscBool      iascii;
1422dae52e14SToby Isaac   PetscErrorCode ierr;
1423dae52e14SToby Isaac 
1424dae52e14SToby Isaac   PetscFunctionBegin;
1425dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1426dae52e14SToby Isaac   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1427dae52e14SToby Isaac   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1428dae52e14SToby Isaac   if (iascii) {ierr = PetscPartitionerView_Gather_Ascii(part, viewer);CHKERRQ(ierr);}
1429dae52e14SToby Isaac   PetscFunctionReturn(0);
1430dae52e14SToby Isaac }
1431dae52e14SToby Isaac 
1432d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Gather(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1433dae52e14SToby Isaac {
1434dae52e14SToby Isaac   PetscInt       np;
1435dae52e14SToby Isaac   PetscErrorCode ierr;
1436dae52e14SToby Isaac 
1437dae52e14SToby Isaac   PetscFunctionBegin;
1438dae52e14SToby Isaac   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1439dae52e14SToby Isaac   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1440dae52e14SToby Isaac   ierr = PetscSectionSetDof(partSection,0,numVertices);CHKERRQ(ierr);
1441dae52e14SToby Isaac   for (np = 1; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, 0);CHKERRQ(ierr);}
1442dae52e14SToby Isaac   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1443dae52e14SToby Isaac   PetscFunctionReturn(0);
1444dae52e14SToby Isaac }
1445dae52e14SToby Isaac 
1446d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Gather(PetscPartitioner part)
1447dae52e14SToby Isaac {
1448dae52e14SToby Isaac   PetscFunctionBegin;
1449074d466cSStefano Zampini   part->noGraph        = PETSC_TRUE;
1450dae52e14SToby Isaac   part->ops->view      = PetscPartitionerView_Gather;
1451dae52e14SToby Isaac   part->ops->destroy   = PetscPartitionerDestroy_Gather;
1452dae52e14SToby Isaac   part->ops->partition = PetscPartitionerPartition_Gather;
1453dae52e14SToby Isaac   PetscFunctionReturn(0);
1454dae52e14SToby Isaac }
1455dae52e14SToby Isaac 
1456dae52e14SToby Isaac /*MC
1457dae52e14SToby Isaac   PETSCPARTITIONERGATHER = "gather" - A PetscPartitioner object
1458dae52e14SToby Isaac 
1459dae52e14SToby Isaac   Level: intermediate
1460dae52e14SToby Isaac 
1461dae52e14SToby Isaac .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1462dae52e14SToby Isaac M*/
1463dae52e14SToby Isaac 
1464dae52e14SToby Isaac PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Gather(PetscPartitioner part)
1465dae52e14SToby Isaac {
1466dae52e14SToby Isaac   PetscPartitioner_Gather *p;
1467dae52e14SToby Isaac   PetscErrorCode           ierr;
1468dae52e14SToby Isaac 
1469dae52e14SToby Isaac   PetscFunctionBegin;
1470dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1471dae52e14SToby Isaac   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1472dae52e14SToby Isaac   part->data = p;
1473dae52e14SToby Isaac 
1474dae52e14SToby Isaac   ierr = PetscPartitionerInitialize_Gather(part);CHKERRQ(ierr);
1475dae52e14SToby Isaac   PetscFunctionReturn(0);
1476dae52e14SToby Isaac }
1477dae52e14SToby Isaac 
1478dae52e14SToby Isaac 
1479d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Chaco(PetscPartitioner part)
148077623264SMatthew G. Knepley {
148177623264SMatthew G. Knepley   PetscPartitioner_Chaco *p = (PetscPartitioner_Chaco *) part->data;
148277623264SMatthew G. Knepley   PetscErrorCode          ierr;
148377623264SMatthew G. Knepley 
148477623264SMatthew G. Knepley   PetscFunctionBegin;
148577623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
148677623264SMatthew G. Knepley   PetscFunctionReturn(0);
148777623264SMatthew G. Knepley }
148877623264SMatthew G. Knepley 
1489d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco_Ascii(PetscPartitioner part, PetscViewer viewer)
149077623264SMatthew G. Knepley {
149177623264SMatthew G. Knepley   PetscFunctionBegin;
149277623264SMatthew G. Knepley   PetscFunctionReturn(0);
149377623264SMatthew G. Knepley }
149477623264SMatthew G. Knepley 
1495d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco(PetscPartitioner part, PetscViewer viewer)
149677623264SMatthew G. Knepley {
149777623264SMatthew G. Knepley   PetscBool      iascii;
149877623264SMatthew G. Knepley   PetscErrorCode ierr;
149977623264SMatthew G. Knepley 
150077623264SMatthew G. Knepley   PetscFunctionBegin;
150177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
150277623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
150377623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
150477623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Chaco_Ascii(part, viewer);CHKERRQ(ierr);}
150577623264SMatthew G. Knepley   PetscFunctionReturn(0);
150677623264SMatthew G. Knepley }
150777623264SMatthew G. Knepley 
150870034214SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
150970034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
151070034214SMatthew G. Knepley #include <unistd.h>
151170034214SMatthew G. Knepley #endif
151211d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
151311d1e910SBarry Smith #include <chaco.h>
151411d1e910SBarry Smith #else
151511d1e910SBarry Smith /* Older versions of Chaco do not have an include file */
151670034214SMatthew G. Knepley PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
151770034214SMatthew G. Knepley                        float *ewgts, float *x, float *y, float *z, char *outassignname,
151870034214SMatthew G. Knepley                        char *outfilename, short *assignment, int architecture, int ndims_tot,
151970034214SMatthew G. Knepley                        int mesh_dims[3], double *goal, int global_method, int local_method,
152070034214SMatthew G. Knepley                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
152111d1e910SBarry Smith #endif
152270034214SMatthew G. Knepley extern int FREE_GRAPH;
152377623264SMatthew G. Knepley #endif
152470034214SMatthew G. Knepley 
1525d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Chaco(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
152670034214SMatthew G. Knepley {
152777623264SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
152870034214SMatthew G. Knepley   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
152970034214SMatthew G. Knepley   MPI_Comm       comm;
153070034214SMatthew G. Knepley   int            nvtxs          = numVertices; /* number of vertices in full graph */
153170034214SMatthew G. Knepley   int           *vwgts          = NULL;   /* weights for all vertices */
153270034214SMatthew G. Knepley   float         *ewgts          = NULL;   /* weights for all edges */
153370034214SMatthew G. Knepley   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
153470034214SMatthew G. Knepley   char          *outassignname  = NULL;   /*  name of assignment output file */
153570034214SMatthew G. Knepley   char          *outfilename    = NULL;   /* output file name */
153670034214SMatthew G. Knepley   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
153770034214SMatthew G. Knepley   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
153870034214SMatthew G. Knepley   int            mesh_dims[3];            /* dimensions of mesh of processors */
153970034214SMatthew G. Knepley   double        *goal          = NULL;    /* desired set sizes for each set */
154070034214SMatthew G. Knepley   int            global_method = 1;       /* global partitioning algorithm */
154170034214SMatthew G. Knepley   int            local_method  = 1;       /* local partitioning algorithm */
154270034214SMatthew G. Knepley   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
154370034214SMatthew G. Knepley   int            vmax          = 200;     /* how many vertices to coarsen down to? */
154470034214SMatthew G. Knepley   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
154570034214SMatthew G. Knepley   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
154670034214SMatthew G. Knepley   long           seed          = 123636512; /* for random graph mutations */
154711d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
154811d1e910SBarry Smith   int           *assignment;              /* Output partition */
154911d1e910SBarry Smith #else
155070034214SMatthew G. Knepley   short int     *assignment;              /* Output partition */
155111d1e910SBarry Smith #endif
155270034214SMatthew G. Knepley   int            fd_stdout, fd_pipe[2];
155370034214SMatthew G. Knepley   PetscInt      *points;
155470034214SMatthew G. Knepley   int            i, v, p;
155570034214SMatthew G. Knepley   PetscErrorCode ierr;
155670034214SMatthew G. Knepley 
155770034214SMatthew G. Knepley   PetscFunctionBegin;
155870034214SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
155907ed3857SLisandro Dalcin #if defined (PETSC_USE_DEBUG)
156007ed3857SLisandro Dalcin   {
156107ed3857SLisandro Dalcin     int ival,isum;
156207ed3857SLisandro Dalcin     PetscBool distributed;
156307ed3857SLisandro Dalcin 
156407ed3857SLisandro Dalcin     ival = (numVertices > 0);
156507ed3857SLisandro Dalcin     ierr = MPI_Allreduce(&ival, &isum, 1, MPI_INT, MPI_SUM, comm);CHKERRQ(ierr);
156607ed3857SLisandro Dalcin     distributed = (isum > 1) ? PETSC_TRUE : PETSC_FALSE;
156707ed3857SLisandro Dalcin     if (distributed) SETERRQ(comm, PETSC_ERR_SUP, "Chaco cannot partition a distributed graph");
156807ed3857SLisandro Dalcin   }
156907ed3857SLisandro Dalcin #endif
157070034214SMatthew G. Knepley   if (!numVertices) {
157177623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
157277623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
157370034214SMatthew G. Knepley     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
157470034214SMatthew G. Knepley     PetscFunctionReturn(0);
157570034214SMatthew G. Knepley   }
157670034214SMatthew G. Knepley   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
157770034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
157870034214SMatthew G. Knepley 
157970034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
158070034214SMatthew G. Knepley     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
158170034214SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
158270034214SMatthew G. Knepley   }
158377623264SMatthew G. Knepley   mesh_dims[0] = nparts;
158470034214SMatthew G. Knepley   mesh_dims[1] = 1;
158570034214SMatthew G. Knepley   mesh_dims[2] = 1;
158670034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &assignment);CHKERRQ(ierr);
158770034214SMatthew G. Knepley   /* Chaco outputs to stdout. We redirect this to a buffer. */
158870034214SMatthew G. Knepley   /* TODO: check error codes for UNIX calls */
158970034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
159070034214SMatthew G. Knepley   {
159170034214SMatthew G. Knepley     int piperet;
159270034214SMatthew G. Knepley     piperet = pipe(fd_pipe);
159370034214SMatthew G. Knepley     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
159470034214SMatthew G. Knepley     fd_stdout = dup(1);
159570034214SMatthew G. Knepley     close(1);
159670034214SMatthew G. Knepley     dup2(fd_pipe[1], 1);
159770034214SMatthew G. Knepley   }
159870034214SMatthew G. Knepley #endif
159970034214SMatthew G. Knepley   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
160070034214SMatthew G. Knepley                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
160170034214SMatthew G. Knepley                    vmax, ndims, eigtol, seed);
160270034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
160370034214SMatthew G. Knepley   {
160470034214SMatthew G. Knepley     char msgLog[10000];
160570034214SMatthew G. Knepley     int  count;
160670034214SMatthew G. Knepley 
160770034214SMatthew G. Knepley     fflush(stdout);
160870034214SMatthew G. Knepley     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
160970034214SMatthew G. Knepley     if (count < 0) count = 0;
161070034214SMatthew G. Knepley     msgLog[count] = 0;
161170034214SMatthew G. Knepley     close(1);
161270034214SMatthew G. Knepley     dup2(fd_stdout, 1);
161370034214SMatthew G. Knepley     close(fd_stdout);
161470034214SMatthew G. Knepley     close(fd_pipe[0]);
161570034214SMatthew G. Knepley     close(fd_pipe[1]);
161670034214SMatthew G. Knepley     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
161770034214SMatthew G. Knepley   }
161807ed3857SLisandro Dalcin #else
161907ed3857SLisandro Dalcin   if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", "error in stdout");
162070034214SMatthew G. Knepley #endif
162170034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
162277623264SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
162370034214SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {
162477623264SMatthew G. Knepley     ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);
162570034214SMatthew G. Knepley   }
162677623264SMatthew G. Knepley   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
162770034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
162877623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
162970034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
163070034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
163170034214SMatthew G. Knepley     }
163270034214SMatthew G. Knepley   }
163370034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
163470034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
163570034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
163670034214SMatthew G. Knepley     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
163770034214SMatthew G. Knepley   }
163870034214SMatthew G. Knepley   ierr = PetscFree(assignment);CHKERRQ(ierr);
163970034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
164070034214SMatthew G. Knepley   PetscFunctionReturn(0);
164177623264SMatthew G. Knepley #else
164277623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
164370034214SMatthew G. Knepley #endif
164477623264SMatthew G. Knepley }
164577623264SMatthew G. Knepley 
1646d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Chaco(PetscPartitioner part)
164777623264SMatthew G. Knepley {
164877623264SMatthew G. Knepley   PetscFunctionBegin;
1649074d466cSStefano Zampini   part->noGraph        = PETSC_FALSE;
165077623264SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Chaco;
165177623264SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Chaco;
165277623264SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Chaco;
165377623264SMatthew G. Knepley   PetscFunctionReturn(0);
165477623264SMatthew G. Knepley }
165577623264SMatthew G. Knepley 
165677623264SMatthew G. Knepley /*MC
165777623264SMatthew G. Knepley   PETSCPARTITIONERCHACO = "chaco" - A PetscPartitioner object using the Chaco library
165877623264SMatthew G. Knepley 
165977623264SMatthew G. Knepley   Level: intermediate
166077623264SMatthew G. Knepley 
166177623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
166277623264SMatthew G. Knepley M*/
166377623264SMatthew G. Knepley 
166477623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Chaco(PetscPartitioner part)
166577623264SMatthew G. Knepley {
166677623264SMatthew G. Knepley   PetscPartitioner_Chaco *p;
166777623264SMatthew G. Knepley   PetscErrorCode          ierr;
166877623264SMatthew G. Knepley 
166977623264SMatthew G. Knepley   PetscFunctionBegin;
167077623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
167177623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
167277623264SMatthew G. Knepley   part->data = p;
167377623264SMatthew G. Knepley 
167477623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Chaco(part);CHKERRQ(ierr);
167577623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ChacoPartitionerCitation, &ChacoPartitionercite);CHKERRQ(ierr);
167677623264SMatthew G. Knepley   PetscFunctionReturn(0);
167777623264SMatthew G. Knepley }
167877623264SMatthew G. Knepley 
16795b440754SMatthew G. Knepley static const char *ptypes[] = {"kway", "rb"};
16805b440754SMatthew G. Knepley 
1681d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_ParMetis(PetscPartitioner part)
168277623264SMatthew G. Knepley {
168377623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
168477623264SMatthew G. Knepley   PetscErrorCode             ierr;
168577623264SMatthew G. Knepley 
168677623264SMatthew G. Knepley   PetscFunctionBegin;
168777623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
168877623264SMatthew G. Knepley   PetscFunctionReturn(0);
168977623264SMatthew G. Knepley }
169077623264SMatthew G. Knepley 
1691d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis_Ascii(PetscPartitioner part, PetscViewer viewer)
169277623264SMatthew G. Knepley {
16932abdaa70SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
169477623264SMatthew G. Knepley   PetscErrorCode             ierr;
169577623264SMatthew G. Knepley 
169677623264SMatthew G. Knepley   PetscFunctionBegin;
16972abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
16982abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "ParMetis type: %s\n", ptypes[p->ptype]);CHKERRQ(ierr);
16992abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "load imbalance ratio %g\n", (double) p->imbalanceRatio);CHKERRQ(ierr);
17002abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "debug flag %D\n", p->debugFlag);CHKERRQ(ierr);
17019d459c0eSStefano Zampini   ierr = PetscViewerASCIIPrintf(viewer, "random seed %D\n", p->randomSeed);CHKERRQ(ierr);
17022abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
170377623264SMatthew G. Knepley   PetscFunctionReturn(0);
170477623264SMatthew G. Knepley }
170577623264SMatthew G. Knepley 
1706d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis(PetscPartitioner part, PetscViewer viewer)
170777623264SMatthew G. Knepley {
170877623264SMatthew G. Knepley   PetscBool      iascii;
170977623264SMatthew G. Knepley   PetscErrorCode ierr;
171077623264SMatthew G. Knepley 
171177623264SMatthew G. Knepley   PetscFunctionBegin;
171277623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
171377623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
171477623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
171577623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_ParMetis_Ascii(part, viewer);CHKERRQ(ierr);}
171677623264SMatthew G. Knepley   PetscFunctionReturn(0);
171777623264SMatthew G. Knepley }
171870034214SMatthew G. Knepley 
171944d8be81SLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_ParMetis(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
172044d8be81SLisandro Dalcin {
172144d8be81SLisandro Dalcin   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
172244d8be81SLisandro Dalcin   PetscErrorCode            ierr;
172344d8be81SLisandro Dalcin 
172444d8be81SLisandro Dalcin   PetscFunctionBegin;
172544d8be81SLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner ParMetis Options");CHKERRQ(ierr);
172644d8be81SLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_parmetis_type", "Partitioning method", "", ptypes, 2, ptypes[p->ptype], &p->ptype, NULL);CHKERRQ(ierr);
17275b440754SMatthew G. Knepley   ierr = PetscOptionsReal("-petscpartitioner_parmetis_imbalance_ratio", "Load imbalance ratio limit", "", p->imbalanceRatio, &p->imbalanceRatio, NULL);CHKERRQ(ierr);
17285b440754SMatthew G. Knepley   ierr = PetscOptionsInt("-petscpartitioner_parmetis_debug", "Debugging flag", "", p->debugFlag, &p->debugFlag, NULL);CHKERRQ(ierr);
17299d459c0eSStefano Zampini   ierr = PetscOptionsInt("-petscpartitioner_parmetis_seed", "Random seed", "", p->randomSeed, &p->randomSeed, NULL);CHKERRQ(ierr);
173044d8be81SLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
173144d8be81SLisandro Dalcin   PetscFunctionReturn(0);
173244d8be81SLisandro Dalcin }
173344d8be81SLisandro Dalcin 
173470034214SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
173570034214SMatthew G. Knepley #include <parmetis.h>
173677623264SMatthew G. Knepley #endif
173770034214SMatthew G. Knepley 
1738d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_ParMetis(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
173970034214SMatthew G. Knepley {
174077623264SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
17415b440754SMatthew G. Knepley   PetscPartitioner_ParMetis *pm = (PetscPartitioner_ParMetis *) part->data;
174270034214SMatthew G. Knepley   MPI_Comm       comm;
1743deea36a5SMatthew G. Knepley   PetscSection   section;
174470034214SMatthew G. Knepley   PetscInt       nvtxs       = numVertices; /* The number of vertices in full graph */
174570034214SMatthew G. Knepley   PetscInt      *vtxdist;                   /* Distribution of vertices across processes */
174670034214SMatthew G. Knepley   PetscInt      *xadj        = start;       /* Start of edge list for each vertex */
174770034214SMatthew G. Knepley   PetscInt      *adjncy      = adjacency;   /* Edge lists for all vertices */
174870034214SMatthew G. Knepley   PetscInt      *vwgt        = NULL;        /* Vertex weights */
174970034214SMatthew G. Knepley   PetscInt      *adjwgt      = NULL;        /* Edge weights */
175070034214SMatthew G. Knepley   PetscInt       wgtflag     = 0;           /* Indicates which weights are present */
175170034214SMatthew G. Knepley   PetscInt       numflag     = 0;           /* Indicates initial offset (0 or 1) */
175270034214SMatthew G. Knepley   PetscInt       ncon        = 1;           /* The number of weights per vertex */
17535b440754SMatthew G. Knepley   PetscInt       metis_ptype = pm->ptype;   /* kway or recursive bisection */
1754fb83b9f2SMichael Gegg   real_t        *tpwgts;                    /* The fraction of vertex weights assigned to each partition */
1755fb83b9f2SMichael Gegg   real_t        *ubvec;                     /* The balance intolerance for vertex weights */
1756b3ce585bSLisandro Dalcin   PetscInt       options[64];               /* Options */
175770034214SMatthew G. Knepley   /* Outputs */
1758b3ce585bSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
1759b3ce585bSLisandro Dalcin   PetscMPIInt    size, rank, p;
176070034214SMatthew G. Knepley   PetscErrorCode ierr;
176170034214SMatthew G. Knepley 
176270034214SMatthew G. Knepley   PetscFunctionBegin;
176377623264SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) part, &comm);CHKERRQ(ierr);
1764b3ce585bSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
176570034214SMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
176670034214SMatthew G. Knepley   /* Calculate vertex distribution */
1767b3ce585bSLisandro Dalcin   ierr = PetscMalloc5(size+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment,nvtxs,&vwgt);CHKERRQ(ierr);
176870034214SMatthew G. Knepley   vtxdist[0] = 0;
176970034214SMatthew G. Knepley   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
1770b3ce585bSLisandro Dalcin   for (p = 2; p <= size; ++p) {
177170034214SMatthew G. Knepley     vtxdist[p] += vtxdist[p-1];
177270034214SMatthew G. Knepley   }
177344d8be81SLisandro Dalcin   /* Calculate partition weights */
177470034214SMatthew G. Knepley   for (p = 0; p < nparts; ++p) {
177570034214SMatthew G. Knepley     tpwgts[p] = 1.0/nparts;
177670034214SMatthew G. Knepley   }
17775b440754SMatthew G. Knepley   ubvec[0] = pm->imbalanceRatio;
1778deea36a5SMatthew G. Knepley   /* Weight cells by dofs on cell by default */
1779e87a4003SBarry Smith   ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
17808ef05d33SStefano Zampini   for (v = 0; v < nvtxs; ++v) vwgt[v] = 1;
1781deea36a5SMatthew G. Knepley   if (section) {
1782deea36a5SMatthew G. Knepley     PetscInt cStart, cEnd, dof;
178370034214SMatthew G. Knepley 
1784925b1076SLisandro Dalcin     /* WARNING: Assumes that meshes with overlap have the overlapped cells at the end of the stratum. */
1785925b1076SLisandro Dalcin     /* To do this properly, we should use the cell numbering created in DMPlexCreatePartitionerGraph. */
17868ef05d33SStefano Zampini     ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
17878ef05d33SStefano Zampini     for (v = cStart; v < cStart + numVertices; ++v) {
17888ef05d33SStefano Zampini       ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr);
17898ef05d33SStefano Zampini       vwgt[v-cStart] = PetscMax(dof, 1);
1790deea36a5SMatthew G. Knepley     }
1791cd0de0f2SShri   }
179244d8be81SLisandro Dalcin   wgtflag |= 2; /* have weights on graph vertices */
1793cd0de0f2SShri 
179470034214SMatthew G. Knepley   if (nparts == 1) {
1795580bdb30SBarry Smith     ierr = PetscArrayzero(assignment, nvtxs);CHKERRQ(ierr);
179670034214SMatthew G. Knepley   } else {
1797b3ce585bSLisandro Dalcin     for (p = 0; !vtxdist[p+1] && p < size; ++p);
1798b3ce585bSLisandro Dalcin     if (vtxdist[p+1] == vtxdist[size]) {
1799b3ce585bSLisandro Dalcin       if (rank == p) {
180044d8be81SLisandro Dalcin         ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
180142678178SLisandro Dalcin         options[METIS_OPTION_DBGLVL] = pm->debugFlag;
18029d459c0eSStefano Zampini         options[METIS_OPTION_SEED]   = pm->randomSeed;
180344d8be81SLisandro Dalcin         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
180444d8be81SLisandro Dalcin         if (metis_ptype == 1) {
180544d8be81SLisandro Dalcin           PetscStackPush("METIS_PartGraphRecursive");
180672379da4SMatthew G. Knepley           ierr = METIS_PartGraphRecursive(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
180744d8be81SLisandro Dalcin           PetscStackPop;
180844d8be81SLisandro Dalcin           if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphRecursive()");
180944d8be81SLisandro Dalcin         } else {
181044d8be81SLisandro Dalcin           /*
181144d8be81SLisandro Dalcin            It would be nice to activate the two options below, but they would need some actual testing.
181244d8be81SLisandro Dalcin            - Turning on these options may exercise path of the METIS code that have bugs and may break production runs.
181344d8be81SLisandro 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.
181444d8be81SLisandro Dalcin           */
181544d8be81SLisandro Dalcin           /* options[METIS_OPTION_CONTIG]  = 1; */ /* try to produce partitions that are contiguous */
181644d8be81SLisandro Dalcin           /* options[METIS_OPTION_MINCONN] = 1; */ /* minimize the maximum degree of the subdomain graph */
181770034214SMatthew G. Knepley           PetscStackPush("METIS_PartGraphKway");
181872379da4SMatthew G. Knepley           ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
181970034214SMatthew G. Knepley           PetscStackPop;
182070034214SMatthew G. Knepley           if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
182170034214SMatthew G. Knepley         }
182244d8be81SLisandro Dalcin       }
182370034214SMatthew G. Knepley     } else {
182442678178SLisandro Dalcin       options[0] = 1; /*use options */
18255b440754SMatthew G. Knepley       options[1] = pm->debugFlag;
18269d459c0eSStefano Zampini       options[2] = (pm->randomSeed == -1) ? 15 : pm->randomSeed; /* default is GLOBAL_SEED=15 from `libparmetis/defs.h` */
182770034214SMatthew G. Knepley       PetscStackPush("ParMETIS_V3_PartKway");
182872379da4SMatthew G. Knepley       ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment, &comm);
182970034214SMatthew G. Knepley       PetscStackPop;
1830c717d290SMatthew G. Knepley       if (ierr != METIS_OK) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error %d in ParMETIS_V3_PartKway()", ierr);
183170034214SMatthew G. Knepley     }
183270034214SMatthew G. Knepley   }
183370034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
183477623264SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
183577623264SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
183677623264SMatthew G. Knepley   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
183770034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
183877623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
183970034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
184070034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
184170034214SMatthew G. Knepley     }
184270034214SMatthew G. Knepley   }
184370034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
184470034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
1845cd0de0f2SShri   ierr = PetscFree5(vtxdist,tpwgts,ubvec,assignment,vwgt);CHKERRQ(ierr);
18469b80ac48SMatthew G. Knepley   PetscFunctionReturn(0);
184770034214SMatthew G. Knepley #else
184877623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
184970034214SMatthew G. Knepley #endif
185070034214SMatthew G. Knepley }
185170034214SMatthew G. Knepley 
1852d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_ParMetis(PetscPartitioner part)
185377623264SMatthew G. Knepley {
185477623264SMatthew G. Knepley   PetscFunctionBegin;
1855074d466cSStefano Zampini   part->noGraph             = PETSC_FALSE;
185677623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_ParMetis;
185744d8be81SLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_ParMetis;
185877623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_ParMetis;
185977623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_ParMetis;
186077623264SMatthew G. Knepley   PetscFunctionReturn(0);
186177623264SMatthew G. Knepley }
186277623264SMatthew G. Knepley 
186377623264SMatthew G. Knepley /*MC
186477623264SMatthew G. Knepley   PETSCPARTITIONERPARMETIS = "parmetis" - A PetscPartitioner object using the ParMetis library
186577623264SMatthew G. Knepley 
186677623264SMatthew G. Knepley   Level: intermediate
186777623264SMatthew G. Knepley 
186877623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
186977623264SMatthew G. Knepley M*/
187077623264SMatthew G. Knepley 
187177623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_ParMetis(PetscPartitioner part)
187277623264SMatthew G. Knepley {
187377623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p;
187477623264SMatthew G. Knepley   PetscErrorCode          ierr;
187577623264SMatthew G. Knepley 
187677623264SMatthew G. Knepley   PetscFunctionBegin;
187777623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
187877623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
187977623264SMatthew G. Knepley   part->data = p;
188077623264SMatthew G. Knepley 
18815b440754SMatthew G. Knepley   p->ptype          = 0;
18825b440754SMatthew G. Knepley   p->imbalanceRatio = 1.05;
18835b440754SMatthew G. Knepley   p->debugFlag      = 0;
18849d459c0eSStefano Zampini   p->randomSeed     = -1; /* defaults to GLOBAL_SEED=15 from `libparmetis/defs.h` */
18855b440754SMatthew G. Knepley 
188677623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_ParMetis(part);CHKERRQ(ierr);
188777623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ParMetisPartitionerCitation, &ParMetisPartitionercite);CHKERRQ(ierr);
188870034214SMatthew G. Knepley   PetscFunctionReturn(0);
188970034214SMatthew G. Knepley }
189070034214SMatthew G. Knepley 
1891137cd93aSLisandro Dalcin PetscBool PTScotchPartitionercite = PETSC_FALSE;
1892137cd93aSLisandro Dalcin const char PTScotchPartitionerCitation[] =
1893137cd93aSLisandro Dalcin   "@article{PTSCOTCH,\n"
1894137cd93aSLisandro Dalcin   "  author  = {C. Chevalier and F. Pellegrini},\n"
1895137cd93aSLisandro Dalcin   "  title   = {{PT-SCOTCH}: a tool for efficient parallel graph ordering},\n"
1896137cd93aSLisandro Dalcin   "  journal = {Parallel Computing},\n"
1897137cd93aSLisandro Dalcin   "  volume  = {34},\n"
1898137cd93aSLisandro Dalcin   "  number  = {6},\n"
1899137cd93aSLisandro Dalcin   "  pages   = {318--331},\n"
1900137cd93aSLisandro Dalcin   "  year    = {2008},\n"
1901137cd93aSLisandro Dalcin   "  doi     = {https://doi.org/10.1016/j.parco.2007.12.001}\n"
1902137cd93aSLisandro Dalcin   "}\n";
1903137cd93aSLisandro Dalcin 
1904137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
1905137cd93aSLisandro Dalcin 
1906137cd93aSLisandro Dalcin EXTERN_C_BEGIN
1907137cd93aSLisandro Dalcin #include <ptscotch.h>
1908137cd93aSLisandro Dalcin EXTERN_C_END
1909137cd93aSLisandro Dalcin 
1910137cd93aSLisandro Dalcin #define CHKERRPTSCOTCH(ierr) do { if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error calling PT-Scotch library"); } while(0)
1911137cd93aSLisandro Dalcin 
1912137cd93aSLisandro Dalcin static int PTScotch_Strategy(PetscInt strategy)
1913137cd93aSLisandro Dalcin {
1914137cd93aSLisandro Dalcin   switch (strategy) {
1915137cd93aSLisandro Dalcin   case  0: return SCOTCH_STRATDEFAULT;
1916137cd93aSLisandro Dalcin   case  1: return SCOTCH_STRATQUALITY;
1917137cd93aSLisandro Dalcin   case  2: return SCOTCH_STRATSPEED;
1918137cd93aSLisandro Dalcin   case  3: return SCOTCH_STRATBALANCE;
1919137cd93aSLisandro Dalcin   case  4: return SCOTCH_STRATSAFETY;
1920137cd93aSLisandro Dalcin   case  5: return SCOTCH_STRATSCALABILITY;
1921137cd93aSLisandro Dalcin   case  6: return SCOTCH_STRATRECURSIVE;
1922137cd93aSLisandro Dalcin   case  7: return SCOTCH_STRATREMAP;
1923137cd93aSLisandro Dalcin   default: return SCOTCH_STRATDEFAULT;
1924137cd93aSLisandro Dalcin   }
1925137cd93aSLisandro Dalcin }
1926137cd93aSLisandro Dalcin 
1927137cd93aSLisandro Dalcin 
1928137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_Seq(SCOTCH_Num strategy, double imbalance, SCOTCH_Num n, SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
1929137cd93aSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num part[])
1930137cd93aSLisandro Dalcin {
1931137cd93aSLisandro Dalcin   SCOTCH_Graph   grafdat;
1932137cd93aSLisandro Dalcin   SCOTCH_Strat   stradat;
1933137cd93aSLisandro Dalcin   SCOTCH_Num     vertnbr = n;
1934137cd93aSLisandro Dalcin   SCOTCH_Num     edgenbr = xadj[n];
1935137cd93aSLisandro Dalcin   SCOTCH_Num*    velotab = vtxwgt;
1936137cd93aSLisandro Dalcin   SCOTCH_Num*    edlotab = adjwgt;
1937137cd93aSLisandro Dalcin   SCOTCH_Num     flagval = strategy;
1938137cd93aSLisandro Dalcin   double         kbalval = imbalance;
1939137cd93aSLisandro Dalcin   PetscErrorCode ierr;
1940137cd93aSLisandro Dalcin 
1941137cd93aSLisandro Dalcin   PetscFunctionBegin;
1942d99a0000SVaclav Hapla   {
1943d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
1944d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
1945d99a0000SVaclav Hapla     if (!flg) velotab = NULL;
1946d99a0000SVaclav Hapla   }
1947137cd93aSLisandro Dalcin   ierr = SCOTCH_graphInit(&grafdat);CHKERRPTSCOTCH(ierr);
1948137cd93aSLisandro Dalcin   ierr = SCOTCH_graphBuild(&grafdat, 0, vertnbr, xadj, xadj + 1, velotab, NULL, edgenbr, adjncy, edlotab);CHKERRPTSCOTCH(ierr);
1949137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
1950137cd93aSLisandro Dalcin   ierr = SCOTCH_stratGraphMapBuild(&stradat, flagval, nparts, kbalval);CHKERRPTSCOTCH(ierr);
1951137cd93aSLisandro Dalcin #if defined(PETSC_USE_DEBUG)
1952137cd93aSLisandro Dalcin   ierr = SCOTCH_graphCheck(&grafdat);CHKERRPTSCOTCH(ierr);
1953137cd93aSLisandro Dalcin #endif
1954137cd93aSLisandro Dalcin   ierr = SCOTCH_graphPart(&grafdat, nparts, &stradat, part);CHKERRPTSCOTCH(ierr);
1955137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
1956137cd93aSLisandro Dalcin   SCOTCH_graphExit(&grafdat);
1957137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1958137cd93aSLisandro Dalcin }
1959137cd93aSLisandro Dalcin 
1960137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_MPI(SCOTCH_Num strategy, double imbalance, SCOTCH_Num vtxdist[], SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
1961137cd93aSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num part[], MPI_Comm comm)
1962137cd93aSLisandro Dalcin {
1963137cd93aSLisandro Dalcin   PetscMPIInt     procglbnbr;
1964137cd93aSLisandro Dalcin   PetscMPIInt     proclocnum;
1965137cd93aSLisandro Dalcin   SCOTCH_Arch     archdat;
1966137cd93aSLisandro Dalcin   SCOTCH_Dgraph   grafdat;
1967137cd93aSLisandro Dalcin   SCOTCH_Dmapping mappdat;
1968137cd93aSLisandro Dalcin   SCOTCH_Strat    stradat;
1969137cd93aSLisandro Dalcin   SCOTCH_Num      vertlocnbr;
1970137cd93aSLisandro Dalcin   SCOTCH_Num      edgelocnbr;
1971137cd93aSLisandro Dalcin   SCOTCH_Num*     veloloctab = vtxwgt;
1972137cd93aSLisandro Dalcin   SCOTCH_Num*     edloloctab = adjwgt;
1973137cd93aSLisandro Dalcin   SCOTCH_Num      flagval = strategy;
1974137cd93aSLisandro Dalcin   double          kbalval = imbalance;
1975137cd93aSLisandro Dalcin   PetscErrorCode  ierr;
1976137cd93aSLisandro Dalcin 
1977137cd93aSLisandro Dalcin   PetscFunctionBegin;
1978d99a0000SVaclav Hapla   {
1979d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
1980d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
1981d99a0000SVaclav Hapla     if (!flg) veloloctab = NULL;
1982d99a0000SVaclav Hapla   }
1983137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &procglbnbr);CHKERRQ(ierr);
1984137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &proclocnum);CHKERRQ(ierr);
1985137cd93aSLisandro Dalcin   vertlocnbr = vtxdist[proclocnum + 1] - vtxdist[proclocnum];
1986137cd93aSLisandro Dalcin   edgelocnbr = xadj[vertlocnbr];
1987137cd93aSLisandro Dalcin 
1988137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphInit(&grafdat, comm);CHKERRPTSCOTCH(ierr);
1989137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphBuild(&grafdat, 0, vertlocnbr, vertlocnbr, xadj, xadj + 1, veloloctab, NULL, edgelocnbr, edgelocnbr, adjncy, NULL, edloloctab);CHKERRPTSCOTCH(ierr);
1990137cd93aSLisandro Dalcin #if defined(PETSC_USE_DEBUG)
1991137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphCheck(&grafdat);CHKERRPTSCOTCH(ierr);
1992137cd93aSLisandro Dalcin #endif
1993137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
1994137cd93aSLisandro Dalcin   ierr = SCOTCH_stratDgraphMapBuild(&stradat, flagval, procglbnbr, nparts, kbalval);CHKERRQ(ierr);
1995137cd93aSLisandro Dalcin   ierr = SCOTCH_archInit(&archdat);CHKERRPTSCOTCH(ierr);
1996137cd93aSLisandro Dalcin   ierr = SCOTCH_archCmplt(&archdat, nparts);CHKERRPTSCOTCH(ierr);
1997137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapInit(&grafdat, &mappdat, &archdat, part);CHKERRPTSCOTCH(ierr);
1998cb87ef4cSFlorian Wechsung 
1999137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapCompute(&grafdat, &mappdat, &stradat);CHKERRPTSCOTCH(ierr);
2000137cd93aSLisandro Dalcin   SCOTCH_dgraphMapExit(&grafdat, &mappdat);
2001137cd93aSLisandro Dalcin   SCOTCH_archExit(&archdat);
2002137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
2003137cd93aSLisandro Dalcin   SCOTCH_dgraphExit(&grafdat);
2004137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2005137cd93aSLisandro Dalcin }
2006137cd93aSLisandro Dalcin 
2007137cd93aSLisandro Dalcin #endif /* PETSC_HAVE_PTSCOTCH */
2008137cd93aSLisandro Dalcin 
2009137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerDestroy_PTScotch(PetscPartitioner part)
2010137cd93aSLisandro Dalcin {
2011137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2012137cd93aSLisandro Dalcin   PetscErrorCode             ierr;
2013137cd93aSLisandro Dalcin 
2014137cd93aSLisandro Dalcin   PetscFunctionBegin;
2015137cd93aSLisandro Dalcin   ierr = PetscFree(p);CHKERRQ(ierr);
2016137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2017137cd93aSLisandro Dalcin }
2018137cd93aSLisandro Dalcin 
2019137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch_Ascii(PetscPartitioner part, PetscViewer viewer)
2020137cd93aSLisandro Dalcin {
2021137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2022137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
2023137cd93aSLisandro Dalcin 
2024137cd93aSLisandro Dalcin   PetscFunctionBegin;
2025137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
2026137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer, "using partitioning strategy %s\n",PTScotchStrategyList[p->strategy]);CHKERRQ(ierr);
2027137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer, "using load imbalance ratio %g\n",(double)p->imbalance);CHKERRQ(ierr);
2028137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
2029137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2030137cd93aSLisandro Dalcin }
2031137cd93aSLisandro Dalcin 
2032137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch(PetscPartitioner part, PetscViewer viewer)
2033137cd93aSLisandro Dalcin {
2034137cd93aSLisandro Dalcin   PetscBool      iascii;
2035137cd93aSLisandro Dalcin   PetscErrorCode ierr;
2036137cd93aSLisandro Dalcin 
2037137cd93aSLisandro Dalcin   PetscFunctionBegin;
2038137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
2039137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2040137cd93aSLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
2041137cd93aSLisandro Dalcin   if (iascii) {ierr = PetscPartitionerView_PTScotch_Ascii(part, viewer);CHKERRQ(ierr);}
2042137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2043137cd93aSLisandro Dalcin }
2044137cd93aSLisandro Dalcin 
2045137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_PTScotch(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
2046137cd93aSLisandro Dalcin {
2047137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2048137cd93aSLisandro Dalcin   const char *const         *slist = PTScotchStrategyList;
2049137cd93aSLisandro Dalcin   PetscInt                  nlist = (PetscInt)(sizeof(PTScotchStrategyList)/sizeof(PTScotchStrategyList[0]));
2050137cd93aSLisandro Dalcin   PetscBool                 flag;
2051137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
2052137cd93aSLisandro Dalcin 
2053137cd93aSLisandro Dalcin   PetscFunctionBegin;
2054137cd93aSLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner PTScotch Options");CHKERRQ(ierr);
2055137cd93aSLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_ptscotch_strategy","Partitioning strategy","",slist,nlist,slist[p->strategy],&p->strategy,&flag);CHKERRQ(ierr);
2056137cd93aSLisandro Dalcin   ierr = PetscOptionsReal("-petscpartitioner_ptscotch_imbalance","Load imbalance ratio","",p->imbalance,&p->imbalance,&flag);CHKERRQ(ierr);
2057137cd93aSLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
2058137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2059137cd93aSLisandro Dalcin }
2060137cd93aSLisandro Dalcin 
2061137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerPartition_PTScotch(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
2062137cd93aSLisandro Dalcin {
2063137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
2064137cd93aSLisandro Dalcin   MPI_Comm       comm       = PetscObjectComm((PetscObject)part);
2065137cd93aSLisandro Dalcin   PetscInt       nvtxs      = numVertices; /* The number of vertices in full graph */
2066137cd93aSLisandro Dalcin   PetscInt      *vtxdist;                  /* Distribution of vertices across processes */
2067137cd93aSLisandro Dalcin   PetscInt      *xadj       = start;       /* Start of edge list for each vertex */
2068137cd93aSLisandro Dalcin   PetscInt      *adjncy     = adjacency;   /* Edge lists for all vertices */
2069137cd93aSLisandro Dalcin   PetscInt      *vwgt       = NULL;        /* Vertex weights */
2070137cd93aSLisandro Dalcin   PetscInt      *adjwgt     = NULL;        /* Edge weights */
2071137cd93aSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
2072137cd93aSLisandro Dalcin   PetscMPIInt    size, rank, p;
2073137cd93aSLisandro Dalcin   PetscErrorCode ierr;
2074137cd93aSLisandro Dalcin 
2075137cd93aSLisandro Dalcin   PetscFunctionBegin;
2076137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
2077137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
207899b53901SStefano Zampini   ierr = PetscMalloc2(size+1,&vtxdist,PetscMax(nvtxs,1),&assignment);CHKERRQ(ierr);
2079137cd93aSLisandro Dalcin 
2080137cd93aSLisandro Dalcin   /* Calculate vertex distribution */
2081137cd93aSLisandro Dalcin   vtxdist[0] = 0;
2082137cd93aSLisandro Dalcin   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
2083137cd93aSLisandro Dalcin   for (p = 2; p <= size; ++p) {
2084137cd93aSLisandro Dalcin     vtxdist[p] += vtxdist[p-1];
2085137cd93aSLisandro Dalcin   }
2086137cd93aSLisandro Dalcin 
2087137cd93aSLisandro Dalcin   if (nparts == 1) {
2088580bdb30SBarry Smith     ierr = PetscArrayzero(assignment, nvtxs);CHKERRQ(ierr);
20898ef05d33SStefano Zampini   } else { /* Weight cells by dofs on cell by default */
2090137cd93aSLisandro Dalcin     PetscSection section;
20918ef05d33SStefano Zampini 
2092137cd93aSLisandro Dalcin     /* WARNING: Assumes that meshes with overlap have the overlapped cells at the end of the stratum. */
2093137cd93aSLisandro Dalcin     /* To do this properly, we should use the cell numbering created in DMPlexCreatePartitionerGraph. */
20948ef05d33SStefano Zampini     ierr = PetscMalloc1(PetscMax(nvtxs,1),&vwgt);CHKERRQ(ierr);
20958ef05d33SStefano Zampini     for (v = 0; v < PetscMax(nvtxs,1); ++v) vwgt[v] = 1;
20968ef05d33SStefano Zampini     ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
20978ef05d33SStefano Zampini     if (section) {
20988ef05d33SStefano Zampini       PetscInt vStart, vEnd, dof;
20998ef05d33SStefano Zampini       ierr = DMPlexGetHeightStratum(dm, part->height, &vStart, &vEnd);CHKERRQ(ierr);
21008ef05d33SStefano Zampini       for (v = vStart; v < vStart + numVertices; ++v) {
21018ef05d33SStefano Zampini         ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr);
21028ef05d33SStefano Zampini         vwgt[v-vStart] = PetscMax(dof, 1);
2103137cd93aSLisandro Dalcin       }
2104137cd93aSLisandro Dalcin     }
2105137cd93aSLisandro Dalcin     {
2106137cd93aSLisandro Dalcin       PetscPartitioner_PTScotch *pts = (PetscPartitioner_PTScotch *) part->data;
2107137cd93aSLisandro Dalcin       int                       strat = PTScotch_Strategy(pts->strategy);
2108137cd93aSLisandro Dalcin       double                    imbal = (double)pts->imbalance;
2109137cd93aSLisandro Dalcin 
2110137cd93aSLisandro Dalcin       for (p = 0; !vtxdist[p+1] && p < size; ++p);
2111137cd93aSLisandro Dalcin       if (vtxdist[p+1] == vtxdist[size]) {
2112137cd93aSLisandro Dalcin         if (rank == p) {
2113137cd93aSLisandro Dalcin           ierr = PTScotch_PartGraph_Seq(strat, imbal, nvtxs, xadj, adjncy, vwgt, adjwgt, nparts, assignment);CHKERRQ(ierr);
2114137cd93aSLisandro Dalcin         }
2115137cd93aSLisandro Dalcin       } else {
2116137cd93aSLisandro Dalcin         ierr = PTScotch_PartGraph_MPI(strat, imbal, vtxdist, xadj, adjncy, vwgt, adjwgt, nparts, assignment, comm);CHKERRQ(ierr);
2117137cd93aSLisandro Dalcin       }
2118137cd93aSLisandro Dalcin     }
2119137cd93aSLisandro Dalcin     ierr = PetscFree(vwgt);CHKERRQ(ierr);
2120137cd93aSLisandro Dalcin   }
2121137cd93aSLisandro Dalcin 
2122137cd93aSLisandro Dalcin   /* Convert to PetscSection+IS */
2123137cd93aSLisandro Dalcin   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
2124137cd93aSLisandro Dalcin   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
2125137cd93aSLisandro Dalcin   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
2126137cd93aSLisandro Dalcin   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
2127137cd93aSLisandro Dalcin   for (p = 0, i = 0; p < nparts; ++p) {
2128137cd93aSLisandro Dalcin     for (v = 0; v < nvtxs; ++v) {
2129137cd93aSLisandro Dalcin       if (assignment[v] == p) points[i++] = v;
2130137cd93aSLisandro Dalcin     }
2131137cd93aSLisandro Dalcin   }
2132137cd93aSLisandro Dalcin   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2133137cd93aSLisandro Dalcin   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2134137cd93aSLisandro Dalcin 
2135137cd93aSLisandro Dalcin   ierr = PetscFree2(vtxdist,assignment);CHKERRQ(ierr);
2136137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2137137cd93aSLisandro Dalcin #else
2138137cd93aSLisandro Dalcin   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-ptscotch.");
2139137cd93aSLisandro Dalcin #endif
2140137cd93aSLisandro Dalcin }
2141137cd93aSLisandro Dalcin 
2142137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerInitialize_PTScotch(PetscPartitioner part)
2143137cd93aSLisandro Dalcin {
2144137cd93aSLisandro Dalcin   PetscFunctionBegin;
2145074d466cSStefano Zampini   part->noGraph             = PETSC_FALSE;
2146137cd93aSLisandro Dalcin   part->ops->view           = PetscPartitionerView_PTScotch;
2147137cd93aSLisandro Dalcin   part->ops->destroy        = PetscPartitionerDestroy_PTScotch;
2148137cd93aSLisandro Dalcin   part->ops->partition      = PetscPartitionerPartition_PTScotch;
2149137cd93aSLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_PTScotch;
2150137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2151137cd93aSLisandro Dalcin }
2152137cd93aSLisandro Dalcin 
2153137cd93aSLisandro Dalcin /*MC
2154137cd93aSLisandro Dalcin   PETSCPARTITIONERPTSCOTCH = "ptscotch" - A PetscPartitioner object using the PT-Scotch library
2155137cd93aSLisandro Dalcin 
2156137cd93aSLisandro Dalcin   Level: intermediate
2157137cd93aSLisandro Dalcin 
2158137cd93aSLisandro Dalcin .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
2159137cd93aSLisandro Dalcin M*/
2160137cd93aSLisandro Dalcin 
2161137cd93aSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_PTScotch(PetscPartitioner part)
2162137cd93aSLisandro Dalcin {
2163137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p;
2164137cd93aSLisandro Dalcin   PetscErrorCode          ierr;
2165137cd93aSLisandro Dalcin 
2166137cd93aSLisandro Dalcin   PetscFunctionBegin;
2167137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
2168137cd93aSLisandro Dalcin   ierr = PetscNewLog(part, &p);CHKERRQ(ierr);
2169137cd93aSLisandro Dalcin   part->data = p;
2170137cd93aSLisandro Dalcin 
2171137cd93aSLisandro Dalcin   p->strategy  = 0;
2172137cd93aSLisandro Dalcin   p->imbalance = 0.01;
2173137cd93aSLisandro Dalcin 
2174137cd93aSLisandro Dalcin   ierr = PetscPartitionerInitialize_PTScotch(part);CHKERRQ(ierr);
2175137cd93aSLisandro Dalcin   ierr = PetscCitationsRegister(PTScotchPartitionerCitation, &PTScotchPartitionercite);CHKERRQ(ierr);
2176137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2177137cd93aSLisandro Dalcin }
2178137cd93aSLisandro Dalcin 
2179137cd93aSLisandro Dalcin 
21805680f57bSMatthew G. Knepley /*@
21815680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
21825680f57bSMatthew G. Knepley 
21835680f57bSMatthew G. Knepley   Not collective
21845680f57bSMatthew G. Knepley 
21855680f57bSMatthew G. Knepley   Input Parameter:
21865680f57bSMatthew G. Knepley . dm - The DM
21875680f57bSMatthew G. Knepley 
21885680f57bSMatthew G. Knepley   Output Parameter:
21895680f57bSMatthew G. Knepley . part - The PetscPartitioner
21905680f57bSMatthew G. Knepley 
21915680f57bSMatthew G. Knepley   Level: developer
21925680f57bSMatthew G. Knepley 
219398599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
219498599a47SLawrence Mitchell 
219598599a47SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerCreate()
21965680f57bSMatthew G. Knepley @*/
21975680f57bSMatthew G. Knepley PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
21985680f57bSMatthew G. Knepley {
21995680f57bSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex *) dm->data;
22005680f57bSMatthew G. Knepley 
22015680f57bSMatthew G. Knepley   PetscFunctionBegin;
22025680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22035680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
22045680f57bSMatthew G. Knepley   *part = mesh->partitioner;
22055680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
22065680f57bSMatthew G. Knepley }
22075680f57bSMatthew G. Knepley 
220871bb2955SLawrence Mitchell /*@
220971bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
221071bb2955SLawrence Mitchell 
2211d083f849SBarry Smith   logically collective on dm
221271bb2955SLawrence Mitchell 
221371bb2955SLawrence Mitchell   Input Parameters:
221471bb2955SLawrence Mitchell + dm - The DM
221571bb2955SLawrence Mitchell - part - The partitioner
221671bb2955SLawrence Mitchell 
221771bb2955SLawrence Mitchell   Level: developer
221871bb2955SLawrence Mitchell 
221971bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
222071bb2955SLawrence Mitchell 
222171bb2955SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate()
222271bb2955SLawrence Mitchell @*/
222371bb2955SLawrence Mitchell PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
222471bb2955SLawrence Mitchell {
222571bb2955SLawrence Mitchell   DM_Plex       *mesh = (DM_Plex *) dm->data;
222671bb2955SLawrence Mitchell   PetscErrorCode ierr;
222771bb2955SLawrence Mitchell 
222871bb2955SLawrence Mitchell   PetscFunctionBegin;
222971bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
223071bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
223171bb2955SLawrence Mitchell   ierr = PetscObjectReference((PetscObject)part);CHKERRQ(ierr);
223271bb2955SLawrence Mitchell   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
223371bb2955SLawrence Mitchell   mesh->partitioner = part;
223471bb2955SLawrence Mitchell   PetscFunctionReturn(0);
223571bb2955SLawrence Mitchell }
223671bb2955SLawrence Mitchell 
22378e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point)
22388e330a33SStefano Zampini {
22398e330a33SStefano Zampini   const PetscInt *cone;
22408e330a33SStefano Zampini   PetscInt       coneSize, c;
22418e330a33SStefano Zampini   PetscBool      missing;
22428e330a33SStefano Zampini   PetscErrorCode ierr;
22438e330a33SStefano Zampini 
22448e330a33SStefano Zampini   PetscFunctionBeginHot;
22458e330a33SStefano Zampini   ierr = PetscHSetIQueryAdd(ht, point, &missing);CHKERRQ(ierr);
22468e330a33SStefano Zampini   if (missing) {
22478e330a33SStefano Zampini     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
22488e330a33SStefano Zampini     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
22498e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
22508e330a33SStefano Zampini       ierr = DMPlexAddClosure_Private(dm, ht, cone[c]);CHKERRQ(ierr);
22518e330a33SStefano Zampini     }
22528e330a33SStefano Zampini   }
22538e330a33SStefano Zampini   PetscFunctionReturn(0);
22548e330a33SStefano Zampini }
22558e330a33SStefano Zampini 
22568e330a33SStefano Zampini PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
2257270bba0cSToby Isaac {
2258270bba0cSToby Isaac   PetscErrorCode ierr;
2259270bba0cSToby Isaac 
2260270bba0cSToby Isaac   PetscFunctionBegin;
22616a5a2ffdSToby Isaac   if (up) {
22626a5a2ffdSToby Isaac     PetscInt parent;
22636a5a2ffdSToby Isaac 
2264270bba0cSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
22656a5a2ffdSToby Isaac     if (parent != point) {
22666a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
22676a5a2ffdSToby Isaac 
2268270bba0cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
2269270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
2270270bba0cSToby Isaac         PetscInt cpoint = closure[2*i];
2271270bba0cSToby Isaac 
2272e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
22731b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
2274270bba0cSToby Isaac       }
2275270bba0cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
22766a5a2ffdSToby Isaac     }
22776a5a2ffdSToby Isaac   }
22786a5a2ffdSToby Isaac   if (down) {
22796a5a2ffdSToby Isaac     PetscInt numChildren;
22806a5a2ffdSToby Isaac     const PetscInt *children;
22816a5a2ffdSToby Isaac 
22826a5a2ffdSToby Isaac     ierr = DMPlexGetTreeChildren(dm,point,&numChildren,&children);CHKERRQ(ierr);
22836a5a2ffdSToby Isaac     if (numChildren) {
22846a5a2ffdSToby Isaac       PetscInt i;
22856a5a2ffdSToby Isaac 
22866a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
22876a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
22886a5a2ffdSToby Isaac 
2289e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
22901b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
22916a5a2ffdSToby Isaac       }
22926a5a2ffdSToby Isaac     }
22936a5a2ffdSToby Isaac   }
2294270bba0cSToby Isaac   PetscFunctionReturn(0);
2295270bba0cSToby Isaac }
2296270bba0cSToby Isaac 
22978e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point)
22988e330a33SStefano Zampini {
22998e330a33SStefano Zampini   PetscInt       parent;
23008e330a33SStefano Zampini   PetscErrorCode ierr;
2301825f8a23SLisandro Dalcin 
23028e330a33SStefano Zampini   PetscFunctionBeginHot;
23038e330a33SStefano Zampini   ierr = DMPlexGetTreeParent(dm, point, &parent,NULL);CHKERRQ(ierr);
23048e330a33SStefano Zampini   if (point != parent) {
23058e330a33SStefano Zampini     const PetscInt *cone;
23068e330a33SStefano Zampini     PetscInt       coneSize, c;
23078e330a33SStefano Zampini 
23088e330a33SStefano Zampini     ierr = DMPlexAddClosureTree_Up_Private(dm, ht, parent);CHKERRQ(ierr);
23098e330a33SStefano Zampini     ierr = DMPlexAddClosure_Private(dm, ht, parent);CHKERRQ(ierr);
23108e330a33SStefano Zampini     ierr = DMPlexGetCone(dm, parent, &cone);CHKERRQ(ierr);
23118e330a33SStefano Zampini     ierr = DMPlexGetConeSize(dm, parent, &coneSize);CHKERRQ(ierr);
23128e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
23138e330a33SStefano Zampini       const PetscInt cp = cone[c];
23148e330a33SStefano Zampini 
23158e330a33SStefano Zampini       ierr = DMPlexAddClosureTree_Up_Private(dm, ht, cp);CHKERRQ(ierr);
23168e330a33SStefano Zampini     }
23178e330a33SStefano Zampini   }
23188e330a33SStefano Zampini   PetscFunctionReturn(0);
23198e330a33SStefano Zampini }
23208e330a33SStefano Zampini 
23218e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point)
23228e330a33SStefano Zampini {
23238e330a33SStefano Zampini   PetscInt       i, numChildren;
23248e330a33SStefano Zampini   const PetscInt *children;
23258e330a33SStefano Zampini   PetscErrorCode ierr;
23268e330a33SStefano Zampini 
23278e330a33SStefano Zampini   PetscFunctionBeginHot;
23288e330a33SStefano Zampini   ierr = DMPlexGetTreeChildren(dm, point, &numChildren, &children);CHKERRQ(ierr);
23298e330a33SStefano Zampini   for (i = 0; i < numChildren; i++) {
23308e330a33SStefano Zampini     ierr = PetscHSetIAdd(ht, children[i]);CHKERRQ(ierr);
23318e330a33SStefano Zampini   }
23328e330a33SStefano Zampini   PetscFunctionReturn(0);
23338e330a33SStefano Zampini }
23348e330a33SStefano Zampini 
23358e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point)
23368e330a33SStefano Zampini {
23378e330a33SStefano Zampini   const PetscInt *cone;
23388e330a33SStefano Zampini   PetscInt       coneSize, c;
23398e330a33SStefano Zampini   PetscErrorCode ierr;
23408e330a33SStefano Zampini 
23418e330a33SStefano Zampini   PetscFunctionBeginHot;
23428e330a33SStefano Zampini   ierr = PetscHSetIAdd(ht, point);CHKERRQ(ierr);
23438e330a33SStefano Zampini   ierr = DMPlexAddClosureTree_Up_Private(dm, ht, point);CHKERRQ(ierr);
23448e330a33SStefano Zampini   ierr = DMPlexAddClosureTree_Down_Private(dm, ht, point);CHKERRQ(ierr);
23458e330a33SStefano Zampini   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
23468e330a33SStefano Zampini   ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
23478e330a33SStefano Zampini   for (c = 0; c < coneSize; c++) {
23488e330a33SStefano Zampini     ierr = DMPlexAddClosureTree_Private(dm, ht, cone[c]);CHKERRQ(ierr);
23498e330a33SStefano Zampini   }
23508e330a33SStefano Zampini   PetscFunctionReturn(0);
23518e330a33SStefano Zampini }
23528e330a33SStefano Zampini 
23538e330a33SStefano Zampini PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS)
2354825f8a23SLisandro Dalcin {
2355825f8a23SLisandro Dalcin   DM_Plex         *mesh = (DM_Plex *)dm->data;
23568e330a33SStefano Zampini   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
23578e330a33SStefano Zampini   PetscInt        nelems, *elems, off = 0, p;
2358825f8a23SLisandro Dalcin   PetscHSetI      ht;
2359825f8a23SLisandro Dalcin   PetscErrorCode  ierr;
2360825f8a23SLisandro Dalcin 
2361825f8a23SLisandro Dalcin   PetscFunctionBegin;
2362825f8a23SLisandro Dalcin   ierr = PetscHSetICreate(&ht);CHKERRQ(ierr);
2363825f8a23SLisandro Dalcin   ierr = PetscHSetIResize(ht, numPoints*16);CHKERRQ(ierr);
23648e330a33SStefano Zampini   if (!hasTree) {
23658e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
23668e330a33SStefano Zampini       ierr = DMPlexAddClosure_Private(dm, ht, points[p]);CHKERRQ(ierr);
23678e330a33SStefano Zampini     }
23688e330a33SStefano Zampini   } else {
23698e330a33SStefano Zampini #if 1
23708e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
23718e330a33SStefano Zampini       ierr = DMPlexAddClosureTree_Private(dm, ht, points[p]);CHKERRQ(ierr);
23728e330a33SStefano Zampini     }
23738e330a33SStefano Zampini #else
23748e330a33SStefano Zampini     PetscInt  *closure = NULL, closureSize, c;
2375825f8a23SLisandro Dalcin     for (p = 0; p < numPoints; ++p) {
2376825f8a23SLisandro Dalcin       ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2377825f8a23SLisandro Dalcin       for (c = 0; c < closureSize*2; c += 2) {
2378825f8a23SLisandro Dalcin         ierr = PetscHSetIAdd(ht, closure[c]);CHKERRQ(ierr);
2379825f8a23SLisandro Dalcin         if (hasTree) {ierr = DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE);CHKERRQ(ierr);}
2380825f8a23SLisandro Dalcin       }
2381825f8a23SLisandro Dalcin     }
2382825f8a23SLisandro Dalcin     if (closure) {ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure);CHKERRQ(ierr);}
23838e330a33SStefano Zampini #endif
23848e330a33SStefano Zampini   }
2385825f8a23SLisandro Dalcin   ierr = PetscHSetIGetSize(ht, &nelems);CHKERRQ(ierr);
2386825f8a23SLisandro Dalcin   ierr = PetscMalloc1(nelems, &elems);CHKERRQ(ierr);
2387825f8a23SLisandro Dalcin   ierr = PetscHSetIGetElems(ht, &off, elems);CHKERRQ(ierr);
2388825f8a23SLisandro Dalcin   ierr = PetscHSetIDestroy(&ht);CHKERRQ(ierr);
2389825f8a23SLisandro Dalcin   ierr = PetscSortInt(nelems, elems);CHKERRQ(ierr);
2390825f8a23SLisandro Dalcin   ierr = ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS);CHKERRQ(ierr);
2391825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
2392825f8a23SLisandro Dalcin }
2393825f8a23SLisandro Dalcin 
23945abbe4feSMichael Lange /*@
23955abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
23965abbe4feSMichael Lange 
23975abbe4feSMichael Lange   Input Parameters:
23985abbe4feSMichael Lange + dm     - The DM
23995abbe4feSMichael Lange - label  - DMLabel assinging ranks to remote roots
24005abbe4feSMichael Lange 
24015abbe4feSMichael Lange   Level: developer
24025abbe4feSMichael Lange 
240330b0ce1bSStefano Zampini .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
24045abbe4feSMichael Lange @*/
24055abbe4feSMichael Lange PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
24069ffc88e4SToby Isaac {
2407825f8a23SLisandro Dalcin   IS              rankIS,   pointIS, closureIS;
24085abbe4feSMichael Lange   const PetscInt *ranks,   *points;
2409825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
24109ffc88e4SToby Isaac   PetscErrorCode  ierr;
24119ffc88e4SToby Isaac 
24129ffc88e4SToby Isaac   PetscFunctionBegin;
24135abbe4feSMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
24145abbe4feSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
24155abbe4feSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
24165abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
24175abbe4feSMichael Lange     const PetscInt rank = ranks[r];
24185abbe4feSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
24195abbe4feSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
24205abbe4feSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
24218e330a33SStefano Zampini     ierr = DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS);CHKERRQ(ierr);
24225abbe4feSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
24235abbe4feSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2424825f8a23SLisandro Dalcin     ierr = DMLabelSetStratumIS(label, rank, closureIS);CHKERRQ(ierr);
2425825f8a23SLisandro Dalcin     ierr = ISDestroy(&closureIS);CHKERRQ(ierr);
24269ffc88e4SToby Isaac   }
24275abbe4feSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
24285abbe4feSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
24299ffc88e4SToby Isaac   PetscFunctionReturn(0);
24309ffc88e4SToby Isaac }
24319ffc88e4SToby Isaac 
243224d039d7SMichael Lange /*@
243324d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
243424d039d7SMichael Lange 
243524d039d7SMichael Lange   Input Parameters:
243624d039d7SMichael Lange + dm     - The DM
243724d039d7SMichael Lange - label  - DMLabel assinging ranks to remote roots
243824d039d7SMichael Lange 
243924d039d7SMichael Lange   Level: developer
244024d039d7SMichael Lange 
244124d039d7SMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
244224d039d7SMichael Lange @*/
244324d039d7SMichael Lange PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
244470034214SMatthew G. Knepley {
244524d039d7SMichael Lange   IS              rankIS,   pointIS;
244624d039d7SMichael Lange   const PetscInt *ranks,   *points;
244724d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
244824d039d7SMichael Lange   PetscInt       *adj = NULL;
244970034214SMatthew G. Knepley   PetscErrorCode  ierr;
245070034214SMatthew G. Knepley 
245170034214SMatthew G. Knepley   PetscFunctionBegin;
245224d039d7SMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
245324d039d7SMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
245424d039d7SMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
245524d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
245624d039d7SMichael Lange     const PetscInt rank = ranks[r];
245770034214SMatthew G. Knepley 
245824d039d7SMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
245924d039d7SMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
246024d039d7SMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
246170034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
246224d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
246324d039d7SMichael Lange       ierr = DMPlexGetAdjacency(dm, points[p], &adjSize, &adj);CHKERRQ(ierr);
246424d039d7SMichael Lange       for (a = 0; a < adjSize; ++a) {ierr = DMLabelSetValue(label, adj[a], rank);CHKERRQ(ierr);}
246570034214SMatthew G. Knepley     }
246624d039d7SMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
246724d039d7SMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
246870034214SMatthew G. Knepley   }
246924d039d7SMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
247024d039d7SMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
247124d039d7SMichael Lange   ierr = PetscFree(adj);CHKERRQ(ierr);
247224d039d7SMichael Lange   PetscFunctionReturn(0);
247370034214SMatthew G. Knepley }
247470034214SMatthew G. Knepley 
2475be200f8dSMichael Lange /*@
2476be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
2477be200f8dSMichael Lange 
2478be200f8dSMichael Lange   Input Parameters:
2479be200f8dSMichael Lange + dm     - The DM
2480be200f8dSMichael Lange - label  - DMLabel assinging ranks to remote roots
2481be200f8dSMichael Lange 
2482be200f8dSMichael Lange   Level: developer
2483be200f8dSMichael Lange 
2484be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
2485be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
2486be200f8dSMichael Lange 
2487be200f8dSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
2488be200f8dSMichael Lange @*/
2489be200f8dSMichael Lange PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
2490be200f8dSMichael Lange {
2491be200f8dSMichael Lange   MPI_Comm        comm;
2492be200f8dSMichael Lange   PetscMPIInt     rank;
2493be200f8dSMichael Lange   PetscSF         sfPoint;
24945d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
2495be200f8dSMichael Lange   IS              rankIS, pointIS;
2496be200f8dSMichael Lange   const PetscInt *ranks;
2497be200f8dSMichael Lange   PetscInt        numRanks, r;
2498be200f8dSMichael Lange   PetscErrorCode  ierr;
2499be200f8dSMichael Lange 
2500be200f8dSMichael Lange   PetscFunctionBegin;
2501be200f8dSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
2502be200f8dSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2503be200f8dSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
25045d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
25055d04f6ebSMichael Lange   ierr = DMLabelGather(label, sfPoint, &lblLeaves);CHKERRQ(ierr);
25065d04f6ebSMichael Lange   ierr = DMLabelGetValueIS(lblLeaves, &rankIS);CHKERRQ(ierr);
25075d04f6ebSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
25085d04f6ebSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
25095d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
25105d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
25115d04f6ebSMichael Lange     if (remoteRank == rank) continue;
25125d04f6ebSMichael Lange     ierr = DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS);CHKERRQ(ierr);
25135d04f6ebSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
25145d04f6ebSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
25155d04f6ebSMichael Lange   }
25165d04f6ebSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
25175d04f6ebSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
25185d04f6ebSMichael Lange   ierr = DMLabelDestroy(&lblLeaves);CHKERRQ(ierr);
2519be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
2520be200f8dSMichael Lange   ierr = DMLabelDistribute(label, sfPoint, &lblRoots);CHKERRQ(ierr);
2521be200f8dSMichael Lange   ierr = DMLabelGetValueIS(lblRoots, &rankIS);CHKERRQ(ierr);
2522be200f8dSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
2523be200f8dSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
2524be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
2525be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
2526be200f8dSMichael Lange     if (remoteRank == rank) continue;
2527be200f8dSMichael Lange     ierr = DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS);CHKERRQ(ierr);
2528be200f8dSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
2529be200f8dSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2530be200f8dSMichael Lange   }
2531be200f8dSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
2532be200f8dSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
2533be200f8dSMichael Lange   ierr = DMLabelDestroy(&lblRoots);CHKERRQ(ierr);
2534be200f8dSMichael Lange   PetscFunctionReturn(0);
2535be200f8dSMichael Lange }
2536be200f8dSMichael Lange 
25371fd9873aSMichael Lange /*@
25381fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
25391fd9873aSMichael Lange 
25401fd9873aSMichael Lange   Input Parameters:
25411fd9873aSMichael Lange + dm        - The DM
25421fd9873aSMichael Lange . rootLabel - DMLabel assinging ranks to local roots
25431fd9873aSMichael Lange . processSF - A star forest mapping into the local index on each remote rank
25441fd9873aSMichael Lange 
25451fd9873aSMichael Lange   Output Parameter:
25461fd9873aSMichael Lange - leafLabel - DMLabel assinging ranks to remote roots
25471fd9873aSMichael Lange 
25481fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
25491fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
25501fd9873aSMichael Lange 
25511fd9873aSMichael Lange   Level: developer
25521fd9873aSMichael Lange 
25531fd9873aSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
25541fd9873aSMichael Lange @*/
25551fd9873aSMichael Lange PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
25561fd9873aSMichael Lange {
25571fd9873aSMichael Lange   MPI_Comm           comm;
2558874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
2559874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
25601fd9873aSMichael Lange   PetscSF            sfPoint;
2561874ddda9SLisandro Dalcin   PetscSection       rootSection;
25621fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
25631fd9873aSMichael Lange   const PetscSFNode *remote;
25641fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
25651fd9873aSMichael Lange   IS                 valueIS;
2566874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
25671fd9873aSMichael Lange   PetscErrorCode     ierr;
25681fd9873aSMichael Lange 
25691fd9873aSMichael Lange   PetscFunctionBegin;
257030b0ce1bSStefano Zampini   ierr = PetscLogEventBegin(DMPLEX_PartLabelInvert,dm,0,0,0);CHKERRQ(ierr);
25711fd9873aSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
25721fd9873aSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
25739852e123SBarry Smith   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
25741fd9873aSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
25751fd9873aSMichael Lange 
25761fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
25771fd9873aSMichael Lange   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
25789852e123SBarry Smith   ierr = PetscSectionSetChart(rootSection, 0, size);CHKERRQ(ierr);
25791fd9873aSMichael Lange   ierr = DMLabelGetValueIS(rootLabel, &valueIS);CHKERRQ(ierr);
25801fd9873aSMichael Lange   ierr = ISGetLocalSize(valueIS, &numNeighbors);CHKERRQ(ierr);
25811fd9873aSMichael Lange   ierr = ISGetIndices(valueIS, &neighbors);CHKERRQ(ierr);
25821fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
25831fd9873aSMichael Lange     ierr = DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints);CHKERRQ(ierr);
25841fd9873aSMichael Lange     ierr = PetscSectionAddDof(rootSection, neighbors[n], numPoints);CHKERRQ(ierr);
25851fd9873aSMichael Lange   }
25861fd9873aSMichael Lange   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
2587874ddda9SLisandro Dalcin   ierr = PetscSectionGetStorageSize(rootSection, &rootSize);CHKERRQ(ierr);
2588874ddda9SLisandro Dalcin   ierr = PetscMalloc1(rootSize, &rootPoints);CHKERRQ(ierr);
25891fd9873aSMichael Lange   ierr = PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote);CHKERRQ(ierr);
25901fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
25911fd9873aSMichael Lange     IS              pointIS;
25921fd9873aSMichael Lange     const PetscInt *points;
25931fd9873aSMichael Lange 
25941fd9873aSMichael Lange     ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
25951fd9873aSMichael Lange     ierr = DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS);CHKERRQ(ierr);
25961fd9873aSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
25971fd9873aSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
25981fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
2599f8987ae8SMichael Lange       if (local) {ierr = PetscFindInt(points[p], nleaves, local, &l);CHKERRQ(ierr);}
2600f8987ae8SMichael Lange       else       {l = -1;}
26011fd9873aSMichael Lange       if (l >= 0) {rootPoints[off+p] = remote[l];}
26021fd9873aSMichael Lange       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
26031fd9873aSMichael Lange     }
26041fd9873aSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
26051fd9873aSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
26061fd9873aSMichael Lange   }
2607874ddda9SLisandro Dalcin 
2608874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
2609874ddda9SLisandro Dalcin   if (!processSF) {
2610874ddda9SLisandro Dalcin     PetscInt64  counter = 0;
2611874ddda9SLisandro Dalcin     PetscBool   locOverflow = PETSC_FALSE;
2612874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
2613874ddda9SLisandro Dalcin 
2614874ddda9SLisandro Dalcin     ierr = PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls);CHKERRQ(ierr);
2615874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
2616874ddda9SLisandro Dalcin       ierr = PetscSectionGetDof(rootSection, neighbors[n], &dof);CHKERRQ(ierr);
2617874ddda9SLisandro Dalcin       ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
2618874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
2619874ddda9SLisandro Dalcin       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2620874ddda9SLisandro Dalcin       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2621874ddda9SLisandro Dalcin #endif
2622874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt) dof;
2623874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt) off;
2624874ddda9SLisandro Dalcin     }
2625874ddda9SLisandro Dalcin     ierr = MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm);CHKERRQ(ierr);
2626874ddda9SLisandro Dalcin     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
2627874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
2628874ddda9SLisandro Dalcin     ierr = MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm);CHKERRQ(ierr);
2629874ddda9SLisandro Dalcin     if (!mpiOverflow) {
263094b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using Alltoallv for mesh distribution\n");CHKERRQ(ierr);
2631874ddda9SLisandro Dalcin       leafSize = (PetscInt) counter;
2632874ddda9SLisandro Dalcin       ierr = PetscMalloc1(leafSize, &leafPoints);CHKERRQ(ierr);
2633874ddda9SLisandro Dalcin       ierr = MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm);CHKERRQ(ierr);
2634874ddda9SLisandro Dalcin     }
2635874ddda9SLisandro Dalcin     ierr = PetscFree4(scounts, sdispls, rcounts, rdispls);CHKERRQ(ierr);
2636874ddda9SLisandro Dalcin   }
2637874ddda9SLisandro Dalcin 
2638874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
2639874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
2640874ddda9SLisandro Dalcin     PetscSF      procSF;
2641874ddda9SLisandro Dalcin     PetscSFNode  *remote;
2642874ddda9SLisandro Dalcin     PetscSection leafSection;
2643874ddda9SLisandro Dalcin 
2644874ddda9SLisandro Dalcin     if (processSF) {
264594b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using processSF for mesh distribution\n");CHKERRQ(ierr);
2646874ddda9SLisandro Dalcin       ierr = PetscObjectReference((PetscObject)processSF);CHKERRQ(ierr);
2647874ddda9SLisandro Dalcin       procSF = processSF;
2648874ddda9SLisandro Dalcin     } else {
264994b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using processSF for mesh distribution (MPI overflow)\n");CHKERRQ(ierr);
2650874ddda9SLisandro Dalcin       ierr = PetscMalloc1(size, &remote);CHKERRQ(ierr);
2651874ddda9SLisandro Dalcin       for (r = 0; r < size; ++r) { remote[r].rank  = r; remote[r].index = rank; }
2652874ddda9SLisandro Dalcin       ierr = PetscSFCreate(comm, &procSF);CHKERRQ(ierr);
2653874ddda9SLisandro Dalcin       ierr = PetscSFSetGraph(procSF, size, size, NULL, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
2654874ddda9SLisandro Dalcin     }
2655874ddda9SLisandro Dalcin 
2656874ddda9SLisandro Dalcin     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection);CHKERRQ(ierr);
26571fd9873aSMichael Lange     ierr = DMPlexDistributeData(dm, processSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints);CHKERRQ(ierr);
2658874ddda9SLisandro Dalcin     ierr = PetscSectionGetStorageSize(leafSection, &leafSize);CHKERRQ(ierr);
2659874ddda9SLisandro Dalcin     ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
2660874ddda9SLisandro Dalcin     ierr = PetscSFDestroy(&procSF);CHKERRQ(ierr);
2661874ddda9SLisandro Dalcin   }
2662874ddda9SLisandro Dalcin 
2663874ddda9SLisandro Dalcin   for (p = 0; p < leafSize; p++) {
26641fd9873aSMichael Lange     ierr = DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank);CHKERRQ(ierr);
26651fd9873aSMichael Lange   }
2666874ddda9SLisandro Dalcin 
2667874ddda9SLisandro Dalcin   ierr = ISRestoreIndices(valueIS, &neighbors);CHKERRQ(ierr);
2668874ddda9SLisandro Dalcin   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
26691fd9873aSMichael Lange   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
2670874ddda9SLisandro Dalcin   ierr = PetscFree(rootPoints);CHKERRQ(ierr);
26711fd9873aSMichael Lange   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
267230b0ce1bSStefano Zampini   ierr = PetscLogEventEnd(DMPLEX_PartLabelInvert,dm,0,0,0);CHKERRQ(ierr);
26731fd9873aSMichael Lange   PetscFunctionReturn(0);
26741fd9873aSMichael Lange }
26751fd9873aSMichael Lange 
2676aa3148a8SMichael Lange /*@
2677aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
2678aa3148a8SMichael Lange 
2679aa3148a8SMichael Lange   Input Parameters:
2680aa3148a8SMichael Lange + dm    - The DM
2681aa3148a8SMichael Lange . label - DMLabel assinging ranks to remote roots
2682aa3148a8SMichael Lange 
2683aa3148a8SMichael Lange   Output Parameter:
2684aa3148a8SMichael Lange - sf    - The star forest communication context encapsulating the defined mapping
2685aa3148a8SMichael Lange 
2686aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
2687aa3148a8SMichael Lange 
2688aa3148a8SMichael Lange   Level: developer
2689aa3148a8SMichael Lange 
269030b0ce1bSStefano Zampini .seealso: DMPlexDistribute(), DMPlexCreateOverlap()
2691aa3148a8SMichael Lange @*/
2692aa3148a8SMichael Lange PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
2693aa3148a8SMichael Lange {
26946e203dd9SStefano Zampini   PetscMPIInt     rank;
26956e203dd9SStefano Zampini   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
2696aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
26976e203dd9SStefano Zampini   IS              remoteRootIS, neighborsIS;
26986e203dd9SStefano Zampini   const PetscInt *remoteRoots, *neighbors;
2699aa3148a8SMichael Lange   PetscErrorCode ierr;
2700aa3148a8SMichael Lange 
2701aa3148a8SMichael Lange   PetscFunctionBegin;
270230b0ce1bSStefano Zampini   ierr = PetscLogEventBegin(DMPLEX_PartLabelCreateSF,dm,0,0,0);CHKERRQ(ierr);
270343f7d02bSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
2704aa3148a8SMichael Lange 
27056e203dd9SStefano Zampini   ierr = DMLabelGetValueIS(label, &neighborsIS);CHKERRQ(ierr);
27066e203dd9SStefano Zampini #if 0
27076e203dd9SStefano Zampini   {
27086e203dd9SStefano Zampini     IS is;
27096e203dd9SStefano Zampini     ierr = ISDuplicate(neighborsIS, &is);CHKERRQ(ierr);
27106e203dd9SStefano Zampini     ierr = ISSort(is);CHKERRQ(ierr);
27116e203dd9SStefano Zampini     ierr = ISDestroy(&neighborsIS);CHKERRQ(ierr);
27126e203dd9SStefano Zampini     neighborsIS = is;
27136e203dd9SStefano Zampini   }
27146e203dd9SStefano Zampini #endif
27156e203dd9SStefano Zampini   ierr = ISGetLocalSize(neighborsIS, &nNeighbors);CHKERRQ(ierr);
27166e203dd9SStefano Zampini   ierr = ISGetIndices(neighborsIS, &neighbors);CHKERRQ(ierr);
27176e203dd9SStefano Zampini   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
27186e203dd9SStefano Zampini     ierr = DMLabelGetStratumSize(label, neighbors[n], &numPoints);CHKERRQ(ierr);
2719aa3148a8SMichael Lange     numRemote += numPoints;
2720aa3148a8SMichael Lange   }
2721aa3148a8SMichael Lange   ierr = PetscMalloc1(numRemote, &remotePoints);CHKERRQ(ierr);
272243f7d02bSMichael Lange   /* Put owned points first */
272343f7d02bSMichael Lange   ierr = DMLabelGetStratumSize(label, rank, &numPoints);CHKERRQ(ierr);
272443f7d02bSMichael Lange   if (numPoints > 0) {
272543f7d02bSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &remoteRootIS);CHKERRQ(ierr);
272643f7d02bSMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
272743f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
272843f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
272943f7d02bSMichael Lange       remotePoints[idx].rank = rank;
273043f7d02bSMichael Lange       idx++;
273143f7d02bSMichael Lange     }
273243f7d02bSMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
273343f7d02bSMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
273443f7d02bSMichael Lange   }
273543f7d02bSMichael Lange   /* Now add remote points */
27366e203dd9SStefano Zampini   for (n = 0; n < nNeighbors; ++n) {
27376e203dd9SStefano Zampini     const PetscInt nn = neighbors[n];
27386e203dd9SStefano Zampini 
27396e203dd9SStefano Zampini     ierr = DMLabelGetStratumSize(label, nn, &numPoints);CHKERRQ(ierr);
27406e203dd9SStefano Zampini     if (nn == rank || numPoints <= 0) continue;
27416e203dd9SStefano Zampini     ierr = DMLabelGetStratumIS(label, nn, &remoteRootIS);CHKERRQ(ierr);
2742aa3148a8SMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
2743aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
2744aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
27456e203dd9SStefano Zampini       remotePoints[idx].rank = nn;
2746aa3148a8SMichael Lange       idx++;
2747aa3148a8SMichael Lange     }
2748aa3148a8SMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
2749aa3148a8SMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
2750aa3148a8SMichael Lange   }
2751aa3148a8SMichael Lange   ierr = PetscSFCreate(PetscObjectComm((PetscObject) dm), sf);CHKERRQ(ierr);
2752aa3148a8SMichael Lange   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2753aa3148a8SMichael Lange   ierr = PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
275430b0ce1bSStefano Zampini   ierr = PetscSFSetUp(*sf);CHKERRQ(ierr);
27556e203dd9SStefano Zampini   ierr = ISDestroy(&neighborsIS);CHKERRQ(ierr);
275630b0ce1bSStefano Zampini   ierr = PetscLogEventEnd(DMPLEX_PartLabelCreateSF,dm,0,0,0);CHKERRQ(ierr);
275770034214SMatthew G. Knepley   PetscFunctionReturn(0);
275870034214SMatthew G. Knepley }
2759cb87ef4cSFlorian Wechsung 
27606a3739e5SFlorian Wechsung /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
27616a3739e5SFlorian Wechsung  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
27626a3739e5SFlorian Wechsung  * them out in that case. */
27636a3739e5SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
27647a82c785SFlorian Wechsung /*@C
27657f57c1a4SFlorian Wechsung 
27667f57c1a4SFlorian Wechsung   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).
27677f57c1a4SFlorian Wechsung 
27687f57c1a4SFlorian Wechsung   Input parameters:
27697f57c1a4SFlorian Wechsung   + dm                - The DMPlex object.
27707f57c1a4SFlorian Wechsung   + n                 - The number of points.
27717f57c1a4SFlorian Wechsung   + pointsToRewrite   - The points in the SF whose ownership will change.
27727f57c1a4SFlorian Wechsung   + targetOwners      - New owner for each element in pointsToRewrite.
27737f57c1a4SFlorian Wechsung   + degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.
27747f57c1a4SFlorian Wechsung 
27757f57c1a4SFlorian Wechsung   Level: developer
27767f57c1a4SFlorian Wechsung 
27777f57c1a4SFlorian Wechsung @*/
27787f57c1a4SFlorian Wechsung static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
27797f57c1a4SFlorian Wechsung {
27807f57c1a4SFlorian Wechsung   PetscInt      ierr, pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
27817f57c1a4SFlorian Wechsung   PetscInt     *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
27827f57c1a4SFlorian Wechsung   PetscSFNode  *leafLocationsNew;
27837f57c1a4SFlorian Wechsung   const         PetscSFNode *iremote;
27847f57c1a4SFlorian Wechsung   const         PetscInt *ilocal;
27857f57c1a4SFlorian Wechsung   PetscBool    *isLeaf;
27867f57c1a4SFlorian Wechsung   PetscSF       sf;
27877f57c1a4SFlorian Wechsung   MPI_Comm      comm;
27885a30b08bSFlorian Wechsung   PetscMPIInt   rank, size;
27897f57c1a4SFlorian Wechsung 
27907f57c1a4SFlorian Wechsung   PetscFunctionBegin;
27917f57c1a4SFlorian Wechsung   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
27927f57c1a4SFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
27937f57c1a4SFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
27947f57c1a4SFlorian Wechsung   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
27957f57c1a4SFlorian Wechsung 
27967f57c1a4SFlorian Wechsung   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
27977f57c1a4SFlorian Wechsung   ierr = PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote); CHKERRQ(ierr);
27987f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isLeaf);CHKERRQ(ierr);
27997f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28007f57c1a4SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
28017f57c1a4SFlorian Wechsung   }
28027f57c1a4SFlorian Wechsung   for (i=0; i<nleafs; i++) {
28037f57c1a4SFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
28047f57c1a4SFlorian Wechsung   }
28057f57c1a4SFlorian Wechsung 
28067f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart+1, &cumSumDegrees);CHKERRQ(ierr);
28077f57c1a4SFlorian Wechsung   cumSumDegrees[0] = 0;
28087f57c1a4SFlorian Wechsung   for (i=1; i<=pEnd-pStart; i++) {
28097f57c1a4SFlorian Wechsung     cumSumDegrees[i] = cumSumDegrees[i-1] + degrees[i-1];
28107f57c1a4SFlorian Wechsung   }
28117f57c1a4SFlorian Wechsung   sumDegrees = cumSumDegrees[pEnd-pStart];
28127f57c1a4SFlorian Wechsung   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
28137f57c1a4SFlorian Wechsung 
28147f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(sumDegrees, &locationsOfLeafs);CHKERRQ(ierr);
28157f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &rankOnLeafs);CHKERRQ(ierr);
28167f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28177f57c1a4SFlorian Wechsung     rankOnLeafs[i] = rank;
28187f57c1a4SFlorian Wechsung   }
28197f57c1a4SFlorian Wechsung   ierr = PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);CHKERRQ(ierr);
28207f57c1a4SFlorian Wechsung   ierr = PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);CHKERRQ(ierr);
28217f57c1a4SFlorian Wechsung   ierr = PetscFree(rankOnLeafs);CHKERRQ(ierr);
28227f57c1a4SFlorian Wechsung 
28237f57c1a4SFlorian Wechsung   /* get the remote local points of my leaves */
28247f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs);CHKERRQ(ierr);
28257f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &points);CHKERRQ(ierr);
28267f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28277f57c1a4SFlorian Wechsung     points[i] = pStart+i;
28287f57c1a4SFlorian Wechsung   }
28297f57c1a4SFlorian Wechsung   ierr = PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs);CHKERRQ(ierr);
28307f57c1a4SFlorian Wechsung   ierr = PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs);CHKERRQ(ierr);
28317f57c1a4SFlorian Wechsung   ierr = PetscFree(points);CHKERRQ(ierr);
28327f57c1a4SFlorian Wechsung   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
28337f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &newOwners);CHKERRQ(ierr);
28347f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &newNumbers);CHKERRQ(ierr);
28357f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28367f57c1a4SFlorian Wechsung     newOwners[i] = -1;
28377f57c1a4SFlorian Wechsung     newNumbers[i] = -1;
28387f57c1a4SFlorian Wechsung   }
28397f57c1a4SFlorian Wechsung   {
28407f57c1a4SFlorian Wechsung     PetscInt oldNumber, newNumber, oldOwner, newOwner;
28417f57c1a4SFlorian Wechsung     for (i=0; i<n; i++) {
28427f57c1a4SFlorian Wechsung       oldNumber = pointsToRewrite[i];
28437f57c1a4SFlorian Wechsung       newNumber = -1;
28447f57c1a4SFlorian Wechsung       oldOwner = rank;
28457f57c1a4SFlorian Wechsung       newOwner = targetOwners[i];
28467f57c1a4SFlorian Wechsung       if (oldOwner == newOwner) {
28477f57c1a4SFlorian Wechsung         newNumber = oldNumber;
28487f57c1a4SFlorian Wechsung       } else {
28497f57c1a4SFlorian Wechsung         for (j=0; j<degrees[oldNumber]; j++) {
28507f57c1a4SFlorian Wechsung           if (locationsOfLeafs[cumSumDegrees[oldNumber]+j] == newOwner) {
28517f57c1a4SFlorian Wechsung             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber]+j];
28527f57c1a4SFlorian Wechsung             break;
28537f57c1a4SFlorian Wechsung           }
28547f57c1a4SFlorian Wechsung         }
28557f57c1a4SFlorian Wechsung       }
28567f57c1a4SFlorian Wechsung       if (newNumber == -1) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
28577f57c1a4SFlorian Wechsung 
28587f57c1a4SFlorian Wechsung       newOwners[oldNumber] = newOwner;
28597f57c1a4SFlorian Wechsung       newNumbers[oldNumber] = newNumber;
28607f57c1a4SFlorian Wechsung     }
28617f57c1a4SFlorian Wechsung   }
28627f57c1a4SFlorian Wechsung   ierr = PetscFree(cumSumDegrees);CHKERRQ(ierr);
28637f57c1a4SFlorian Wechsung   ierr = PetscFree(locationsOfLeafs);CHKERRQ(ierr);
28647f57c1a4SFlorian Wechsung   ierr = PetscFree(remoteLocalPointOfLeafs);CHKERRQ(ierr);
28657f57c1a4SFlorian Wechsung 
28667f57c1a4SFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners);CHKERRQ(ierr);
28677f57c1a4SFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners);CHKERRQ(ierr);
28687f57c1a4SFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers);CHKERRQ(ierr);
28697f57c1a4SFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers);CHKERRQ(ierr);
28707f57c1a4SFlorian Wechsung 
28717f57c1a4SFlorian Wechsung   /* Now count how many leafs we have on each processor. */
28727f57c1a4SFlorian Wechsung   leafCounter=0;
28737f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28747f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
28757f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
28767f57c1a4SFlorian Wechsung         leafCounter++;
28777f57c1a4SFlorian Wechsung       }
28787f57c1a4SFlorian Wechsung     } else {
28797f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
28807f57c1a4SFlorian Wechsung         leafCounter++;
28817f57c1a4SFlorian Wechsung       }
28827f57c1a4SFlorian Wechsung     }
28837f57c1a4SFlorian Wechsung   }
28847f57c1a4SFlorian Wechsung 
28857f57c1a4SFlorian Wechsung   /* Now set up the new sf by creating the leaf arrays */
28867f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(leafCounter, &leafsNew);CHKERRQ(ierr);
28877f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(leafCounter, &leafLocationsNew);CHKERRQ(ierr);
28887f57c1a4SFlorian Wechsung 
28897f57c1a4SFlorian Wechsung   leafCounter = 0;
28907f57c1a4SFlorian Wechsung   counter = 0;
28917f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28927f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
28937f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
28947f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
28957f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = newOwners[i];
28967f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = newNumbers[i];
28977f57c1a4SFlorian Wechsung         leafCounter++;
28987f57c1a4SFlorian Wechsung       }
28997f57c1a4SFlorian Wechsung     } else {
29007f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
29017f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
29027f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = iremote[counter].rank;
29037f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = iremote[counter].index;
29047f57c1a4SFlorian Wechsung         leafCounter++;
29057f57c1a4SFlorian Wechsung       }
29067f57c1a4SFlorian Wechsung     }
29077f57c1a4SFlorian Wechsung     if (isLeaf[i]) {
29087f57c1a4SFlorian Wechsung       counter++;
29097f57c1a4SFlorian Wechsung     }
29107f57c1a4SFlorian Wechsung   }
29117f57c1a4SFlorian Wechsung 
29127f57c1a4SFlorian Wechsung   ierr = PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
29137f57c1a4SFlorian Wechsung   ierr = PetscFree(newOwners);CHKERRQ(ierr);
29147f57c1a4SFlorian Wechsung   ierr = PetscFree(newNumbers);CHKERRQ(ierr);
29157f57c1a4SFlorian Wechsung   ierr = PetscFree(isLeaf);CHKERRQ(ierr);
29167f57c1a4SFlorian Wechsung   PetscFunctionReturn(0);
29177f57c1a4SFlorian Wechsung }
29187f57c1a4SFlorian Wechsung 
2919125d2a8fSFlorian Wechsung static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
2920125d2a8fSFlorian Wechsung {
29215a30b08bSFlorian Wechsung   PetscInt *distribution, min, max, sum, i, ierr;
29225a30b08bSFlorian Wechsung   PetscMPIInt rank, size;
2923125d2a8fSFlorian Wechsung   PetscFunctionBegin;
2924125d2a8fSFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
2925125d2a8fSFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2926125d2a8fSFlorian Wechsung   ierr = PetscCalloc1(size, &distribution);CHKERRQ(ierr);
2927125d2a8fSFlorian Wechsung   for (i=0; i<n; i++) {
2928125d2a8fSFlorian Wechsung     if (part) distribution[part[i]] += vtxwgt[skip*i];
2929125d2a8fSFlorian Wechsung     else distribution[rank] += vtxwgt[skip*i];
2930125d2a8fSFlorian Wechsung   }
2931125d2a8fSFlorian Wechsung   ierr = MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
2932125d2a8fSFlorian Wechsung   min = distribution[0];
2933125d2a8fSFlorian Wechsung   max = distribution[0];
2934125d2a8fSFlorian Wechsung   sum = distribution[0];
2935125d2a8fSFlorian Wechsung   for (i=1; i<size; i++) {
2936125d2a8fSFlorian Wechsung     if (distribution[i]<min) min=distribution[i];
2937125d2a8fSFlorian Wechsung     if (distribution[i]>max) max=distribution[i];
2938125d2a8fSFlorian Wechsung     sum += distribution[i];
2939125d2a8fSFlorian Wechsung   }
2940125d2a8fSFlorian Wechsung   ierr = PetscViewerASCIIPrintf(viewer, "Min: %D, Avg: %D, Max: %D, Balance: %f\n", min, sum/size, max, (max*1.*size)/sum);CHKERRQ(ierr);
2941125d2a8fSFlorian Wechsung   ierr = PetscFree(distribution);CHKERRQ(ierr);
2942125d2a8fSFlorian Wechsung   PetscFunctionReturn(0);
2943125d2a8fSFlorian Wechsung }
2944125d2a8fSFlorian Wechsung 
29456a3739e5SFlorian Wechsung #endif
29466a3739e5SFlorian Wechsung 
2947cb87ef4cSFlorian Wechsung /*@
29485dc86ac1SFlorian 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.
2949cb87ef4cSFlorian Wechsung 
2950cb87ef4cSFlorian Wechsung   Input parameters:
2951ed44d270SFlorian Wechsung   + dm               - The DMPlex object.
29527f57c1a4SFlorian Wechsung   + entityDepth      - depth of the entity to balance (0 -> balance vertices).
29537f57c1a4SFlorian Wechsung   + useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
29547f57c1a4SFlorian 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.
2955cb87ef4cSFlorian Wechsung 
29568b879b41SFlorian Wechsung   Output parameters:
29578b879b41SFlorian Wechsung   + success          - whether the graph partitioning was successful or not. If not, try useInitialGuess=True and parallel=True.
29588b879b41SFlorian Wechsung 
2959cb87ef4cSFlorian Wechsung   Level: user
2960cb87ef4cSFlorian Wechsung 
2961cb87ef4cSFlorian Wechsung @*/
2962cb87ef4cSFlorian Wechsung 
29638b879b41SFlorian Wechsung PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
2964cb87ef4cSFlorian Wechsung {
296541525646SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
2966cb87ef4cSFlorian Wechsung   PetscSF     sf;
29670faf6628SFlorian Wechsung   PetscInt    ierr, i, j, idx, jdx;
29687f57c1a4SFlorian Wechsung   PetscInt    eBegin, eEnd, nroots, nleafs, pStart, pEnd;
29697f57c1a4SFlorian Wechsung   const       PetscInt *degrees, *ilocal;
29707f57c1a4SFlorian Wechsung   const       PetscSFNode *iremote;
2971cb87ef4cSFlorian Wechsung   PetscBool   *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
2972cf818975SFlorian Wechsung   PetscInt    numExclusivelyOwned, numNonExclusivelyOwned;
2973cb87ef4cSFlorian Wechsung   PetscMPIInt rank, size;
29747f57c1a4SFlorian Wechsung   PetscInt    *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
29755dc86ac1SFlorian Wechsung   const       PetscInt *cumSumVertices;
2976cb87ef4cSFlorian Wechsung   PetscInt    offset, counter;
29777f57c1a4SFlorian Wechsung   PetscInt    lenadjncy;
2978cb87ef4cSFlorian Wechsung   PetscInt    *xadj, *adjncy, *vtxwgt;
2979cb87ef4cSFlorian Wechsung   PetscInt    lenxadj;
2980cb87ef4cSFlorian Wechsung   PetscInt    *adjwgt = NULL;
2981cb87ef4cSFlorian Wechsung   PetscInt    *part, *options;
2982cf818975SFlorian Wechsung   PetscInt    nparts, wgtflag, numflag, ncon, edgecut;
2983cb87ef4cSFlorian Wechsung   real_t      *ubvec;
2984cb87ef4cSFlorian Wechsung   PetscInt    *firstVertices, *renumbering;
2985cb87ef4cSFlorian Wechsung   PetscInt    failed, failedGlobal;
2986cb87ef4cSFlorian Wechsung   MPI_Comm    comm;
29874baf1206SFlorian Wechsung   Mat         A, Apre;
298812617df9SFlorian Wechsung   const char *prefix = NULL;
29897d197802SFlorian Wechsung   PetscViewer       viewer;
29907d197802SFlorian Wechsung   PetscViewerFormat format;
29915a30b08bSFlorian Wechsung   PetscLayout layout;
299212617df9SFlorian Wechsung 
299312617df9SFlorian Wechsung   PetscFunctionBegin;
29948b879b41SFlorian Wechsung   if (success) *success = PETSC_FALSE;
29957f57c1a4SFlorian Wechsung   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
29967f57c1a4SFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
29977f57c1a4SFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
29987f57c1a4SFlorian Wechsung   if (size==1) PetscFunctionReturn(0);
29997f57c1a4SFlorian Wechsung 
300041525646SFlorian Wechsung   ierr = PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
300141525646SFlorian Wechsung 
30025a30b08bSFlorian Wechsung   ierr = PetscOptionsGetViewer(comm,((PetscObject)dm)->options, prefix,"-dm_rebalance_partition_view",&viewer,&format,NULL);CHKERRQ(ierr);
30035dc86ac1SFlorian Wechsung   if (viewer) {
30045a30b08bSFlorian Wechsung     ierr = PetscViewerPushFormat(viewer,format);CHKERRQ(ierr);
30057d197802SFlorian Wechsung   }
30067d197802SFlorian Wechsung 
3007ed44d270SFlorian Wechsung   /* Figure out all points in the plex that we are interested in balancing. */
3008d5528e35SFlorian Wechsung   ierr = DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd);CHKERRQ(ierr);
3009cb87ef4cSFlorian Wechsung   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3010cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &toBalance);CHKERRQ(ierr);
3011cf818975SFlorian Wechsung 
3012cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
30135a7e692eSFlorian Wechsung     toBalance[i] = (PetscBool)(i-pStart>=eBegin && i-pStart<eEnd);
3014cb87ef4cSFlorian Wechsung   }
3015cb87ef4cSFlorian Wechsung 
3016cf818975SFlorian Wechsung   /* There are three types of points:
3017cf818975SFlorian Wechsung    * exclusivelyOwned: points that are owned by this process and only seen by this process
3018cf818975SFlorian Wechsung    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
3019cf818975SFlorian Wechsung    * leaf: a point that is seen by this process but owned by a different process
3020cf818975SFlorian Wechsung    */
3021cb87ef4cSFlorian Wechsung   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
3022cb87ef4cSFlorian Wechsung   ierr = PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote); CHKERRQ(ierr);
3023cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isLeaf);CHKERRQ(ierr);
3024cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isNonExclusivelyOwned);CHKERRQ(ierr);
3025cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isExclusivelyOwned);CHKERRQ(ierr);
3026cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
3027cb87ef4cSFlorian Wechsung     isNonExclusivelyOwned[i] = PETSC_FALSE;
3028cb87ef4cSFlorian Wechsung     isExclusivelyOwned[i] = PETSC_FALSE;
3029cf818975SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
3030cb87ef4cSFlorian Wechsung   }
3031cf818975SFlorian Wechsung 
3032cf818975SFlorian Wechsung   /* start by marking all the leafs */
3033cb87ef4cSFlorian Wechsung   for (i=0; i<nleafs; i++) {
3034cb87ef4cSFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
3035cb87ef4cSFlorian Wechsung   }
3036cb87ef4cSFlorian Wechsung 
3037cf818975SFlorian Wechsung   /* for an owned point, we can figure out whether another processor sees it or
3038cf818975SFlorian Wechsung    * not by calculating its degree */
30397f57c1a4SFlorian Wechsung   ierr = PetscSFComputeDegreeBegin(sf, &degrees);CHKERRQ(ierr);
30407f57c1a4SFlorian Wechsung   ierr = PetscSFComputeDegreeEnd(sf, &degrees);CHKERRQ(ierr);
3041cf818975SFlorian Wechsung 
3042cb87ef4cSFlorian Wechsung   numExclusivelyOwned = 0;
3043cb87ef4cSFlorian Wechsung   numNonExclusivelyOwned = 0;
3044cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
3045cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
30467f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
3047cb87ef4cSFlorian Wechsung         isNonExclusivelyOwned[i] = PETSC_TRUE;
3048cb87ef4cSFlorian Wechsung         numNonExclusivelyOwned += 1;
3049cb87ef4cSFlorian Wechsung       } else {
3050cb87ef4cSFlorian Wechsung         if (!isLeaf[i]) {
3051cb87ef4cSFlorian Wechsung           isExclusivelyOwned[i] = PETSC_TRUE;
3052cb87ef4cSFlorian Wechsung           numExclusivelyOwned += 1;
3053cb87ef4cSFlorian Wechsung         }
3054cb87ef4cSFlorian Wechsung       }
3055cb87ef4cSFlorian Wechsung     }
3056cb87ef4cSFlorian Wechsung   }
3057cb87ef4cSFlorian Wechsung 
3058cf818975SFlorian Wechsung   /* We are going to build a graph with one vertex per core representing the
3059cf818975SFlorian Wechsung    * exclusively owned points and then one vertex per nonExclusively owned
3060cf818975SFlorian Wechsung    * point. */
3061cb87ef4cSFlorian Wechsung 
30625dc86ac1SFlorian Wechsung   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
30635dc86ac1SFlorian Wechsung   ierr = PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned);CHKERRQ(ierr);
30645dc86ac1SFlorian Wechsung   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
30655dc86ac1SFlorian Wechsung   ierr = PetscLayoutGetRanges(layout, &cumSumVertices);CHKERRQ(ierr);
30665dc86ac1SFlorian Wechsung 
3067cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &globalNumbersOfLocalOwnedVertices);CHKERRQ(ierr);
3068cb87ef4cSFlorian Wechsung   offset = cumSumVertices[rank];
3069cb87ef4cSFlorian Wechsung   counter = 0;
3070cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
3071cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
30727f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
3073cb87ef4cSFlorian Wechsung         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
3074cb87ef4cSFlorian Wechsung         counter++;
3075cb87ef4cSFlorian Wechsung       }
3076cb87ef4cSFlorian Wechsung     }
3077cb87ef4cSFlorian Wechsung   }
3078cb87ef4cSFlorian Wechsung 
3079cb87ef4cSFlorian Wechsung   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
3080cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &leafGlobalNumbers);CHKERRQ(ierr);
3081cb87ef4cSFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers);CHKERRQ(ierr);
3082cb87ef4cSFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers);CHKERRQ(ierr);
3083cb87ef4cSFlorian Wechsung 
30840faf6628SFlorian Wechsung   /* Now start building the data structure for ParMETIS */
3085cb87ef4cSFlorian Wechsung 
30864baf1206SFlorian Wechsung   ierr = MatCreate(comm, &Apre);CHKERRQ(ierr);
30874baf1206SFlorian Wechsung   ierr = MatSetType(Apre, MATPREALLOCATOR);CHKERRQ(ierr);
30884baf1206SFlorian Wechsung   ierr = MatSetSizes(Apre, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);CHKERRQ(ierr);
30894baf1206SFlorian Wechsung   ierr = MatSetUp(Apre);CHKERRQ(ierr);
30908c9a1619SFlorian Wechsung 
30918c9a1619SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
30928c9a1619SFlorian Wechsung     if (toBalance[i]) {
30930faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
30940faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
30950faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
30960faf6628SFlorian Wechsung       else continue;
30970faf6628SFlorian Wechsung       ierr = MatSetValue(Apre, idx, jdx, 1, INSERT_VALUES);CHKERRQ(ierr);
30980faf6628SFlorian Wechsung       ierr = MatSetValue(Apre, jdx, idx, 1, INSERT_VALUES);CHKERRQ(ierr);
30994baf1206SFlorian Wechsung     }
31004baf1206SFlorian Wechsung   }
31014baf1206SFlorian Wechsung 
31024baf1206SFlorian Wechsung   ierr = MatAssemblyBegin(Apre, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
31034baf1206SFlorian Wechsung   ierr = MatAssemblyEnd(Apre, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
31044baf1206SFlorian Wechsung 
31054baf1206SFlorian Wechsung   ierr = MatCreate(comm, &A);CHKERRQ(ierr);
31064baf1206SFlorian Wechsung   ierr = MatSetType(A, MATMPIAIJ);CHKERRQ(ierr);
31074baf1206SFlorian Wechsung   ierr = MatSetSizes(A, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);CHKERRQ(ierr);
31084baf1206SFlorian Wechsung   ierr = MatPreallocatorPreallocate(Apre, PETSC_FALSE, A);CHKERRQ(ierr);
31094baf1206SFlorian Wechsung   ierr = MatDestroy(&Apre);CHKERRQ(ierr);
31104baf1206SFlorian Wechsung 
31114baf1206SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
31124baf1206SFlorian Wechsung     if (toBalance[i]) {
31130faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
31140faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
31150faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
31160faf6628SFlorian Wechsung       else continue;
31170faf6628SFlorian Wechsung       ierr = MatSetValue(A, idx, jdx, 1, INSERT_VALUES);CHKERRQ(ierr);
31180faf6628SFlorian Wechsung       ierr = MatSetValue(A, jdx, idx, 1, INSERT_VALUES);CHKERRQ(ierr);
31190941debbSFlorian Wechsung     }
31200941debbSFlorian Wechsung   }
31218c9a1619SFlorian Wechsung 
31228c9a1619SFlorian Wechsung   ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
31238c9a1619SFlorian Wechsung   ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
31244baf1206SFlorian Wechsung   ierr = PetscFree(leafGlobalNumbers);CHKERRQ(ierr);
31254baf1206SFlorian Wechsung   ierr = PetscFree(globalNumbersOfLocalOwnedVertices);CHKERRQ(ierr);
31264baf1206SFlorian Wechsung 
312741525646SFlorian Wechsung   nparts = size;
312841525646SFlorian Wechsung   wgtflag = 2;
312941525646SFlorian Wechsung   numflag = 0;
313041525646SFlorian Wechsung   ncon = 2;
313141525646SFlorian Wechsung   real_t *tpwgts;
313241525646SFlorian Wechsung   ierr = PetscMalloc1(ncon * nparts, &tpwgts);CHKERRQ(ierr);
313341525646SFlorian Wechsung   for (i=0; i<ncon*nparts; i++) {
313441525646SFlorian Wechsung     tpwgts[i] = 1./(nparts);
313541525646SFlorian Wechsung   }
313641525646SFlorian Wechsung 
313741525646SFlorian Wechsung   ierr = PetscMalloc1(ncon, &ubvec);CHKERRQ(ierr);
313841525646SFlorian Wechsung   ubvec[0] = 1.01;
31395a30b08bSFlorian Wechsung   ubvec[1] = 1.01;
31408c9a1619SFlorian Wechsung   lenadjncy = 0;
31418c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
31428c9a1619SFlorian Wechsung     PetscInt temp=0;
31438c9a1619SFlorian Wechsung     ierr = MatGetRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);CHKERRQ(ierr);
31448c9a1619SFlorian Wechsung     lenadjncy += temp;
31458c9a1619SFlorian Wechsung     ierr = MatRestoreRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);CHKERRQ(ierr);
31468c9a1619SFlorian Wechsung   }
31478c9a1619SFlorian Wechsung   ierr = PetscMalloc1(lenadjncy, &adjncy);CHKERRQ(ierr);
31487407ba93SFlorian Wechsung   lenxadj = 2 + numNonExclusivelyOwned;
31490941debbSFlorian Wechsung   ierr = PetscMalloc1(lenxadj, &xadj);CHKERRQ(ierr);
31500941debbSFlorian Wechsung   xadj[0] = 0;
31518c9a1619SFlorian Wechsung   counter = 0;
31528c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
31532953a68cSFlorian Wechsung     PetscInt        temp=0;
31542953a68cSFlorian Wechsung     const PetscInt *cols;
31558c9a1619SFlorian Wechsung     ierr = MatGetRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);CHKERRQ(ierr);
3156580bdb30SBarry Smith     ierr = PetscArraycpy(&adjncy[counter], cols, temp);CHKERRQ(ierr);
31578c9a1619SFlorian Wechsung     counter += temp;
31580941debbSFlorian Wechsung     xadj[i+1] = counter;
31598c9a1619SFlorian Wechsung     ierr = MatRestoreRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);CHKERRQ(ierr);
31608c9a1619SFlorian Wechsung   }
31618c9a1619SFlorian Wechsung 
3162cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(cumSumVertices[rank+1]-cumSumVertices[rank], &part);CHKERRQ(ierr);
316341525646SFlorian Wechsung   ierr = PetscMalloc1(ncon*(1 + numNonExclusivelyOwned), &vtxwgt);CHKERRQ(ierr);
316441525646SFlorian Wechsung   vtxwgt[0] = numExclusivelyOwned;
316541525646SFlorian Wechsung   if (ncon>1) vtxwgt[1] = 1;
316641525646SFlorian Wechsung   for (i=0; i<numNonExclusivelyOwned; i++) {
316741525646SFlorian Wechsung     vtxwgt[ncon*(i+1)] = 1;
316841525646SFlorian Wechsung     if (ncon>1) vtxwgt[ncon*(i+1)+1] = 0;
316941525646SFlorian Wechsung   }
31708c9a1619SFlorian Wechsung 
31715dc86ac1SFlorian Wechsung   if (viewer) {
31727d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %D on interface of mesh distribution.\n", entityDepth);CHKERRQ(ierr);
31737d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %D\n", cumSumVertices[size]);CHKERRQ(ierr);
317412617df9SFlorian Wechsung   }
317541525646SFlorian Wechsung   if (parallel) {
31765a30b08bSFlorian Wechsung     ierr = PetscMalloc1(4, &options);CHKERRQ(ierr);
31775a30b08bSFlorian Wechsung     options[0] = 1;
31785a30b08bSFlorian Wechsung     options[1] = 0; /* Verbosity */
31795a30b08bSFlorian Wechsung     options[2] = 0; /* Seed */
31805a30b08bSFlorian Wechsung     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
31815dc86ac1SFlorian Wechsung     if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n");CHKERRQ(ierr); }
31828c9a1619SFlorian Wechsung     if (useInitialGuess) {
31835dc86ac1SFlorian Wechsung       if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n");CHKERRQ(ierr); }
31848c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_RefineKway");
31855dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_RefineKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
318606b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
31878c9a1619SFlorian Wechsung       PetscStackPop;
31888c9a1619SFlorian Wechsung     } else {
31898c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_PartKway");
31905dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_PartKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
31918c9a1619SFlorian Wechsung       PetscStackPop;
319206b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
31938c9a1619SFlorian Wechsung     }
3194ef74bcceSFlorian Wechsung     ierr = PetscFree(options);CHKERRQ(ierr);
319541525646SFlorian Wechsung   } else {
31965dc86ac1SFlorian Wechsung     if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n");CHKERRQ(ierr); }
319741525646SFlorian Wechsung     Mat As;
319841525646SFlorian Wechsung     PetscInt numRows;
319941525646SFlorian Wechsung     PetscInt *partGlobal;
320041525646SFlorian Wechsung     ierr = MatCreateRedundantMatrix(A, size, MPI_COMM_NULL, MAT_INITIAL_MATRIX, &As);CHKERRQ(ierr);
3201cb87ef4cSFlorian Wechsung 
320241525646SFlorian Wechsung     PetscInt *numExclusivelyOwnedAll;
320341525646SFlorian Wechsung     ierr = PetscMalloc1(size, &numExclusivelyOwnedAll);CHKERRQ(ierr);
320441525646SFlorian Wechsung     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
32052953a68cSFlorian Wechsung     ierr = MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,numExclusivelyOwnedAll,1,MPIU_INT,comm);CHKERRQ(ierr);
3206cb87ef4cSFlorian Wechsung 
320741525646SFlorian Wechsung     ierr = MatGetSize(As, &numRows, NULL);CHKERRQ(ierr);
320841525646SFlorian Wechsung     ierr = PetscMalloc1(numRows, &partGlobal);CHKERRQ(ierr);
32095dc86ac1SFlorian Wechsung     if (!rank) {
321041525646SFlorian Wechsung       PetscInt *adjncy_g, *xadj_g, *vtxwgt_g;
321141525646SFlorian Wechsung       lenadjncy = 0;
321241525646SFlorian Wechsung 
321341525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
321441525646SFlorian Wechsung         PetscInt temp=0;
321541525646SFlorian Wechsung         ierr = MatGetRow(As, i, &temp, NULL, NULL);CHKERRQ(ierr);
321641525646SFlorian Wechsung         lenadjncy += temp;
321741525646SFlorian Wechsung         ierr = MatRestoreRow(As, i, &temp, NULL, NULL);CHKERRQ(ierr);
321841525646SFlorian Wechsung       }
321941525646SFlorian Wechsung       ierr = PetscMalloc1(lenadjncy, &adjncy_g);CHKERRQ(ierr);
322041525646SFlorian Wechsung       lenxadj = 1 + numRows;
322141525646SFlorian Wechsung       ierr = PetscMalloc1(lenxadj, &xadj_g);CHKERRQ(ierr);
322241525646SFlorian Wechsung       xadj_g[0] = 0;
322341525646SFlorian Wechsung       counter = 0;
322441525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
32252953a68cSFlorian Wechsung         PetscInt        temp=0;
32262953a68cSFlorian Wechsung         const PetscInt *cols;
322741525646SFlorian Wechsung         ierr = MatGetRow(As, i, &temp, &cols, NULL);CHKERRQ(ierr);
3228580bdb30SBarry Smith         ierr = PetscArraycpy(&adjncy_g[counter], cols, temp);CHKERRQ(ierr);
322941525646SFlorian Wechsung         counter += temp;
323041525646SFlorian Wechsung         xadj_g[i+1] = counter;
323141525646SFlorian Wechsung         ierr = MatRestoreRow(As, i, &temp, &cols, NULL);CHKERRQ(ierr);
323241525646SFlorian Wechsung       }
323341525646SFlorian Wechsung       ierr = PetscMalloc1(2*numRows, &vtxwgt_g);CHKERRQ(ierr);
323441525646SFlorian Wechsung       for (i=0; i<size; i++){
323541525646SFlorian Wechsung         vtxwgt_g[ncon*cumSumVertices[i]] = numExclusivelyOwnedAll[i];
323641525646SFlorian Wechsung         if (ncon>1) vtxwgt_g[ncon*cumSumVertices[i]+1] = 1;
323741525646SFlorian Wechsung         for (j=cumSumVertices[i]+1; j<cumSumVertices[i+1]; j++) {
323841525646SFlorian Wechsung           vtxwgt_g[ncon*j] = 1;
323941525646SFlorian Wechsung           if (ncon>1) vtxwgt_g[2*j+1] = 0;
324041525646SFlorian Wechsung         }
324141525646SFlorian Wechsung       }
324241525646SFlorian Wechsung       ierr = PetscMalloc1(64, &options);CHKERRQ(ierr);
324341525646SFlorian Wechsung       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
324406b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
324541525646SFlorian Wechsung       options[METIS_OPTION_CONTIG] = 1;
324641525646SFlorian Wechsung       PetscStackPush("METIS_PartGraphKway");
324706b3913eSFlorian Wechsung       ierr = METIS_PartGraphKway(&numRows, &ncon, xadj_g, adjncy_g, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
324841525646SFlorian Wechsung       PetscStackPop;
324906b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
3250ef74bcceSFlorian Wechsung       ierr = PetscFree(options);CHKERRQ(ierr);
325141525646SFlorian Wechsung       ierr = PetscFree(xadj_g);CHKERRQ(ierr);
325241525646SFlorian Wechsung       ierr = PetscFree(adjncy_g);CHKERRQ(ierr);
325341525646SFlorian Wechsung       ierr = PetscFree(vtxwgt_g);CHKERRQ(ierr);
325441525646SFlorian Wechsung     }
325541525646SFlorian Wechsung     ierr = PetscFree(numExclusivelyOwnedAll);CHKERRQ(ierr);
325641525646SFlorian Wechsung 
32575dc86ac1SFlorian Wechsung     /* Now scatter the parts array. */
32585dc86ac1SFlorian Wechsung     {
325981a13b52SFlorian Wechsung       PetscMPIInt *counts, *mpiCumSumVertices;
32605dc86ac1SFlorian Wechsung       ierr = PetscMalloc1(size, &counts);CHKERRQ(ierr);
326181a13b52SFlorian Wechsung       ierr = PetscMalloc1(size+1, &mpiCumSumVertices);CHKERRQ(ierr);
32625dc86ac1SFlorian Wechsung       for(i=0; i<size; i++) {
326381a13b52SFlorian Wechsung         ierr = PetscMPIIntCast(cumSumVertices[i+1] - cumSumVertices[i], &(counts[i]));CHKERRQ(ierr);
326441525646SFlorian Wechsung       }
326581a13b52SFlorian Wechsung       for(i=0; i<=size; i++) {
326681a13b52SFlorian Wechsung         ierr = PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i]));CHKERRQ(ierr);
326781a13b52SFlorian Wechsung       }
326881a13b52SFlorian Wechsung       ierr = MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm);CHKERRQ(ierr);
32695dc86ac1SFlorian Wechsung       ierr = PetscFree(counts);CHKERRQ(ierr);
327081a13b52SFlorian Wechsung       ierr = PetscFree(mpiCumSumVertices);CHKERRQ(ierr);
32715dc86ac1SFlorian Wechsung     }
32725dc86ac1SFlorian Wechsung 
327341525646SFlorian Wechsung     ierr = PetscFree(partGlobal);CHKERRQ(ierr);
32742953a68cSFlorian Wechsung     ierr = MatDestroy(&As);CHKERRQ(ierr);
327541525646SFlorian Wechsung   }
3276cb87ef4cSFlorian Wechsung 
32772953a68cSFlorian Wechsung   ierr = MatDestroy(&A);CHKERRQ(ierr);
3278cb87ef4cSFlorian Wechsung   ierr = PetscFree(ubvec);CHKERRQ(ierr);
3279cb87ef4cSFlorian Wechsung   ierr = PetscFree(tpwgts);CHKERRQ(ierr);
3280cb87ef4cSFlorian Wechsung 
3281cb87ef4cSFlorian Wechsung   /* Now rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
3282cb87ef4cSFlorian Wechsung 
3283cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(size, &firstVertices);CHKERRQ(ierr);
3284cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(size, &renumbering);CHKERRQ(ierr);
3285cb87ef4cSFlorian Wechsung   firstVertices[rank] = part[0];
32862953a68cSFlorian Wechsung   ierr = MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,firstVertices,1,MPIU_INT,comm);CHKERRQ(ierr);
3287cb87ef4cSFlorian Wechsung   for (i=0; i<size; i++) {
3288cb87ef4cSFlorian Wechsung     renumbering[firstVertices[i]] = i;
3289cb87ef4cSFlorian Wechsung   }
3290cb87ef4cSFlorian Wechsung   for (i=0; i<cumSumVertices[rank+1]-cumSumVertices[rank]; i++) {
3291cb87ef4cSFlorian Wechsung     part[i] = renumbering[part[i]];
3292cb87ef4cSFlorian Wechsung   }
3293cb87ef4cSFlorian Wechsung   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
3294cb87ef4cSFlorian Wechsung   failed = (PetscInt)(part[0] != rank);
32952953a68cSFlorian Wechsung   ierr = MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
3296cb87ef4cSFlorian Wechsung 
32977f57c1a4SFlorian Wechsung   ierr = PetscFree(firstVertices);CHKERRQ(ierr);
32987f57c1a4SFlorian Wechsung   ierr = PetscFree(renumbering);CHKERRQ(ierr);
32997f57c1a4SFlorian Wechsung 
3300cb87ef4cSFlorian Wechsung   if (failedGlobal > 0) {
33017f57c1a4SFlorian Wechsung     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
33027f57c1a4SFlorian Wechsung     ierr = PetscFree(xadj);CHKERRQ(ierr);
33037f57c1a4SFlorian Wechsung     ierr = PetscFree(adjncy);CHKERRQ(ierr);
33047f57c1a4SFlorian Wechsung     ierr = PetscFree(vtxwgt);CHKERRQ(ierr);
33057f57c1a4SFlorian Wechsung     ierr = PetscFree(toBalance);CHKERRQ(ierr);
33067f57c1a4SFlorian Wechsung     ierr = PetscFree(isLeaf);CHKERRQ(ierr);
33077f57c1a4SFlorian Wechsung     ierr = PetscFree(isNonExclusivelyOwned);CHKERRQ(ierr);
33087f57c1a4SFlorian Wechsung     ierr = PetscFree(isExclusivelyOwned);CHKERRQ(ierr);
33097f57c1a4SFlorian Wechsung     ierr = PetscFree(part);CHKERRQ(ierr);
33107f57c1a4SFlorian Wechsung     if (viewer) {
331106b3913eSFlorian Wechsung       ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
331206b3913eSFlorian Wechsung       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
33137f57c1a4SFlorian Wechsung     }
33147f57c1a4SFlorian Wechsung     ierr = PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
33158b879b41SFlorian Wechsung     PetscFunctionReturn(0);
3316cb87ef4cSFlorian Wechsung   }
3317cb87ef4cSFlorian Wechsung 
33187407ba93SFlorian Wechsung   /*Let's check how well we did distributing points*/
33195dc86ac1SFlorian Wechsung   if (viewer) {
33207d197802SFlorian 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);
3321125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Initial.     ");CHKERRQ(ierr);
3322125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, NULL, viewer);CHKERRQ(ierr);
3323125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Rebalanced.  ");CHKERRQ(ierr);
3324125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);CHKERRQ(ierr);
33257407ba93SFlorian Wechsung   }
33267407ba93SFlorian Wechsung 
3327cb87ef4cSFlorian Wechsung   /* Now check that every vertex is owned by a process that it is actually connected to. */
332841525646SFlorian Wechsung   for (i=1; i<=numNonExclusivelyOwned; i++) {
3329cb87ef4cSFlorian Wechsung     PetscInt loc = 0;
333041525646SFlorian Wechsung     ierr = PetscFindInt(cumSumVertices[part[i]], xadj[i+1]-xadj[i], &adjncy[xadj[i]], &loc);CHKERRQ(ierr);
33317407ba93SFlorian Wechsung     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
3332cb87ef4cSFlorian Wechsung     if (loc<0) {
333341525646SFlorian Wechsung       part[i] = rank;
3334cb87ef4cSFlorian Wechsung     }
3335cb87ef4cSFlorian Wechsung   }
3336cb87ef4cSFlorian Wechsung 
33377407ba93SFlorian Wechsung   /* Let's see how significant the influences of the previous fixing up step was.*/
33385dc86ac1SFlorian Wechsung   if (viewer) {
3339125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "After.       ");CHKERRQ(ierr);
3340125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);CHKERRQ(ierr);
33417407ba93SFlorian Wechsung   }
33427407ba93SFlorian Wechsung 
33435dc86ac1SFlorian Wechsung   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3344cb87ef4cSFlorian Wechsung   ierr = PetscFree(xadj);CHKERRQ(ierr);
3345cb87ef4cSFlorian Wechsung   ierr = PetscFree(adjncy);CHKERRQ(ierr);
334641525646SFlorian Wechsung   ierr = PetscFree(vtxwgt);CHKERRQ(ierr);
3347cb87ef4cSFlorian Wechsung 
33487f57c1a4SFlorian Wechsung   /* Almost done, now rewrite the SF to reflect the new ownership. */
3349cf818975SFlorian Wechsung   {
33507f57c1a4SFlorian Wechsung     PetscInt *pointsToRewrite;
335106b3913eSFlorian Wechsung     ierr = PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite);CHKERRQ(ierr);
33527f57c1a4SFlorian Wechsung     counter = 0;
3353cb87ef4cSFlorian Wechsung     for(i=0; i<pEnd-pStart; i++) {
3354cb87ef4cSFlorian Wechsung       if (toBalance[i]) {
3355cb87ef4cSFlorian Wechsung         if (isNonExclusivelyOwned[i]) {
33567f57c1a4SFlorian Wechsung           pointsToRewrite[counter] = i + pStart;
3357cb87ef4cSFlorian Wechsung           counter++;
3358cb87ef4cSFlorian Wechsung         }
3359cb87ef4cSFlorian Wechsung       }
3360cb87ef4cSFlorian Wechsung     }
33617f57c1a4SFlorian Wechsung     ierr = DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part+1, degrees);CHKERRQ(ierr);
33627f57c1a4SFlorian Wechsung     ierr = PetscFree(pointsToRewrite);CHKERRQ(ierr);
3363cf818975SFlorian Wechsung   }
3364cb87ef4cSFlorian Wechsung 
3365cb87ef4cSFlorian Wechsung   ierr = PetscFree(toBalance);CHKERRQ(ierr);
3366cb87ef4cSFlorian Wechsung   ierr = PetscFree(isLeaf);CHKERRQ(ierr);
3367cf818975SFlorian Wechsung   ierr = PetscFree(isNonExclusivelyOwned);CHKERRQ(ierr);
3368cf818975SFlorian Wechsung   ierr = PetscFree(isExclusivelyOwned);CHKERRQ(ierr);
33697f57c1a4SFlorian Wechsung   ierr = PetscFree(part);CHKERRQ(ierr);
33705dc86ac1SFlorian Wechsung   if (viewer) {
337106b3913eSFlorian Wechsung     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
337206b3913eSFlorian Wechsung     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
33737d197802SFlorian Wechsung   }
33748b879b41SFlorian Wechsung   if (success) *success = PETSC_TRUE;
337541525646SFlorian Wechsung   ierr = PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
3376240408d3SFlorian Wechsung #else
33775f441e9bSFlorian Wechsung   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
337841525646SFlorian Wechsung #endif
3379cb87ef4cSFlorian Wechsung   PetscFunctionReturn(0);
3380cb87ef4cSFlorian Wechsung }
3381