xref: /petsc/src/dm/impls/plex/plexpartition.c (revision 3c41b853d46e0278719d5fdae38ed3abae699698)
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 
30*3c41b853SStefano Zampini PetscBool PTScotchPartitionercite = PETSC_FALSE;
31*3c41b853SStefano Zampini const char PTScotchPartitionerCitation[] =
32*3c41b853SStefano Zampini   "@article{PTSCOTCH,\n"
33*3c41b853SStefano Zampini   "  author  = {C. Chevalier and F. Pellegrini},\n"
34*3c41b853SStefano Zampini   "  title   = {{PT-SCOTCH}: a tool for efficient parallel graph ordering},\n"
35*3c41b853SStefano Zampini   "  journal = {Parallel Computing},\n"
36*3c41b853SStefano Zampini   "  volume  = {34},\n"
37*3c41b853SStefano Zampini   "  number  = {6},\n"
38*3c41b853SStefano Zampini   "  pages   = {318--331},\n"
39*3c41b853SStefano Zampini   "  year    = {2008},\n"
40*3c41b853SStefano Zampini   "  doi     = {https://doi.org/10.1016/j.parco.2007.12.001}\n"
41*3c41b853SStefano Zampini   "}\n";
42*3c41b853SStefano Zampini 
43*3c41b853SStefano Zampini 
440134a67bSLisandro Dalcin PETSC_STATIC_INLINE PetscInt DMPlex_GlobalID(PetscInt point) { return point >= 0 ? point : -(point+1); }
450134a67bSLisandro Dalcin 
46bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
47532c4e7dSMichael Lange {
48ffbd6163SMatthew G. Knepley   PetscInt       dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
49389e55d8SMichael Lange   PetscInt      *adj = NULL, *vOffsets = NULL, *graph = NULL;
508cfe4c1fSMichael Lange   IS             cellNumbering;
518cfe4c1fSMichael Lange   const PetscInt *cellNum;
52532c4e7dSMichael Lange   PetscBool      useCone, useClosure;
53532c4e7dSMichael Lange   PetscSection   section;
54532c4e7dSMichael Lange   PetscSegBuffer adjBuffer;
558cfe4c1fSMichael Lange   PetscSF        sfPoint;
568f4e72b9SMatthew G. Knepley   PetscInt       *adjCells = NULL, *remoteCells = NULL;
578f4e72b9SMatthew G. Knepley   const PetscInt *local;
588f4e72b9SMatthew G. Knepley   PetscInt       nroots, nleaves, l;
59532c4e7dSMichael Lange   PetscMPIInt    rank;
60532c4e7dSMichael Lange   PetscErrorCode ierr;
61532c4e7dSMichael Lange 
62532c4e7dSMichael Lange   PetscFunctionBegin;
63532c4e7dSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
64ffbd6163SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
65ffbd6163SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
66ffbd6163SMatthew G. Knepley   if (dim != depth) {
67ffbd6163SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
68ffbd6163SMatthew G. Knepley     ierr = DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);CHKERRQ(ierr);
69ffbd6163SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
70ffbd6163SMatthew G. Knepley     if (globalNumbering) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);CHKERRQ(ierr);}
71ffbd6163SMatthew G. Knepley     /* Different behavior for empty graphs */
72ffbd6163SMatthew G. Knepley     if (!*numVertices) {
73ffbd6163SMatthew G. Knepley       ierr = PetscMalloc1(1, offsets);CHKERRQ(ierr);
74ffbd6163SMatthew G. Knepley       (*offsets)[0] = 0;
75ffbd6163SMatthew G. Knepley     }
76ffbd6163SMatthew G. Knepley     /* Broken in parallel */
77ffbd6163SMatthew G. Knepley     if (rank && *numVertices) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
78ffbd6163SMatthew G. Knepley     PetscFunctionReturn(0);
79ffbd6163SMatthew G. Knepley   }
808cfe4c1fSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
810134a67bSLisandro Dalcin   ierr = DMPlexGetHeightStratum(dm, height, &pStart, &pEnd);CHKERRQ(ierr);
82532c4e7dSMichael Lange   /* Build adjacency graph via a section/segbuffer */
83532c4e7dSMichael Lange   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &section);CHKERRQ(ierr);
84532c4e7dSMichael Lange   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
85532c4e7dSMichael Lange   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&adjBuffer);CHKERRQ(ierr);
86532c4e7dSMichael Lange   /* Always use FVM adjacency to create partitioner graph */
87b0441da4SMatthew G. Knepley   ierr = DMGetBasicAdjacency(dm, &useCone, &useClosure);CHKERRQ(ierr);
88b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE);CHKERRQ(ierr);
899886b8cfSStefano Zampini   ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, sfPoint, &cellNumbering);CHKERRQ(ierr);
903fa7752dSToby Isaac   if (globalNumbering) {
913fa7752dSToby Isaac     ierr = PetscObjectReference((PetscObject)cellNumbering);CHKERRQ(ierr);
923fa7752dSToby Isaac     *globalNumbering = cellNumbering;
933fa7752dSToby Isaac   }
948cfe4c1fSMichael Lange   ierr = ISGetIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
958f4e72b9SMatthew G. Knepley   /* For all boundary faces (including faces adjacent to a ghost cell), record the local cell in adjCells
968f4e72b9SMatthew G. Knepley      Broadcast adjCells to remoteCells (to get cells from roots) and Reduce adjCells to remoteCells (to get cells from leaves)
978f4e72b9SMatthew G. Knepley    */
980134a67bSLisandro Dalcin   ierr = PetscSFGetGraph(sfPoint, &nroots, &nleaves, &local, NULL);CHKERRQ(ierr);
998f4e72b9SMatthew G. Knepley   if (nroots >= 0) {
1008f4e72b9SMatthew G. Knepley     PetscInt fStart, fEnd, f;
1018f4e72b9SMatthew G. Knepley 
1028f4e72b9SMatthew G. Knepley     ierr = PetscCalloc2(nroots, &adjCells, nroots, &remoteCells);CHKERRQ(ierr);
1030134a67bSLisandro Dalcin     ierr = DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);CHKERRQ(ierr);
1048f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) adjCells[l] = -3;
1058f4e72b9SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
1068f4e72b9SMatthew G. Knepley       const PetscInt *support;
1078f4e72b9SMatthew G. Knepley       PetscInt        supportSize;
1088f4e72b9SMatthew G. Knepley 
1098f4e72b9SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1108f4e72b9SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1110134a67bSLisandro Dalcin       if (supportSize == 1) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
1128f4e72b9SMatthew G. Knepley       else if (supportSize == 2) {
1138f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
1140134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1]]);
1158f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
1160134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
1170134a67bSLisandro Dalcin       }
1180134a67bSLisandro Dalcin       /* Handle non-conforming meshes */
1190134a67bSLisandro Dalcin       if (supportSize > 2) {
1200134a67bSLisandro Dalcin         PetscInt        numChildren, i;
1210134a67bSLisandro Dalcin         const PetscInt *children;
1220134a67bSLisandro Dalcin 
1230134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, f, &numChildren, &children);CHKERRQ(ierr);
1240134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1250134a67bSLisandro Dalcin           const PetscInt child = children[i];
1260134a67bSLisandro Dalcin           if (fStart <= child && child < fEnd) {
1270134a67bSLisandro Dalcin             ierr = DMPlexGetSupport(dm, child, &support);CHKERRQ(ierr);
1280134a67bSLisandro Dalcin             ierr = DMPlexGetSupportSize(dm, child, &supportSize);CHKERRQ(ierr);
1290134a67bSLisandro Dalcin             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
1300134a67bSLisandro Dalcin             else if (supportSize == 2) {
1310134a67bSLisandro Dalcin               ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
1320134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1]]);
1330134a67bSLisandro Dalcin               ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
1340134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
1350134a67bSLisandro Dalcin             }
1360134a67bSLisandro Dalcin           }
1370134a67bSLisandro Dalcin         }
1388f4e72b9SMatthew G. Knepley       }
1398f4e72b9SMatthew G. Knepley     }
1408f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) remoteCells[l] = -1;
1418f4e72b9SMatthew G. Knepley     ierr = PetscSFBcastBegin(dm->sf, MPIU_INT, adjCells, remoteCells);CHKERRQ(ierr);
1428f4e72b9SMatthew G. Knepley     ierr = PetscSFBcastEnd(dm->sf, MPIU_INT, adjCells, remoteCells);CHKERRQ(ierr);
1438f4e72b9SMatthew G. Knepley     ierr = PetscSFReduceBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);CHKERRQ(ierr);
1448f4e72b9SMatthew G. Knepley     ierr = PetscSFReduceEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);CHKERRQ(ierr);
1458f4e72b9SMatthew G. Knepley   }
1468f4e72b9SMatthew G. Knepley   /* Combine local and global adjacencies */
1478cfe4c1fSMichael Lange   for (*numVertices = 0, p = pStart; p < pEnd; p++) {
1488cfe4c1fSMichael Lange     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
1498cfe4c1fSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
1508f4e72b9SMatthew G. Knepley     /* Add remote cells */
1518f4e72b9SMatthew G. Knepley     if (remoteCells) {
1520134a67bSLisandro Dalcin       const PetscInt gp = DMPlex_GlobalID(cellNum[p]);
1530134a67bSLisandro Dalcin       PetscInt       coneSize, numChildren, c, i;
1540134a67bSLisandro Dalcin       const PetscInt *cone, *children;
1550134a67bSLisandro Dalcin 
1568f4e72b9SMatthew G. Knepley       ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1578f4e72b9SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1588f4e72b9SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
1590134a67bSLisandro Dalcin         const PetscInt point = cone[c];
1600134a67bSLisandro Dalcin         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
1618f4e72b9SMatthew G. Knepley           PetscInt *PETSC_RESTRICT pBuf;
1628f4e72b9SMatthew G. Knepley           ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
1638f4e72b9SMatthew G. Knepley           ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1640134a67bSLisandro Dalcin           *pBuf = remoteCells[point];
1650134a67bSLisandro Dalcin         }
1660134a67bSLisandro Dalcin         /* Handle non-conforming meshes */
1670134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, point, &numChildren, &children);CHKERRQ(ierr);
1680134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1690134a67bSLisandro Dalcin           const PetscInt child = children[i];
1700134a67bSLisandro Dalcin           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
1710134a67bSLisandro Dalcin             PetscInt *PETSC_RESTRICT pBuf;
1720134a67bSLisandro Dalcin             ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
1730134a67bSLisandro Dalcin             ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1740134a67bSLisandro Dalcin             *pBuf = remoteCells[child];
1750134a67bSLisandro Dalcin           }
1768f4e72b9SMatthew G. Knepley         }
1778f4e72b9SMatthew G. Knepley       }
1788f4e72b9SMatthew G. Knepley     }
1798f4e72b9SMatthew G. Knepley     /* Add local cells */
180532c4e7dSMichael Lange     adjSize = PETSC_DETERMINE;
181532c4e7dSMichael Lange     ierr = DMPlexGetAdjacency(dm, p, &adjSize, &adj);CHKERRQ(ierr);
182532c4e7dSMichael Lange     for (a = 0; a < adjSize; ++a) {
183532c4e7dSMichael Lange       const PetscInt point = adj[a];
184532c4e7dSMichael Lange       if (point != p && pStart <= point && point < pEnd) {
185532c4e7dSMichael Lange         PetscInt *PETSC_RESTRICT pBuf;
186532c4e7dSMichael Lange         ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
187532c4e7dSMichael Lange         ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1880134a67bSLisandro Dalcin         *pBuf = DMPlex_GlobalID(cellNum[point]);
189532c4e7dSMichael Lange       }
190532c4e7dSMichael Lange     }
1918cfe4c1fSMichael Lange     (*numVertices)++;
192532c4e7dSMichael Lange   }
1934e468a93SLisandro Dalcin   ierr = PetscFree(adj);CHKERRQ(ierr);
1948f4e72b9SMatthew G. Knepley   ierr = PetscFree2(adjCells, remoteCells);CHKERRQ(ierr);
195b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, useCone, useClosure);CHKERRQ(ierr);
1964e468a93SLisandro Dalcin 
197532c4e7dSMichael Lange   /* Derive CSR graph from section/segbuffer */
198532c4e7dSMichael Lange   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
199532c4e7dSMichael Lange   ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
200389e55d8SMichael Lange   ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
20143f7d02bSMichael Lange   for (idx = 0, p = pStart; p < pEnd; p++) {
20243f7d02bSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
20343f7d02bSMichael Lange     ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
20443f7d02bSMichael Lange   }
205532c4e7dSMichael Lange   vOffsets[*numVertices] = size;
206389e55d8SMichael Lange   ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
2074e468a93SLisandro Dalcin 
2084e468a93SLisandro Dalcin   if (nroots >= 0) {
2094e468a93SLisandro Dalcin     /* Filter out duplicate edges using section/segbuffer */
2104e468a93SLisandro Dalcin     ierr = PetscSectionReset(section);CHKERRQ(ierr);
2114e468a93SLisandro Dalcin     ierr = PetscSectionSetChart(section, 0, *numVertices);CHKERRQ(ierr);
2124e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2134e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
2144e468a93SLisandro Dalcin       PetscInt numEdges = end-start, *PETSC_RESTRICT edges;
2154e468a93SLisandro Dalcin       ierr = PetscSortRemoveDupsInt(&numEdges, &graph[start]);CHKERRQ(ierr);
2164e468a93SLisandro Dalcin       ierr = PetscSectionSetDof(section, p, numEdges);CHKERRQ(ierr);
2174e468a93SLisandro Dalcin       ierr = PetscSegBufferGetInts(adjBuffer, numEdges, &edges);CHKERRQ(ierr);
218580bdb30SBarry Smith       ierr = PetscArraycpy(edges, &graph[start], numEdges);CHKERRQ(ierr);
2194e468a93SLisandro Dalcin     }
2204e468a93SLisandro Dalcin     ierr = PetscFree(vOffsets);CHKERRQ(ierr);
2214e468a93SLisandro Dalcin     ierr = PetscFree(graph);CHKERRQ(ierr);
2224e468a93SLisandro Dalcin     /* Derive CSR graph from section/segbuffer */
2234e468a93SLisandro Dalcin     ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
2244e468a93SLisandro Dalcin     ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
2254e468a93SLisandro Dalcin     ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
2264e468a93SLisandro Dalcin     for (idx = 0, p = 0; p < *numVertices; p++) {
2274e468a93SLisandro Dalcin       ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
2284e468a93SLisandro Dalcin     }
2294e468a93SLisandro Dalcin     vOffsets[*numVertices] = size;
2304e468a93SLisandro Dalcin     ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
2314e468a93SLisandro Dalcin   } else {
2324e468a93SLisandro Dalcin     /* Sort adjacencies (not strictly necessary) */
2334e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2344e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
2354e468a93SLisandro Dalcin       ierr = PetscSortInt(end-start, &graph[start]);CHKERRQ(ierr);
2364e468a93SLisandro Dalcin     }
2374e468a93SLisandro Dalcin   }
2384e468a93SLisandro Dalcin 
2394e468a93SLisandro Dalcin   if (offsets) *offsets = vOffsets;
240389e55d8SMichael Lange   if (adjacency) *adjacency = graph;
2414e468a93SLisandro Dalcin 
242532c4e7dSMichael Lange   /* Cleanup */
243532c4e7dSMichael Lange   ierr = PetscSegBufferDestroy(&adjBuffer);CHKERRQ(ierr);
244532c4e7dSMichael Lange   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
2454e468a93SLisandro Dalcin   ierr = ISRestoreIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
2464e468a93SLisandro Dalcin   ierr = ISDestroy(&cellNumbering);CHKERRQ(ierr);
247532c4e7dSMichael Lange   PetscFunctionReturn(0);
248532c4e7dSMichael Lange }
249532c4e7dSMichael Lange 
250bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
251bbbc8e51SStefano Zampini {
252bbbc8e51SStefano Zampini   Mat            conn, CSR;
253bbbc8e51SStefano Zampini   IS             fis, cis, cis_own;
254bbbc8e51SStefano Zampini   PetscSF        sfPoint;
255bbbc8e51SStefano Zampini   const PetscInt *rows, *cols, *ii, *jj;
256bbbc8e51SStefano Zampini   PetscInt       *idxs,*idxs2;
257bbbc8e51SStefano Zampini   PetscInt       dim, depth, floc, cloc, i, M, N, c, m, cStart, cEnd, fStart, fEnd;
258bbbc8e51SStefano Zampini   PetscMPIInt    rank;
259bbbc8e51SStefano Zampini   PetscBool      flg;
260bbbc8e51SStefano Zampini   PetscErrorCode ierr;
261bbbc8e51SStefano Zampini 
262bbbc8e51SStefano Zampini   PetscFunctionBegin;
263bbbc8e51SStefano Zampini   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
264bbbc8e51SStefano Zampini   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
265bbbc8e51SStefano Zampini   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
266bbbc8e51SStefano Zampini   if (dim != depth) {
267bbbc8e51SStefano Zampini     /* We do not handle the uninterpolated case here */
268bbbc8e51SStefano Zampini     ierr = DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);CHKERRQ(ierr);
269bbbc8e51SStefano Zampini     /* DMPlexCreateNeighborCSR does not make a numbering */
270bbbc8e51SStefano Zampini     if (globalNumbering) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);CHKERRQ(ierr);}
271bbbc8e51SStefano Zampini     /* Different behavior for empty graphs */
272bbbc8e51SStefano Zampini     if (!*numVertices) {
273bbbc8e51SStefano Zampini       ierr = PetscMalloc1(1, offsets);CHKERRQ(ierr);
274bbbc8e51SStefano Zampini       (*offsets)[0] = 0;
275bbbc8e51SStefano Zampini     }
276bbbc8e51SStefano Zampini     /* Broken in parallel */
277bbbc8e51SStefano Zampini     if (rank && *numVertices) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
278bbbc8e51SStefano Zampini     PetscFunctionReturn(0);
279bbbc8e51SStefano Zampini   }
280bbbc8e51SStefano Zampini   /* Interpolated and parallel case */
281bbbc8e51SStefano Zampini 
282bbbc8e51SStefano Zampini   /* numbering */
283bbbc8e51SStefano Zampini   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
284bbbc8e51SStefano Zampini   ierr = DMPlexGetHeightStratum(dm, height, &cStart, &cEnd);CHKERRQ(ierr);
285bbbc8e51SStefano Zampini   ierr = DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);CHKERRQ(ierr);
2869886b8cfSStefano Zampini   ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, &N, sfPoint, &cis);CHKERRQ(ierr);
2879886b8cfSStefano Zampini   ierr = DMPlexCreateNumbering_Plex(dm, fStart, fEnd, 0, &M, sfPoint, &fis);CHKERRQ(ierr);
288bbbc8e51SStefano Zampini   if (globalNumbering) {
289bbbc8e51SStefano Zampini     ierr = ISDuplicate(cis, globalNumbering);CHKERRQ(ierr);
290bbbc8e51SStefano Zampini   }
291bbbc8e51SStefano Zampini 
292bbbc8e51SStefano Zampini   /* get positive global ids and local sizes for facets and cells */
293bbbc8e51SStefano Zampini   ierr = ISGetLocalSize(fis, &m);CHKERRQ(ierr);
294bbbc8e51SStefano Zampini   ierr = ISGetIndices(fis, &rows);CHKERRQ(ierr);
295bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs);CHKERRQ(ierr);
296bbbc8e51SStefano Zampini   for (i = 0, floc = 0; i < m; i++) {
297bbbc8e51SStefano Zampini     const PetscInt p = rows[i];
298bbbc8e51SStefano Zampini 
299bbbc8e51SStefano Zampini     if (p < 0) {
300bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
301bbbc8e51SStefano Zampini     } else {
302bbbc8e51SStefano Zampini       idxs[i] = p;
303bbbc8e51SStefano Zampini       floc   += 1;
304bbbc8e51SStefano Zampini     }
305bbbc8e51SStefano Zampini   }
306bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(fis, &rows);CHKERRQ(ierr);
307bbbc8e51SStefano Zampini   ierr = ISDestroy(&fis);CHKERRQ(ierr);
308bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr);
309bbbc8e51SStefano Zampini 
310bbbc8e51SStefano Zampini   ierr = ISGetLocalSize(cis, &m);CHKERRQ(ierr);
311bbbc8e51SStefano Zampini   ierr = ISGetIndices(cis, &cols);CHKERRQ(ierr);
312bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs);CHKERRQ(ierr);
313bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs2);CHKERRQ(ierr);
314bbbc8e51SStefano Zampini   for (i = 0, cloc = 0; i < m; i++) {
315bbbc8e51SStefano Zampini     const PetscInt p = cols[i];
316bbbc8e51SStefano Zampini 
317bbbc8e51SStefano Zampini     if (p < 0) {
318bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
319bbbc8e51SStefano Zampini     } else {
320bbbc8e51SStefano Zampini       idxs[i]       = p;
321bbbc8e51SStefano Zampini       idxs2[cloc++] = p;
322bbbc8e51SStefano Zampini     }
323bbbc8e51SStefano Zampini   }
324bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(cis, &cols);CHKERRQ(ierr);
325bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis);CHKERRQ(ierr);
326bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr);
327bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own);CHKERRQ(ierr);
328bbbc8e51SStefano Zampini 
329bbbc8e51SStefano Zampini   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
330bbbc8e51SStefano Zampini   ierr = MatCreate(PetscObjectComm((PetscObject)dm), &conn);CHKERRQ(ierr);
331bbbc8e51SStefano Zampini   ierr = MatSetSizes(conn, floc, cloc, M, N);CHKERRQ(ierr);
332bbbc8e51SStefano Zampini   ierr = MatSetType(conn, MATMPIAIJ);CHKERRQ(ierr);
333bbbc8e51SStefano Zampini   ierr = DMPlexGetMaxSizes(dm, NULL, &m);CHKERRQ(ierr);
334bbbc8e51SStefano Zampini   ierr = MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL);CHKERRQ(ierr);
335bbbc8e51SStefano Zampini 
336bbbc8e51SStefano Zampini   /* Assemble matrix */
337bbbc8e51SStefano Zampini   ierr = ISGetIndices(fis, &rows);CHKERRQ(ierr);
338bbbc8e51SStefano Zampini   ierr = ISGetIndices(cis, &cols);CHKERRQ(ierr);
339bbbc8e51SStefano Zampini   for (c = cStart; c < cEnd; c++) {
340bbbc8e51SStefano Zampini     const PetscInt *cone;
341bbbc8e51SStefano Zampini     PetscInt        coneSize, row, col, f;
342bbbc8e51SStefano Zampini 
343bbbc8e51SStefano Zampini     col  = cols[c-cStart];
344bbbc8e51SStefano Zampini     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
345bbbc8e51SStefano Zampini     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
346bbbc8e51SStefano Zampini     for (f = 0; f < coneSize; f++) {
347bbbc8e51SStefano Zampini       const PetscScalar v = 1.0;
348bbbc8e51SStefano Zampini       const PetscInt *children;
349bbbc8e51SStefano Zampini       PetscInt        numChildren, ch;
350bbbc8e51SStefano Zampini 
351bbbc8e51SStefano Zampini       row  = rows[cone[f]-fStart];
352bbbc8e51SStefano Zampini       ierr = MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);CHKERRQ(ierr);
353bbbc8e51SStefano Zampini 
354bbbc8e51SStefano Zampini       /* non-conforming meshes */
355bbbc8e51SStefano Zampini       ierr = DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children);CHKERRQ(ierr);
356bbbc8e51SStefano Zampini       for (ch = 0; ch < numChildren; ch++) {
357bbbc8e51SStefano Zampini         const PetscInt child = children[ch];
358bbbc8e51SStefano Zampini 
359bbbc8e51SStefano Zampini         if (child < fStart || child >= fEnd) continue;
360bbbc8e51SStefano Zampini         row  = rows[child-fStart];
361bbbc8e51SStefano Zampini         ierr = MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);CHKERRQ(ierr);
362bbbc8e51SStefano Zampini       }
363bbbc8e51SStefano Zampini     }
364bbbc8e51SStefano Zampini   }
365bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(fis, &rows);CHKERRQ(ierr);
366bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(cis, &cols);CHKERRQ(ierr);
367bbbc8e51SStefano Zampini   ierr = ISDestroy(&fis);CHKERRQ(ierr);
368bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis);CHKERRQ(ierr);
369bbbc8e51SStefano Zampini   ierr = MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
370bbbc8e51SStefano Zampini   ierr = MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
371bbbc8e51SStefano Zampini 
372bbbc8e51SStefano Zampini   /* Get parallel CSR by doing conn^T * conn */
373bbbc8e51SStefano Zampini   ierr = MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR);CHKERRQ(ierr);
374bbbc8e51SStefano Zampini   ierr = MatDestroy(&conn);CHKERRQ(ierr);
375bbbc8e51SStefano Zampini 
376bbbc8e51SStefano Zampini   /* extract local part of the CSR */
377bbbc8e51SStefano Zampini   ierr = MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn);CHKERRQ(ierr);
378bbbc8e51SStefano Zampini   ierr = MatDestroy(&CSR);CHKERRQ(ierr);
379bbbc8e51SStefano Zampini   ierr = MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);CHKERRQ(ierr);
380bbbc8e51SStefano Zampini   if (!flg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
381bbbc8e51SStefano Zampini 
382bbbc8e51SStefano Zampini   /* get back requested output */
383bbbc8e51SStefano Zampini   if (numVertices) *numVertices = m;
384bbbc8e51SStefano Zampini   if (offsets) {
385bbbc8e51SStefano Zampini     ierr = PetscCalloc1(m+1, &idxs);CHKERRQ(ierr);
386bbbc8e51SStefano Zampini     for (i = 1; i < m+1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
387bbbc8e51SStefano Zampini     *offsets = idxs;
388bbbc8e51SStefano Zampini   }
389bbbc8e51SStefano Zampini   if (adjacency) {
390bbbc8e51SStefano Zampini     ierr = PetscMalloc1(ii[m] - m, &idxs);CHKERRQ(ierr);
391bbbc8e51SStefano Zampini     ierr = ISGetIndices(cis_own, &rows);CHKERRQ(ierr);
392bbbc8e51SStefano Zampini     for (i = 0, c = 0; i < m; i++) {
393bbbc8e51SStefano Zampini       PetscInt j, g = rows[i];
394bbbc8e51SStefano Zampini 
395bbbc8e51SStefano Zampini       for (j = ii[i]; j < ii[i+1]; j++) {
396bbbc8e51SStefano Zampini         if (jj[j] == g) continue; /* again, self-connectivity */
397bbbc8e51SStefano Zampini         idxs[c++] = jj[j];
398bbbc8e51SStefano Zampini       }
399bbbc8e51SStefano Zampini     }
400bbbc8e51SStefano Zampini     if (c != ii[m] - m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %D != %D",c,ii[m]-m);
401bbbc8e51SStefano Zampini     ierr = ISRestoreIndices(cis_own, &rows);CHKERRQ(ierr);
402bbbc8e51SStefano Zampini     *adjacency = idxs;
403bbbc8e51SStefano Zampini   }
404bbbc8e51SStefano Zampini 
405bbbc8e51SStefano Zampini   /* cleanup */
406bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis_own);CHKERRQ(ierr);
407bbbc8e51SStefano Zampini   ierr = MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);CHKERRQ(ierr);
408bbbc8e51SStefano Zampini   if (!flg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
409bbbc8e51SStefano Zampini   ierr = MatDestroy(&conn);CHKERRQ(ierr);
410bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
411bbbc8e51SStefano Zampini }
412bbbc8e51SStefano Zampini 
413bbbc8e51SStefano Zampini /*@C
414bbbc8e51SStefano Zampini   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
415bbbc8e51SStefano Zampini 
416bbbc8e51SStefano Zampini   Input Parameters:
417bbbc8e51SStefano Zampini + dm      - The mesh DM dm
418bbbc8e51SStefano Zampini - height  - Height of the strata from which to construct the graph
419bbbc8e51SStefano Zampini 
420bbbc8e51SStefano Zampini   Output Parameter:
421bbbc8e51SStefano Zampini + numVertices     - Number of vertices in the graph
422bbbc8e51SStefano Zampini . offsets         - Point offsets in the graph
423bbbc8e51SStefano Zampini . adjacency       - Point connectivity in the graph
424bbbc8e51SStefano 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.
425bbbc8e51SStefano Zampini 
426bbbc8e51SStefano Zampini   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
427bbbc8e51SStefano Zampini   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
428bbbc8e51SStefano Zampini 
429bbbc8e51SStefano Zampini   Level: developer
430bbbc8e51SStefano Zampini 
431bbbc8e51SStefano Zampini .seealso: PetscPartitionerGetType(), PetscPartitionerCreate(), DMSetAdjacency()
432bbbc8e51SStefano Zampini @*/
433bbbc8e51SStefano Zampini PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
434bbbc8e51SStefano Zampini {
435bbbc8e51SStefano Zampini   PetscErrorCode ierr;
436bbbc8e51SStefano Zampini   PetscBool      usemat = PETSC_FALSE;
437bbbc8e51SStefano Zampini 
438bbbc8e51SStefano Zampini   PetscFunctionBegin;
439bbbc8e51SStefano Zampini   ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_csr_via_mat", &usemat, NULL);CHKERRQ(ierr);
440bbbc8e51SStefano Zampini   if (usemat) {
441bbbc8e51SStefano Zampini     ierr = DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering);CHKERRQ(ierr);
442bbbc8e51SStefano Zampini   } else {
443bbbc8e51SStefano Zampini     ierr = DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering);CHKERRQ(ierr);
444bbbc8e51SStefano Zampini   }
445bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
446bbbc8e51SStefano Zampini }
447bbbc8e51SStefano Zampini 
448d5577e40SMatthew G. Knepley /*@C
449d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
450d5577e40SMatthew G. Knepley 
451fe2efc57SMark   Collective on DM
452d5577e40SMatthew G. Knepley 
453d5577e40SMatthew G. Knepley   Input Arguments:
454d5577e40SMatthew G. Knepley + dm - The DMPlex
455d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
456d5577e40SMatthew G. Knepley 
457d5577e40SMatthew G. Knepley   Output Arguments:
458d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
459d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
460d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
461d5577e40SMatthew G. Knepley 
462d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
463d5577e40SMatthew G. Knepley 
464d5577e40SMatthew G. Knepley   Level: advanced
465d5577e40SMatthew G. Knepley 
466d5577e40SMatthew G. Knepley .seealso: DMPlexCreate()
467d5577e40SMatthew G. Knepley @*/
46870034214SMatthew G. Knepley PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
46970034214SMatthew G. Knepley {
47070034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
47170034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
47270034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
47370034214SMatthew G. Knepley   PetscInt      *off, *adj;
47470034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
47570034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
47670034214SMatthew G. Knepley   PetscErrorCode ierr;
47770034214SMatthew G. Knepley 
47870034214SMatthew G. Knepley   PetscFunctionBegin;
47970034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
480c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
48170034214SMatthew G. Knepley   cellDim = dim - cellHeight;
48270034214SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
48370034214SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
48470034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
48570034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
48670034214SMatthew G. Knepley     if (offsets)   *offsets   = NULL;
48770034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
48870034214SMatthew G. Knepley     PetscFunctionReturn(0);
48970034214SMatthew G. Knepley   }
49070034214SMatthew G. Knepley   numCells  = cEnd - cStart;
49170034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
49270034214SMatthew G. Knepley   if (dim == depth) {
49370034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
49470034214SMatthew G. Knepley 
49570034214SMatthew G. Knepley     ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
49670034214SMatthew G. Knepley     /* Count neighboring cells */
49770034214SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr);
49870034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
49970034214SMatthew G. Knepley       const PetscInt *support;
50070034214SMatthew G. Knepley       PetscInt        supportSize;
50170034214SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
50270034214SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
50370034214SMatthew G. Knepley       if (supportSize == 2) {
5049ffc88e4SToby Isaac         PetscInt numChildren;
5059ffc88e4SToby Isaac 
5069ffc88e4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
5079ffc88e4SToby Isaac         if (!numChildren) {
50870034214SMatthew G. Knepley           ++off[support[0]-cStart+1];
50970034214SMatthew G. Knepley           ++off[support[1]-cStart+1];
51070034214SMatthew G. Knepley         }
51170034214SMatthew G. Knepley       }
5129ffc88e4SToby Isaac     }
51370034214SMatthew G. Knepley     /* Prefix sum */
51470034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
51570034214SMatthew G. Knepley     if (adjacency) {
51670034214SMatthew G. Knepley       PetscInt *tmp;
51770034214SMatthew G. Knepley 
51870034214SMatthew G. Knepley       ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
519854ce69bSBarry Smith       ierr = PetscMalloc1(numCells+1, &tmp);CHKERRQ(ierr);
520580bdb30SBarry Smith       ierr = PetscArraycpy(tmp, off, numCells+1);CHKERRQ(ierr);
52170034214SMatthew G. Knepley       /* Get neighboring cells */
52270034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
52370034214SMatthew G. Knepley         const PetscInt *support;
52470034214SMatthew G. Knepley         PetscInt        supportSize;
52570034214SMatthew G. Knepley         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
52670034214SMatthew G. Knepley         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
52770034214SMatthew G. Knepley         if (supportSize == 2) {
5289ffc88e4SToby Isaac           PetscInt numChildren;
5299ffc88e4SToby Isaac 
5309ffc88e4SToby Isaac           ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
5319ffc88e4SToby Isaac           if (!numChildren) {
53270034214SMatthew G. Knepley             adj[tmp[support[0]-cStart]++] = support[1];
53370034214SMatthew G. Knepley             adj[tmp[support[1]-cStart]++] = support[0];
53470034214SMatthew G. Knepley           }
53570034214SMatthew G. Knepley         }
5369ffc88e4SToby Isaac       }
53770034214SMatthew G. Knepley #if defined(PETSC_USE_DEBUG)
53870034214SMatthew 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);
53970034214SMatthew G. Knepley #endif
54070034214SMatthew G. Knepley       ierr = PetscFree(tmp);CHKERRQ(ierr);
54170034214SMatthew G. Knepley     }
54270034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
54370034214SMatthew G. Knepley     if (offsets)   *offsets   = off;
54470034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
54570034214SMatthew G. Knepley     PetscFunctionReturn(0);
54670034214SMatthew G. Knepley   }
54770034214SMatthew G. Knepley   /* Setup face recognition */
54870034214SMatthew G. Knepley   if (faceDepth == 1) {
54970034214SMatthew 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 */
55070034214SMatthew G. Knepley 
55170034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
55270034214SMatthew G. Knepley       PetscInt corners;
55370034214SMatthew G. Knepley 
55470034214SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
55570034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
55670034214SMatthew G. Knepley         PetscInt nFV;
55770034214SMatthew G. Knepley 
55870034214SMatthew G. Knepley         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
55970034214SMatthew G. Knepley         cornersSeen[corners] = 1;
56070034214SMatthew G. Knepley 
56170034214SMatthew G. Knepley         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
56270034214SMatthew G. Knepley 
56370034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
56470034214SMatthew G. Knepley       }
56570034214SMatthew G. Knepley     }
56670034214SMatthew G. Knepley   }
56770034214SMatthew G. Knepley   ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
56870034214SMatthew G. Knepley   /* Count neighboring cells */
56970034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
57070034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
57170034214SMatthew G. Knepley 
5728b0b4c70SToby Isaac     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
57370034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
57470034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
57570034214SMatthew G. Knepley       PetscInt        cellPair[2];
57670034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
57770034214SMatthew G. Knepley       PetscInt        meetSize = 0;
57870034214SMatthew G. Knepley       const PetscInt *meet    = NULL;
57970034214SMatthew G. Knepley 
58070034214SMatthew G. Knepley       cellPair[0] = cell; cellPair[1] = neighborCells[n];
58170034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
58270034214SMatthew G. Knepley       if (!found) {
58370034214SMatthew G. Knepley         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
58470034214SMatthew G. Knepley         if (meetSize) {
58570034214SMatthew G. Knepley           PetscInt f;
58670034214SMatthew G. Knepley 
58770034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
58870034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
58970034214SMatthew G. Knepley               found = PETSC_TRUE;
59070034214SMatthew G. Knepley               break;
59170034214SMatthew G. Knepley             }
59270034214SMatthew G. Knepley           }
59370034214SMatthew G. Knepley         }
59470034214SMatthew G. Knepley         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
59570034214SMatthew G. Knepley       }
59670034214SMatthew G. Knepley       if (found) ++off[cell-cStart+1];
59770034214SMatthew G. Knepley     }
59870034214SMatthew G. Knepley   }
59970034214SMatthew G. Knepley   /* Prefix sum */
60070034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
60170034214SMatthew G. Knepley 
60270034214SMatthew G. Knepley   if (adjacency) {
60370034214SMatthew G. Knepley     ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
60470034214SMatthew G. Knepley     /* Get neighboring cells */
60570034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
60670034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
60770034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
60870034214SMatthew G. Knepley 
6098b0b4c70SToby Isaac       ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
61070034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
61170034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
61270034214SMatthew G. Knepley         PetscInt        cellPair[2];
61370034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
61470034214SMatthew G. Knepley         PetscInt        meetSize = 0;
61570034214SMatthew G. Knepley         const PetscInt *meet    = NULL;
61670034214SMatthew G. Knepley 
61770034214SMatthew G. Knepley         cellPair[0] = cell; cellPair[1] = neighborCells[n];
61870034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
61970034214SMatthew G. Knepley         if (!found) {
62070034214SMatthew G. Knepley           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
62170034214SMatthew G. Knepley           if (meetSize) {
62270034214SMatthew G. Knepley             PetscInt f;
62370034214SMatthew G. Knepley 
62470034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
62570034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
62670034214SMatthew G. Knepley                 found = PETSC_TRUE;
62770034214SMatthew G. Knepley                 break;
62870034214SMatthew G. Knepley               }
62970034214SMatthew G. Knepley             }
63070034214SMatthew G. Knepley           }
63170034214SMatthew G. Knepley           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
63270034214SMatthew G. Knepley         }
63370034214SMatthew G. Knepley         if (found) {
63470034214SMatthew G. Knepley           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
63570034214SMatthew G. Knepley           ++cellOffset;
63670034214SMatthew G. Knepley         }
63770034214SMatthew G. Knepley       }
63870034214SMatthew G. Knepley     }
63970034214SMatthew G. Knepley   }
64070034214SMatthew G. Knepley   ierr = PetscFree(neighborCells);CHKERRQ(ierr);
64170034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
64270034214SMatthew G. Knepley   if (offsets)   *offsets   = off;
64370034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
64470034214SMatthew G. Knepley   PetscFunctionReturn(0);
64570034214SMatthew G. Knepley }
64670034214SMatthew G. Knepley 
64777623264SMatthew G. Knepley /*@C
64877623264SMatthew G. Knepley   PetscPartitionerRegister - Adds a new PetscPartitioner implementation
64977623264SMatthew G. Knepley 
65077623264SMatthew G. Knepley   Not Collective
65177623264SMatthew G. Knepley 
65277623264SMatthew G. Knepley   Input Parameters:
65377623264SMatthew G. Knepley + name        - The name of a new user-defined creation routine
65477623264SMatthew G. Knepley - create_func - The creation routine itself
65577623264SMatthew G. Knepley 
65677623264SMatthew G. Knepley   Notes:
65777623264SMatthew G. Knepley   PetscPartitionerRegister() may be called multiple times to add several user-defined PetscPartitioners
65877623264SMatthew G. Knepley 
65977623264SMatthew G. Knepley   Sample usage:
66077623264SMatthew G. Knepley .vb
66177623264SMatthew G. Knepley     PetscPartitionerRegister("my_part", MyPetscPartitionerCreate);
66277623264SMatthew G. Knepley .ve
66377623264SMatthew G. Knepley 
66477623264SMatthew G. Knepley   Then, your PetscPartitioner type can be chosen with the procedural interface via
66577623264SMatthew G. Knepley .vb
66677623264SMatthew G. Knepley     PetscPartitionerCreate(MPI_Comm, PetscPartitioner *);
66777623264SMatthew G. Knepley     PetscPartitionerSetType(PetscPartitioner, "my_part");
66877623264SMatthew G. Knepley .ve
66977623264SMatthew G. Knepley    or at runtime via the option
67077623264SMatthew G. Knepley .vb
67177623264SMatthew G. Knepley     -petscpartitioner_type my_part
67277623264SMatthew G. Knepley .ve
67377623264SMatthew G. Knepley 
67477623264SMatthew G. Knepley   Level: advanced
67577623264SMatthew G. Knepley 
67677623264SMatthew G. Knepley .seealso: PetscPartitionerRegisterAll(), PetscPartitionerRegisterDestroy()
67777623264SMatthew G. Knepley 
67877623264SMatthew G. Knepley @*/
67977623264SMatthew G. Knepley PetscErrorCode PetscPartitionerRegister(const char sname[], PetscErrorCode (*function)(PetscPartitioner))
68077623264SMatthew G. Knepley {
68177623264SMatthew G. Knepley   PetscErrorCode ierr;
68277623264SMatthew G. Knepley 
68377623264SMatthew G. Knepley   PetscFunctionBegin;
68477623264SMatthew G. Knepley   ierr = PetscFunctionListAdd(&PetscPartitionerList, sname, function);CHKERRQ(ierr);
68577623264SMatthew G. Knepley   PetscFunctionReturn(0);
68677623264SMatthew G. Knepley }
68777623264SMatthew G. Knepley 
68877623264SMatthew G. Knepley /*@C
68977623264SMatthew G. Knepley   PetscPartitionerSetType - Builds a particular PetscPartitioner
69077623264SMatthew G. Knepley 
691fe2efc57SMark   Collective on PetscPartitioner
69277623264SMatthew G. Knepley 
69377623264SMatthew G. Knepley   Input Parameters:
69477623264SMatthew G. Knepley + part - The PetscPartitioner object
69577623264SMatthew G. Knepley - name - The kind of partitioner
69677623264SMatthew G. Knepley 
69777623264SMatthew G. Knepley   Options Database Key:
69877623264SMatthew G. Knepley . -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types
69977623264SMatthew G. Knepley 
70077623264SMatthew G. Knepley   Level: intermediate
70177623264SMatthew G. Knepley 
70277623264SMatthew G. Knepley .seealso: PetscPartitionerGetType(), PetscPartitionerCreate()
70377623264SMatthew G. Knepley @*/
70477623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name)
70577623264SMatthew G. Knepley {
70677623264SMatthew G. Knepley   PetscErrorCode (*r)(PetscPartitioner);
70777623264SMatthew G. Knepley   PetscBool      match;
70877623264SMatthew G. Knepley   PetscErrorCode ierr;
70977623264SMatthew G. Knepley 
71077623264SMatthew G. Knepley   PetscFunctionBegin;
71177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
71277623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) part, name, &match);CHKERRQ(ierr);
71377623264SMatthew G. Knepley   if (match) PetscFunctionReturn(0);
71477623264SMatthew G. Knepley 
71577623264SMatthew G. Knepley   ierr = PetscFunctionListFind(PetscPartitionerList, name, &r);CHKERRQ(ierr);
71677623264SMatthew G. Knepley   if (!r) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name);
71777623264SMatthew G. Knepley 
71877623264SMatthew G. Knepley   if (part->ops->destroy) {
71977623264SMatthew G. Knepley     ierr = (*part->ops->destroy)(part);CHKERRQ(ierr);
72077623264SMatthew G. Knepley   }
721074d466cSStefano Zampini   part->noGraph = PETSC_FALSE;
722d57f96a3SLisandro Dalcin   ierr = PetscMemzero(part->ops, sizeof(*part->ops));CHKERRQ(ierr);
72377623264SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) part, name);CHKERRQ(ierr);
724d57f96a3SLisandro Dalcin   ierr = (*r)(part);CHKERRQ(ierr);
72577623264SMatthew G. Knepley   PetscFunctionReturn(0);
72677623264SMatthew G. Knepley }
72777623264SMatthew G. Knepley 
72877623264SMatthew G. Knepley /*@C
72977623264SMatthew G. Knepley   PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object.
73077623264SMatthew G. Knepley 
73177623264SMatthew G. Knepley   Not Collective
73277623264SMatthew G. Knepley 
73377623264SMatthew G. Knepley   Input Parameter:
73477623264SMatthew G. Knepley . part - The PetscPartitioner
73577623264SMatthew G. Knepley 
73677623264SMatthew G. Knepley   Output Parameter:
73777623264SMatthew G. Knepley . name - The PetscPartitioner type name
73877623264SMatthew G. Knepley 
73977623264SMatthew G. Knepley   Level: intermediate
74077623264SMatthew G. Knepley 
74177623264SMatthew G. Knepley .seealso: PetscPartitionerSetType(), PetscPartitionerCreate()
74277623264SMatthew G. Knepley @*/
74377623264SMatthew G. Knepley PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name)
74477623264SMatthew G. Knepley {
74577623264SMatthew G. Knepley   PetscFunctionBegin;
74677623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
74777623264SMatthew G. Knepley   PetscValidPointer(name, 2);
74877623264SMatthew G. Knepley   *name = ((PetscObject) part)->type_name;
74977623264SMatthew G. Knepley   PetscFunctionReturn(0);
75077623264SMatthew G. Knepley }
75177623264SMatthew G. Knepley 
75277623264SMatthew G. Knepley /*@C
753fe2efc57SMark    PetscPartitionerViewFromOptions - View from Options
754fe2efc57SMark 
755fe2efc57SMark    Collective on PetscPartitioner
756fe2efc57SMark 
757fe2efc57SMark    Input Parameters:
758fe2efc57SMark +  A - the PetscPartitioner object
759fe2efc57SMark .  obj - Optional object
760fe2efc57SMark -  name - command line option
761fe2efc57SMark 
762fe2efc57SMark    Level: intermediate
763fe2efc57SMark .seealso:  PetscPartitionerView(), PetscObjectViewFromOptions()
764fe2efc57SMark @*/
765fe2efc57SMark PetscErrorCode PetscPartitionerViewFromOptions(PetscPartitioner A,PetscObject obj,const char name[])
766fe2efc57SMark {
767fe2efc57SMark   PetscErrorCode ierr;
768fe2efc57SMark 
769fe2efc57SMark   PetscFunctionBegin;
770fe2efc57SMark   PetscValidHeaderSpecific(A,PETSCPARTITIONER_CLASSID,1);
771fe2efc57SMark   ierr = PetscObjectViewFromOptions((PetscObject)A,obj,name);CHKERRQ(ierr);
772fe2efc57SMark   PetscFunctionReturn(0);
773fe2efc57SMark }
774fe2efc57SMark 
775fe2efc57SMark /*@C
77677623264SMatthew G. Knepley   PetscPartitionerView - Views a PetscPartitioner
77777623264SMatthew G. Knepley 
778fe2efc57SMark   Collective on PetscPartitioner
77977623264SMatthew G. Knepley 
78077623264SMatthew G. Knepley   Input Parameter:
78177623264SMatthew G. Knepley + part - the PetscPartitioner object to view
78277623264SMatthew G. Knepley - v    - the viewer
78377623264SMatthew G. Knepley 
78477623264SMatthew G. Knepley   Level: developer
78577623264SMatthew G. Knepley 
78677623264SMatthew G. Knepley .seealso: PetscPartitionerDestroy()
78777623264SMatthew G. Knepley @*/
78877623264SMatthew G. Knepley PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v)
78977623264SMatthew G. Knepley {
790ffc59708SMatthew G. Knepley   PetscMPIInt    size;
7912abdaa70SMatthew G. Knepley   PetscBool      isascii;
79277623264SMatthew G. Knepley   PetscErrorCode ierr;
79377623264SMatthew G. Knepley 
79477623264SMatthew G. Knepley   PetscFunctionBegin;
79577623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
79677623264SMatthew G. Knepley   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v);CHKERRQ(ierr);}
7972abdaa70SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
7982abdaa70SMatthew G. Knepley   if (isascii) {
7992abdaa70SMatthew G. Knepley     ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
800ffc59708SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "Graph Partitioner: %d MPI Process%s\n", size, size > 1 ? "es" : "");CHKERRQ(ierr);
8012abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "  type: %s\n", part->hdr.type_name);CHKERRQ(ierr);
8022abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "  edge cut: %D\n", part->edgeCut);CHKERRQ(ierr);
8032abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "  balance: %.2g\n", part->balance);CHKERRQ(ierr);
804*3c41b853SStefano Zampini     ierr = PetscViewerASCIIPrintf(v, "  use vertex weights: %d\n", part->usevwgt);CHKERRQ(ierr);
8052abdaa70SMatthew G. Knepley   }
80677623264SMatthew G. Knepley   if (part->ops->view) {ierr = (*part->ops->view)(part, v);CHKERRQ(ierr);}
80777623264SMatthew G. Knepley   PetscFunctionReturn(0);
80877623264SMatthew G. Knepley }
80977623264SMatthew G. Knepley 
810a0058e54SToby Isaac static PetscErrorCode PetscPartitionerGetDefaultType(const char *currentType, const char **defaultType)
811a0058e54SToby Isaac {
812a0058e54SToby Isaac   PetscFunctionBegin;
813a0058e54SToby Isaac   if (!currentType) {
81456bf5a81SLisandro Dalcin #if defined(PETSC_HAVE_PARMETIS)
815a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERPARMETIS;
816137cd93aSLisandro Dalcin #elif defined(PETSC_HAVE_PTSCOTCH)
817137cd93aSLisandro Dalcin     *defaultType = PETSCPARTITIONERPTSCOTCH;
81856bf5a81SLisandro Dalcin #elif defined(PETSC_HAVE_CHACO)
81956bf5a81SLisandro Dalcin     *defaultType = PETSCPARTITIONERCHACO;
820a0058e54SToby Isaac #else
821a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERSIMPLE;
822a0058e54SToby Isaac #endif
823a0058e54SToby Isaac   } else {
824a0058e54SToby Isaac     *defaultType = currentType;
825a0058e54SToby Isaac   }
826a0058e54SToby Isaac   PetscFunctionReturn(0);
827a0058e54SToby Isaac }
828a0058e54SToby Isaac 
82977623264SMatthew G. Knepley /*@
83077623264SMatthew G. Knepley   PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database
83177623264SMatthew G. Knepley 
832fe2efc57SMark   Collective on PetscPartitioner
83377623264SMatthew G. Knepley 
83477623264SMatthew G. Knepley   Input Parameter:
83577623264SMatthew G. Knepley . part - the PetscPartitioner object to set options for
83677623264SMatthew G. Knepley 
837*3c41b853SStefano Zampini   Options Database Keys:
838*3c41b853SStefano Zampini +  -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types
839*3c41b853SStefano Zampini .  -petscpartitioner_use_vertex_weights - Uses weights associated with the graph vertices
840*3c41b853SStefano Zampini -  -petscpartitioner_view_graph - View the graph each time PetscPartitionerPartition is called. Viewer can be customized, see PetscOptionsGetViewer()
841*3c41b853SStefano Zampini 
84277623264SMatthew G. Knepley   Level: developer
84377623264SMatthew G. Knepley 
844*3c41b853SStefano Zampini .seealso: PetscPartitionerView(), PetscPartitionerSetType(), PetscPartitionerPartition()
84577623264SMatthew G. Knepley @*/
84677623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part)
84777623264SMatthew G. Knepley {
8486bb9daa8SLisandro Dalcin   const char    *defaultType;
8496bb9daa8SLisandro Dalcin   char           name[256];
8506bb9daa8SLisandro Dalcin   PetscBool      flg;
85177623264SMatthew G. Knepley   PetscErrorCode ierr;
85277623264SMatthew G. Knepley 
85377623264SMatthew G. Knepley   PetscFunctionBegin;
85477623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
8556bb9daa8SLisandro Dalcin   ierr = PetscPartitionerGetDefaultType(((PetscObject) part)->type_name,&defaultType);CHKERRQ(ierr);
85677623264SMatthew G. Knepley   ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr);
8576bb9daa8SLisandro Dalcin   ierr = PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, defaultType, name, sizeof(name), &flg);CHKERRQ(ierr);
8586bb9daa8SLisandro Dalcin   if (flg) {
8596bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, name);CHKERRQ(ierr);
8606bb9daa8SLisandro Dalcin   } else if (!((PetscObject) part)->type_name) {
8616bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, defaultType);CHKERRQ(ierr);
8626bb9daa8SLisandro Dalcin   }
863*3c41b853SStefano Zampini   ierr = PetscOptionsBool("-petscpartitioner_use_vertex_weights","Use vertex weights","",part->usevwgt,&part->usevwgt,NULL);CHKERRQ(ierr);
8646bb9daa8SLisandro Dalcin   if (part->ops->setfromoptions) {
8656bb9daa8SLisandro Dalcin     ierr = (*part->ops->setfromoptions)(PetscOptionsObject,part);CHKERRQ(ierr);
8666bb9daa8SLisandro Dalcin   }
867*3c41b853SStefano Zampini   ierr = PetscViewerDestroy(&part->viewer);CHKERRQ(ierr);
868783e1fb6SStefano Zampini   ierr = PetscViewerDestroy(&part->viewerGraph);CHKERRQ(ierr);
869*3c41b853SStefano Zampini   ierr = PetscOptionsGetViewer(((PetscObject) part)->comm, ((PetscObject) part)->options, ((PetscObject) part)->prefix, "-petscpartitioner_view", &part->viewer, NULL, NULL);CHKERRQ(ierr);
870*3c41b853SStefano Zampini   ierr = PetscOptionsGetViewer(((PetscObject) part)->comm, ((PetscObject) part)->options, ((PetscObject) part)->prefix, "-petscpartitioner_view_graph", &part->viewerGraph, NULL, &part->viewGraph);CHKERRQ(ierr);
87177623264SMatthew G. Knepley   /* process any options handlers added with PetscObjectAddOptionsHandler() */
8720633abcbSJed Brown   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) part);CHKERRQ(ierr);
87377623264SMatthew G. Knepley   ierr = PetscOptionsEnd();CHKERRQ(ierr);
87477623264SMatthew G. Knepley   PetscFunctionReturn(0);
87577623264SMatthew G. Knepley }
87677623264SMatthew G. Knepley 
87777623264SMatthew G. Knepley /*@C
87877623264SMatthew G. Knepley   PetscPartitionerSetUp - Construct data structures for the PetscPartitioner
87977623264SMatthew G. Knepley 
880fe2efc57SMark   Collective on PetscPartitioner
88177623264SMatthew G. Knepley 
88277623264SMatthew G. Knepley   Input Parameter:
88377623264SMatthew G. Knepley . part - the PetscPartitioner object to setup
88477623264SMatthew G. Knepley 
88577623264SMatthew G. Knepley   Level: developer
88677623264SMatthew G. Knepley 
88777623264SMatthew G. Knepley .seealso: PetscPartitionerView(), PetscPartitionerDestroy()
88877623264SMatthew G. Knepley @*/
88977623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part)
89077623264SMatthew G. Knepley {
89177623264SMatthew G. Knepley   PetscErrorCode ierr;
89277623264SMatthew G. Knepley 
89377623264SMatthew G. Knepley   PetscFunctionBegin;
89477623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
89577623264SMatthew G. Knepley   if (part->ops->setup) {ierr = (*part->ops->setup)(part);CHKERRQ(ierr);}
89677623264SMatthew G. Knepley   PetscFunctionReturn(0);
89777623264SMatthew G. Knepley }
89877623264SMatthew G. Knepley 
89977623264SMatthew G. Knepley /*@
90077623264SMatthew G. Knepley   PetscPartitionerDestroy - Destroys a PetscPartitioner object
90177623264SMatthew G. Knepley 
902fe2efc57SMark   Collective on PetscPartitioner
90377623264SMatthew G. Knepley 
90477623264SMatthew G. Knepley   Input Parameter:
90577623264SMatthew G. Knepley . part - the PetscPartitioner object to destroy
90677623264SMatthew G. Knepley 
90777623264SMatthew G. Knepley   Level: developer
90877623264SMatthew G. Knepley 
90977623264SMatthew G. Knepley .seealso: PetscPartitionerView()
91077623264SMatthew G. Knepley @*/
91177623264SMatthew G. Knepley PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part)
91277623264SMatthew G. Knepley {
91377623264SMatthew G. Knepley   PetscErrorCode ierr;
91477623264SMatthew G. Knepley 
91577623264SMatthew G. Knepley   PetscFunctionBegin;
91677623264SMatthew G. Knepley   if (!*part) PetscFunctionReturn(0);
91777623264SMatthew G. Knepley   PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1);
91877623264SMatthew G. Knepley 
91977623264SMatthew G. Knepley   if (--((PetscObject)(*part))->refct > 0) {*part = 0; PetscFunctionReturn(0);}
92077623264SMatthew G. Knepley   ((PetscObject) (*part))->refct = 0;
92177623264SMatthew G. Knepley 
922*3c41b853SStefano Zampini   ierr = PetscViewerDestroy(&(*part)->viewer);CHKERRQ(ierr);
9230358368aSMatthew G. Knepley   ierr = PetscViewerDestroy(&(*part)->viewerGraph);CHKERRQ(ierr);
92477623264SMatthew G. Knepley   if ((*part)->ops->destroy) {ierr = (*(*part)->ops->destroy)(*part);CHKERRQ(ierr);}
92577623264SMatthew G. Knepley   ierr = PetscHeaderDestroy(part);CHKERRQ(ierr);
92677623264SMatthew G. Knepley   PetscFunctionReturn(0);
92777623264SMatthew G. Knepley }
92877623264SMatthew G. Knepley 
92977623264SMatthew G. Knepley /*@
930*3c41b853SStefano Zampini   PetscPartitionerPartition - Partition a graph
931*3c41b853SStefano Zampini 
932*3c41b853SStefano Zampini   Collective on PetscPartitioner
933*3c41b853SStefano Zampini 
934*3c41b853SStefano Zampini   Input Parameters:
935*3c41b853SStefano Zampini + part    - The PetscPartitioner
936*3c41b853SStefano Zampini . nparts  - Number of partitions
937*3c41b853SStefano Zampini . numVertices - Number of vertices in the local part of the graph
938*3c41b853SStefano Zampini . start - row pointers for the local part of the graph (CSR style)
939*3c41b853SStefano Zampini . adjacency - adjacency list (CSR style)
940*3c41b853SStefano Zampini . vertexSection - PetscSection describing the absolute weight of each local vertex (can be NULL)
941*3c41b853SStefano Zampini - targetSection - PetscSection describing the absolute weight of each partition (can be NULL)
942*3c41b853SStefano Zampini 
943*3c41b853SStefano Zampini   Output Parameters:
944*3c41b853SStefano Zampini + partSection     - The PetscSection giving the division of points by partition
945*3c41b853SStefano Zampini - partition       - The list of points by partition
946*3c41b853SStefano Zampini 
947*3c41b853SStefano Zampini   Options Database:
948*3c41b853SStefano Zampini . -petscpartitioner_view - View the partitioner information
949*3c41b853SStefano Zampini . -petscpartitioner_view_graph - View the graph we are partitioning
950*3c41b853SStefano Zampini 
951*3c41b853SStefano Zampini   Notes:
952*3c41b853SStefano Zampini     The chart of the vertexSection (if present) must contain [0,numVertices), with the number of dofs in the section specifying the absolute weight for each vertex.
953*3c41b853SStefano Zampini     The chart of the targetSection (if present) must contain [0,nparts), with the number of dofs in the section specifying the absolute weight for each partition. This information must be the same across processes, PETSc does not check it.
954*3c41b853SStefano Zampini 
955*3c41b853SStefano Zampini   Level: developer
956*3c41b853SStefano Zampini 
957*3c41b853SStefano Zampini .seealso PetscPartitionerCreate(), PetscSectionCreate(), PetscSectionSetChart(), PetscSectionSetDof()
958*3c41b853SStefano Zampini @*/
959*3c41b853SStefano Zampini PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertexSection, PetscSection targetSection, PetscSection partSection, IS *partition)
960*3c41b853SStefano Zampini {
961*3c41b853SStefano Zampini   PetscErrorCode ierr;
962*3c41b853SStefano Zampini 
963*3c41b853SStefano Zampini   PetscFunctionBegin;
964*3c41b853SStefano Zampini   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
965*3c41b853SStefano Zampini   PetscValidLogicalCollectiveInt(part, nparts, 2);
966*3c41b853SStefano Zampini   if (nparts <= 0) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Number of parts must be positive");
967*3c41b853SStefano Zampini   if (numVertices < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices must be non-negative");
968*3c41b853SStefano Zampini   if (numVertices && !part->noGraph) {
969*3c41b853SStefano Zampini     PetscValidIntPointer(start, 4);
970*3c41b853SStefano Zampini     PetscValidIntPointer(adjacency, 5);
971*3c41b853SStefano Zampini   }
972*3c41b853SStefano Zampini   if (vertexSection) {
973*3c41b853SStefano Zampini     PetscInt s,e;
974*3c41b853SStefano Zampini 
975*3c41b853SStefano Zampini     PetscValidHeaderSpecific(vertexSection, PETSC_SECTION_CLASSID, 6);
976*3c41b853SStefano Zampini     ierr = PetscSectionGetChart(vertexSection, &s, &e);CHKERRQ(ierr);
977*3c41b853SStefano Zampini     if (s > 0 || e < numVertices) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Invalid vertexSection chart [%D,%D)",s,e);
978*3c41b853SStefano Zampini   }
979*3c41b853SStefano Zampini   if (targetSection) {
980*3c41b853SStefano Zampini     PetscInt s,e;
981*3c41b853SStefano Zampini 
982*3c41b853SStefano Zampini     PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 7);
983*3c41b853SStefano Zampini     ierr = PetscSectionGetChart(targetSection, &s, &e);CHKERRQ(ierr);
984*3c41b853SStefano Zampini     if (s > 0 || e < nparts) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Invalid targetSection chart [%D,%D)",s,e);
985*3c41b853SStefano Zampini   }
986*3c41b853SStefano Zampini   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 8);
987*3c41b853SStefano Zampini   PetscValidPointer(partition, 9);
988*3c41b853SStefano Zampini 
989*3c41b853SStefano Zampini   ierr = PetscSectionReset(partSection);CHKERRQ(ierr);
990*3c41b853SStefano Zampini   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
991*3c41b853SStefano Zampini   if (nparts == 1) { /* quick */
992*3c41b853SStefano Zampini     ierr = PetscSectionSetDof(partSection, 0, numVertices);CHKERRQ(ierr);
993*3c41b853SStefano Zampini     ierr = ISCreateStride(PetscObjectComm((PetscObject)part),numVertices,0,1,partition);CHKERRQ(ierr);
994*3c41b853SStefano Zampini   } else {
995*3c41b853SStefano Zampini     if (!part->ops->partition) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "PetscPartitioner %s has no partitioning method", ((PetscObject)part)->type_name);
996*3c41b853SStefano Zampini     ierr = (*part->ops->partition)(part, nparts, numVertices, start, adjacency, vertexSection, targetSection, partSection, partition);CHKERRQ(ierr);
997*3c41b853SStefano Zampini   }
998*3c41b853SStefano Zampini   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
999*3c41b853SStefano Zampini   if (part->viewerGraph) {
1000*3c41b853SStefano Zampini     PetscViewer viewer = part->viewerGraph;
1001*3c41b853SStefano Zampini     PetscBool   isascii;
1002*3c41b853SStefano Zampini     PetscInt    v, i;
1003*3c41b853SStefano Zampini     PetscMPIInt rank;
1004*3c41b853SStefano Zampini 
1005*3c41b853SStefano Zampini     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) viewer), &rank);CHKERRQ(ierr);
1006*3c41b853SStefano Zampini     ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
1007*3c41b853SStefano Zampini     if (isascii) {
1008*3c41b853SStefano Zampini       ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
1009*3c41b853SStefano Zampini       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]Nv: %D\n", rank, numVertices);CHKERRQ(ierr);
1010*3c41b853SStefano Zampini       for (v = 0; v < numVertices; ++v) {
1011*3c41b853SStefano Zampini         const PetscInt s = start[v];
1012*3c41b853SStefano Zampini         const PetscInt e = start[v+1];
1013*3c41b853SStefano Zampini 
1014*3c41b853SStefano Zampini         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]  ", rank);CHKERRQ(ierr);
1015*3c41b853SStefano Zampini         for (i = s; i < e; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%D ", adjacency[i]);CHKERRQ(ierr);}
1016*3c41b853SStefano Zampini         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D-%D)\n", s, e);CHKERRQ(ierr);
1017*3c41b853SStefano Zampini       }
1018*3c41b853SStefano Zampini       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
1019*3c41b853SStefano Zampini       ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
1020*3c41b853SStefano Zampini     }
1021*3c41b853SStefano Zampini   }
1022*3c41b853SStefano Zampini   if (part->viewer) {
1023*3c41b853SStefano Zampini     ierr = PetscPartitionerView(part,part->viewer);CHKERRQ(ierr);
1024*3c41b853SStefano Zampini   }
1025*3c41b853SStefano Zampini   PetscFunctionReturn(0);
1026*3c41b853SStefano Zampini }
1027*3c41b853SStefano Zampini 
1028*3c41b853SStefano Zampini /*@
102977623264SMatthew G. Knepley   PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType().
103077623264SMatthew G. Knepley 
1031d083f849SBarry Smith   Collective
103277623264SMatthew G. Knepley 
103377623264SMatthew G. Knepley   Input Parameter:
103477623264SMatthew G. Knepley . comm - The communicator for the PetscPartitioner object
103577623264SMatthew G. Knepley 
103677623264SMatthew G. Knepley   Output Parameter:
103777623264SMatthew G. Knepley . part - The PetscPartitioner object
103877623264SMatthew G. Knepley 
103977623264SMatthew G. Knepley   Level: beginner
104077623264SMatthew G. Knepley 
1041dae52e14SToby Isaac .seealso: PetscPartitionerSetType(), PETSCPARTITIONERCHACO, PETSCPARTITIONERPARMETIS, PETSCPARTITIONERSHELL, PETSCPARTITIONERSIMPLE, PETSCPARTITIONERGATHER
104277623264SMatthew G. Knepley @*/
104377623264SMatthew G. Knepley PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
104477623264SMatthew G. Knepley {
104577623264SMatthew G. Knepley   PetscPartitioner p;
1046a0058e54SToby Isaac   const char       *partitionerType = NULL;
104777623264SMatthew G. Knepley   PetscErrorCode   ierr;
104877623264SMatthew G. Knepley 
104977623264SMatthew G. Knepley   PetscFunctionBegin;
105077623264SMatthew G. Knepley   PetscValidPointer(part, 2);
105177623264SMatthew G. Knepley   *part = NULL;
105283cde681SMatthew G. Knepley   ierr = DMInitializePackage();CHKERRQ(ierr);
105377623264SMatthew G. Knepley 
105473107ff1SLisandro Dalcin   ierr = PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView);CHKERRQ(ierr);
1055a0058e54SToby Isaac   ierr = PetscPartitionerGetDefaultType(NULL,&partitionerType);CHKERRQ(ierr);
1056a0058e54SToby Isaac   ierr = PetscPartitionerSetType(p,partitionerType);CHKERRQ(ierr);
105777623264SMatthew G. Knepley 
105872379da4SMatthew G. Knepley   p->edgeCut = 0;
105972379da4SMatthew G. Knepley   p->balance = 0.0;
1060*3c41b853SStefano Zampini   p->usevwgt = PETSC_TRUE;
106172379da4SMatthew G. Knepley 
106277623264SMatthew G. Knepley   *part = p;
106377623264SMatthew G. Knepley   PetscFunctionReturn(0);
106477623264SMatthew G. Knepley }
106577623264SMatthew G. Knepley 
106677623264SMatthew G. Knepley /*@
1067*3c41b853SStefano Zampini   PetscPartitionerDMPlexPartition - Create a non-overlapping partition of the cells in the mesh
106877623264SMatthew G. Knepley 
1069fe2efc57SMark   Collective on PetscPartitioner
107077623264SMatthew G. Knepley 
107177623264SMatthew G. Knepley   Input Parameters:
107277623264SMatthew G. Knepley + part    - The PetscPartitioner
1073*3c41b853SStefano Zampini . targetSection - The PetscSection describing the absolute weight of each partition (can be NULL)
1074f8987ae8SMichael Lange - dm      - The mesh DM
107577623264SMatthew G. Knepley 
107677623264SMatthew G. Knepley   Output Parameters:
107777623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
1078f8987ae8SMichael Lange - partition       - The list of points by partition
107977623264SMatthew G. Knepley 
1080*3c41b853SStefano Zampini   Notes:
1081*3c41b853SStefano Zampini     If the DM has a local section associated, each point to be partitioned will be weighted by the total number of dofs identified
1082*3c41b853SStefano Zampini     by the section in the transitive closure of the point.
108377623264SMatthew G. Knepley 
108477623264SMatthew G. Knepley   Level: developer
108577623264SMatthew G. Knepley 
1086*3c41b853SStefano Zampini .seealso DMPlexDistribute(), PetscPartitionerCreate(), PetscSectionCreate(), PetscSectionSetChart(), PetscPartitionerPartition()
10874b15ede2SMatthew G. Knepley @*/
1088*3c41b853SStefano Zampini PetscErrorCode PetscPartitionerDMPlexPartition(PetscPartitioner part, DM dm, PetscSection targetSection, PetscSection partSection, IS *partition)
108977623264SMatthew G. Knepley {
109077623264SMatthew G. Knepley   PetscMPIInt    size;
1091*3c41b853SStefano Zampini   PetscBool      isplex;
109277623264SMatthew G. Knepley   PetscErrorCode ierr;
1093*3c41b853SStefano Zampini   PetscSection   vertSection = NULL;
109477623264SMatthew G. Knepley 
109577623264SMatthew G. Knepley   PetscFunctionBegin;
109677623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
109777623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1098*3c41b853SStefano Zampini   if (targetSection) PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 3);
109977623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
110077623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
1101*3c41b853SStefano Zampini   ierr = PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isplex);CHKERRQ(ierr);
1102*3c41b853SStefano Zampini   if (!isplex) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Not for type %s",((PetscObject)dm)->type_name);
110377623264SMatthew G. Knepley   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
110477623264SMatthew G. Knepley   if (size == 1) {
110577623264SMatthew G. Knepley     PetscInt *points;
110677623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
110777623264SMatthew G. Knepley 
110877623264SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
1109*3c41b853SStefano Zampini     ierr = PetscSectionReset(partSection);CHKERRQ(ierr);
111077623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr);
111177623264SMatthew G. Knepley     ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr);
111277623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
111377623264SMatthew G. Knepley     ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr);
111477623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
111577623264SMatthew G. Knepley     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
111677623264SMatthew G. Knepley     PetscFunctionReturn(0);
111777623264SMatthew G. Knepley   }
111877623264SMatthew G. Knepley   if (part->height == 0) {
1119074d466cSStefano Zampini     PetscInt numVertices = 0;
112077623264SMatthew G. Knepley     PetscInt *start     = NULL;
112177623264SMatthew G. Knepley     PetscInt *adjacency = NULL;
11223fa7752dSToby Isaac     IS       globalNumbering;
112377623264SMatthew G. Knepley 
1124074d466cSStefano Zampini     if (!part->noGraph || part->viewGraph) {
1125074d466cSStefano Zampini       ierr = DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering);CHKERRQ(ierr);
112613911537SStefano Zampini     } else { /* only compute the number of owned local vertices */
1127074d466cSStefano Zampini       const PetscInt *idxs;
1128074d466cSStefano Zampini       PetscInt       p, pStart, pEnd;
1129074d466cSStefano Zampini 
1130074d466cSStefano Zampini       ierr = DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd);CHKERRQ(ierr);
11319886b8cfSStefano Zampini       ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering);CHKERRQ(ierr);
1132074d466cSStefano Zampini       ierr = ISGetIndices(globalNumbering, &idxs);CHKERRQ(ierr);
1133074d466cSStefano Zampini       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
1134074d466cSStefano Zampini       ierr = ISRestoreIndices(globalNumbering, &idxs);CHKERRQ(ierr);
1135074d466cSStefano Zampini     }
1136*3c41b853SStefano Zampini     if (part->usevwgt) {
1137*3c41b853SStefano Zampini       PetscSection   section = dm->localSection, clSection = NULL;
1138*3c41b853SStefano Zampini       IS             clPoints = NULL;
1139*3c41b853SStefano Zampini       const PetscInt *gid,*clIdx;
1140*3c41b853SStefano Zampini       PetscInt       v, p, pStart, pEnd;
11410358368aSMatthew G. Knepley 
1142*3c41b853SStefano Zampini       /* dm->localSection encodes degrees of freedom per point, not per cell. We need to get the closure index to properly specify cell weights (aka dofs) */
1143*3c41b853SStefano Zampini       /* We do this only if the local section has been set */
1144*3c41b853SStefano Zampini       if (section) {
1145*3c41b853SStefano Zampini         ierr = PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, NULL);CHKERRQ(ierr);
1146*3c41b853SStefano Zampini         if (!clSection) {
1147*3c41b853SStefano Zampini           ierr = DMPlexCreateClosureIndex(dm,NULL);CHKERRQ(ierr);
1148*3c41b853SStefano Zampini         }
1149*3c41b853SStefano Zampini         ierr = PetscSectionGetClosureIndex(section, (PetscObject)dm, &clSection, &clPoints);CHKERRQ(ierr);
1150*3c41b853SStefano Zampini         ierr = ISGetIndices(clPoints,&clIdx);CHKERRQ(ierr);
1151*3c41b853SStefano Zampini       }
1152*3c41b853SStefano Zampini       ierr = DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd);CHKERRQ(ierr);
1153*3c41b853SStefano Zampini       ierr = PetscSectionCreate(PETSC_COMM_SELF, &vertSection);CHKERRQ(ierr);
1154*3c41b853SStefano Zampini       ierr = PetscSectionSetChart(vertSection, 0, numVertices);CHKERRQ(ierr);
1155*3c41b853SStefano Zampini       if (globalNumbering) {
1156*3c41b853SStefano Zampini         ierr = ISGetIndices(globalNumbering,&gid);CHKERRQ(ierr);
1157*3c41b853SStefano Zampini       } else gid = NULL;
1158*3c41b853SStefano Zampini       for (p = pStart, v = 0; p < pEnd; ++p) {
1159*3c41b853SStefano Zampini         PetscInt dof = 1;
11600358368aSMatthew G. Knepley 
1161*3c41b853SStefano Zampini         /* skip cells in the overlap */
1162*3c41b853SStefano Zampini         if (gid && gid[p-pStart] < 0) continue;
1163*3c41b853SStefano Zampini 
1164*3c41b853SStefano Zampini         if (section) {
1165*3c41b853SStefano Zampini           PetscInt cl, clSize, clOff;
1166*3c41b853SStefano Zampini 
1167*3c41b853SStefano Zampini           dof  = 0;
1168*3c41b853SStefano Zampini           ierr = PetscSectionGetDof(clSection, p, &clSize);CHKERRQ(ierr);
1169*3c41b853SStefano Zampini           ierr = PetscSectionGetOffset(clSection, p, &clOff);CHKERRQ(ierr);
1170*3c41b853SStefano Zampini           for (cl = 0; cl < clSize; cl+=2) {
1171*3c41b853SStefano Zampini             PetscInt clDof, clPoint = clIdx[clOff + cl]; /* odd indices are reserved for orientations */
1172*3c41b853SStefano Zampini 
1173*3c41b853SStefano Zampini             ierr = PetscSectionGetDof(section, clPoint, &clDof);CHKERRQ(ierr);
1174*3c41b853SStefano Zampini             dof += clDof;
11750358368aSMatthew G. Knepley           }
11760358368aSMatthew G. Knepley         }
1177*3c41b853SStefano Zampini         if (!dof) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of dofs for point %D in the local section should be positive",p);
1178*3c41b853SStefano Zampini         ierr = PetscSectionSetDof(vertSection, v, dof);CHKERRQ(ierr);
1179*3c41b853SStefano Zampini         v++;
1180*3c41b853SStefano Zampini       }
1181*3c41b853SStefano Zampini       if (globalNumbering) {
1182*3c41b853SStefano Zampini         ierr = ISRestoreIndices(globalNumbering,&gid);CHKERRQ(ierr);
1183*3c41b853SStefano Zampini       }
1184*3c41b853SStefano Zampini       if (clPoints) {
1185*3c41b853SStefano Zampini         ierr = ISRestoreIndices(clPoints,&clIdx);CHKERRQ(ierr);
1186*3c41b853SStefano Zampini       }
1187*3c41b853SStefano Zampini       ierr = PetscSectionSetUp(vertSection);CHKERRQ(ierr);
1188*3c41b853SStefano Zampini     }
1189*3c41b853SStefano Zampini     ierr = PetscPartitionerPartition(part, size, numVertices, start, adjacency, vertSection, targetSection, partSection, partition);CHKERRQ(ierr);
119077623264SMatthew G. Knepley     ierr = PetscFree(start);CHKERRQ(ierr);
119177623264SMatthew G. Knepley     ierr = PetscFree(adjacency);CHKERRQ(ierr);
11923fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
11933fa7752dSToby Isaac       const PetscInt *globalNum;
11943fa7752dSToby Isaac       const PetscInt *partIdx;
11953fa7752dSToby Isaac       PetscInt       *map, cStart, cEnd;
11963fa7752dSToby Isaac       PetscInt       *adjusted, i, localSize, offset;
11973fa7752dSToby Isaac       IS             newPartition;
11983fa7752dSToby Isaac 
11993fa7752dSToby Isaac       ierr = ISGetLocalSize(*partition,&localSize);CHKERRQ(ierr);
12003fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&adjusted);CHKERRQ(ierr);
12013fa7752dSToby Isaac       ierr = ISGetIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
12023fa7752dSToby Isaac       ierr = ISGetIndices(*partition,&partIdx);CHKERRQ(ierr);
12033fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&map);CHKERRQ(ierr);
12043fa7752dSToby Isaac       ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
12053fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
12063fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
12073fa7752dSToby Isaac       }
12083fa7752dSToby Isaac       for (i = 0; i < localSize; i++) {
12093fa7752dSToby Isaac         adjusted[i] = map[partIdx[i]];
12103fa7752dSToby Isaac       }
12113fa7752dSToby Isaac       ierr = PetscFree(map);CHKERRQ(ierr);
12123fa7752dSToby Isaac       ierr = ISRestoreIndices(*partition,&partIdx);CHKERRQ(ierr);
12133fa7752dSToby Isaac       ierr = ISRestoreIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
12143fa7752dSToby Isaac       ierr = ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition);CHKERRQ(ierr);
12153fa7752dSToby Isaac       ierr = ISDestroy(&globalNumbering);CHKERRQ(ierr);
12163fa7752dSToby Isaac       ierr = ISDestroy(partition);CHKERRQ(ierr);
12173fa7752dSToby Isaac       *partition = newPartition;
12183fa7752dSToby Isaac     }
121977623264SMatthew G. Knepley   } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height);
1220*3c41b853SStefano Zampini   ierr = PetscSectionDestroy(&vertSection);CHKERRQ(ierr);
122177623264SMatthew G. Knepley   PetscFunctionReturn(0);
122277623264SMatthew G. Knepley }
122377623264SMatthew G. Knepley 
1224d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Shell(PetscPartitioner part)
122577623264SMatthew G. Knepley {
122677623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
122777623264SMatthew G. Knepley   PetscErrorCode          ierr;
122877623264SMatthew G. Knepley 
122977623264SMatthew G. Knepley   PetscFunctionBegin;
123077623264SMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
123177623264SMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
123277623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
123377623264SMatthew G. Knepley   PetscFunctionReturn(0);
123477623264SMatthew G. Knepley }
123577623264SMatthew G. Knepley 
1236d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell_Ascii(PetscPartitioner part, PetscViewer viewer)
123777623264SMatthew G. Knepley {
1238077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
123977623264SMatthew G. Knepley   PetscErrorCode          ierr;
124077623264SMatthew G. Knepley 
124177623264SMatthew G. Knepley   PetscFunctionBegin;
1242077101c0SMatthew G. Knepley   if (p->random) {
1243077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1244077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(viewer, "using random partition\n");CHKERRQ(ierr);
1245077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1246077101c0SMatthew G. Knepley   }
124777623264SMatthew G. Knepley   PetscFunctionReturn(0);
124877623264SMatthew G. Knepley }
124977623264SMatthew G. Knepley 
1250d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell(PetscPartitioner part, PetscViewer viewer)
125177623264SMatthew G. Knepley {
125277623264SMatthew G. Knepley   PetscBool      iascii;
125377623264SMatthew G. Knepley   PetscErrorCode ierr;
125477623264SMatthew G. Knepley 
125577623264SMatthew G. Knepley   PetscFunctionBegin;
125677623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
125777623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
125877623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
125977623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Shell_Ascii(part, viewer);CHKERRQ(ierr);}
126077623264SMatthew G. Knepley   PetscFunctionReturn(0);
126177623264SMatthew G. Knepley }
126277623264SMatthew G. Knepley 
1263d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerSetFromOptions_Shell(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
1264077101c0SMatthew G. Knepley {
1265077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1266077101c0SMatthew G. Knepley   PetscErrorCode          ierr;
1267077101c0SMatthew G. Knepley 
1268077101c0SMatthew G. Knepley   PetscFunctionBegin;
1269077101c0SMatthew G. Knepley   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner Shell Options");CHKERRQ(ierr);
1270077101c0SMatthew G. Knepley   ierr = PetscOptionsBool("-petscpartitioner_shell_random", "Use a random partition", "PetscPartitionerView", PETSC_FALSE, &p->random, NULL);CHKERRQ(ierr);
1271077101c0SMatthew G. Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1272077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1273077101c0SMatthew G. Knepley }
1274077101c0SMatthew G. Knepley 
1275*3c41b853SStefano Zampini static PetscErrorCode PetscPartitionerPartition_Shell(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertSection, PetscSection targetSection, PetscSection partSection, IS *partition)
127677623264SMatthew G. Knepley {
127777623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
127877623264SMatthew G. Knepley   PetscInt                np;
127977623264SMatthew G. Knepley   PetscErrorCode          ierr;
128077623264SMatthew G. Knepley 
128177623264SMatthew G. Knepley   PetscFunctionBegin;
1282077101c0SMatthew G. Knepley   if (p->random) {
1283077101c0SMatthew G. Knepley     PetscRandom r;
1284aa1d5631SMatthew G. Knepley     PetscInt   *sizes, *points, v, p;
1285aa1d5631SMatthew G. Knepley     PetscMPIInt rank;
1286077101c0SMatthew G. Knepley 
1287*3c41b853SStefano Zampini     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) part), &rank);CHKERRQ(ierr);
1288077101c0SMatthew G. Knepley     ierr = PetscRandomCreate(PETSC_COMM_SELF, &r);CHKERRQ(ierr);
1289c717d290SMatthew G. Knepley     ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) nparts);CHKERRQ(ierr);
1290077101c0SMatthew G. Knepley     ierr = PetscRandomSetFromOptions(r);CHKERRQ(ierr);
1291077101c0SMatthew G. Knepley     ierr = PetscCalloc2(nparts, &sizes, numVertices, &points);CHKERRQ(ierr);
1292aa1d5631SMatthew G. Knepley     for (v = 0; v < numVertices; ++v) {points[v] = v;}
1293ac9a96f1SMichael Lange     for (p = 0; p < nparts; ++p) {sizes[p] = numVertices/nparts + (PetscInt) (p < numVertices % nparts);}
1294aa1d5631SMatthew G. Knepley     for (v = numVertices-1; v > 0; --v) {
1295077101c0SMatthew G. Knepley       PetscReal val;
1296aa1d5631SMatthew G. Knepley       PetscInt  w, tmp;
1297077101c0SMatthew G. Knepley 
1298aa1d5631SMatthew G. Knepley       ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) (v+1));CHKERRQ(ierr);
1299077101c0SMatthew G. Knepley       ierr = PetscRandomGetValueReal(r, &val);CHKERRQ(ierr);
1300aa1d5631SMatthew G. Knepley       w    = PetscFloorReal(val);
1301aa1d5631SMatthew G. Knepley       tmp       = points[v];
1302aa1d5631SMatthew G. Knepley       points[v] = points[w];
1303aa1d5631SMatthew G. Knepley       points[w] = tmp;
1304077101c0SMatthew G. Knepley     }
1305077101c0SMatthew G. Knepley     ierr = PetscRandomDestroy(&r);CHKERRQ(ierr);
1306077101c0SMatthew G. Knepley     ierr = PetscPartitionerShellSetPartition(part, nparts, sizes, points);CHKERRQ(ierr);
1307077101c0SMatthew G. Knepley     ierr = PetscFree2(sizes, points);CHKERRQ(ierr);
1308077101c0SMatthew G. Knepley   }
1309*3c41b853SStefano Zampini   if (!p->section) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_WRONG, "Shell partitioner information not provided. Please call PetscPartitionerShellSetPartition()");
131077623264SMatthew G. Knepley   ierr = PetscSectionGetChart(p->section, NULL, &np);CHKERRQ(ierr);
131177623264SMatthew G. Knepley   if (nparts != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of requested partitions %d != configured partitions %d", nparts, np);
131277623264SMatthew G. Knepley   ierr = ISGetLocalSize(p->partition, &np);CHKERRQ(ierr);
131377623264SMatthew G. Knepley   if (numVertices != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input vertices %d != configured vertices %d", numVertices, np);
13145680f57bSMatthew G. Knepley   ierr = PetscSectionCopy(p->section, partSection);CHKERRQ(ierr);
131577623264SMatthew G. Knepley   *partition = p->partition;
131677623264SMatthew G. Knepley   ierr = PetscObjectReference((PetscObject) p->partition);CHKERRQ(ierr);
131777623264SMatthew G. Knepley   PetscFunctionReturn(0);
131877623264SMatthew G. Knepley }
131977623264SMatthew G. Knepley 
1320d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Shell(PetscPartitioner part)
132177623264SMatthew G. Knepley {
132277623264SMatthew G. Knepley   PetscFunctionBegin;
1323074d466cSStefano Zampini   part->noGraph             = PETSC_TRUE; /* PetscPartitionerShell cannot overload the partition call, so it is safe for now */
132477623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_Shell;
1325077101c0SMatthew G. Knepley   part->ops->setfromoptions = PetscPartitionerSetFromOptions_Shell;
132677623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_Shell;
132777623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_Shell;
132877623264SMatthew G. Knepley   PetscFunctionReturn(0);
132977623264SMatthew G. Knepley }
133077623264SMatthew G. Knepley 
133177623264SMatthew G. Knepley /*MC
133277623264SMatthew G. Knepley   PETSCPARTITIONERSHELL = "shell" - A PetscPartitioner object
133377623264SMatthew G. Knepley 
133477623264SMatthew G. Knepley   Level: intermediate
133577623264SMatthew G. Knepley 
1336*3c41b853SStefano Zampini   Options Database Keys:
1337*3c41b853SStefano Zampini .  -petscpartitioner_shell_random - Use a random partition
1338*3c41b853SStefano Zampini 
133977623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
134077623264SMatthew G. Knepley M*/
134177623264SMatthew G. Knepley 
134277623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Shell(PetscPartitioner part)
134377623264SMatthew G. Knepley {
134477623264SMatthew G. Knepley   PetscPartitioner_Shell *p;
134577623264SMatthew G. Knepley   PetscErrorCode          ierr;
134677623264SMatthew G. Knepley 
134777623264SMatthew G. Knepley   PetscFunctionBegin;
134877623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
134977623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
135077623264SMatthew G. Knepley   part->data = p;
135177623264SMatthew G. Knepley 
135277623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Shell(part);CHKERRQ(ierr);
1353077101c0SMatthew G. Knepley   p->random = PETSC_FALSE;
135477623264SMatthew G. Knepley   PetscFunctionReturn(0);
135577623264SMatthew G. Knepley }
135677623264SMatthew G. Knepley 
13575680f57bSMatthew G. Knepley /*@C
13585680f57bSMatthew G. Knepley   PetscPartitionerShellSetPartition - Set an artifical partition for a mesh
13595680f57bSMatthew G. Knepley 
1360fe2efc57SMark   Collective on PetscPartitioner
13615680f57bSMatthew G. Knepley 
13625680f57bSMatthew G. Knepley   Input Parameters:
13635680f57bSMatthew G. Knepley + part   - The PetscPartitioner
13649852e123SBarry Smith . size   - The number of partitions
1365*3c41b853SStefano Zampini . sizes  - array of length size (or NULL) providing the number of points in each partition
1366*3c41b853SStefano Zampini - points - array of length 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.)
13675680f57bSMatthew G. Knepley 
13685680f57bSMatthew G. Knepley   Level: developer
13695680f57bSMatthew G. Knepley 
1370b7e49471SLawrence Mitchell   Notes:
1371b7e49471SLawrence Mitchell     It is safe to free the sizes and points arrays after use in this routine.
1372b7e49471SLawrence Mitchell 
13735680f57bSMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerCreate()
13745680f57bSMatthew G. Knepley @*/
13759852e123SBarry Smith PetscErrorCode PetscPartitionerShellSetPartition(PetscPartitioner part, PetscInt size, const PetscInt sizes[], const PetscInt points[])
13765680f57bSMatthew G. Knepley {
13775680f57bSMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
13785680f57bSMatthew G. Knepley   PetscInt                proc, numPoints;
13795680f57bSMatthew G. Knepley   PetscErrorCode          ierr;
13805680f57bSMatthew G. Knepley 
13815680f57bSMatthew G. Knepley   PetscFunctionBegin;
13825680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
13835680f57bSMatthew G. Knepley   if (sizes)  {PetscValidPointer(sizes, 3);}
1384c717d290SMatthew G. Knepley   if (points) {PetscValidPointer(points, 4);}
13855680f57bSMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
13865680f57bSMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
13875680f57bSMatthew G. Knepley   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) part), &p->section);CHKERRQ(ierr);
13889852e123SBarry Smith   ierr = PetscSectionSetChart(p->section, 0, size);CHKERRQ(ierr);
13895680f57bSMatthew G. Knepley   if (sizes) {
13909852e123SBarry Smith     for (proc = 0; proc < size; ++proc) {
13915680f57bSMatthew G. Knepley       ierr = PetscSectionSetDof(p->section, proc, sizes[proc]);CHKERRQ(ierr);
13925680f57bSMatthew G. Knepley     }
13935680f57bSMatthew G. Knepley   }
13945680f57bSMatthew G. Knepley   ierr = PetscSectionSetUp(p->section);CHKERRQ(ierr);
13955680f57bSMatthew G. Knepley   ierr = PetscSectionGetStorageSize(p->section, &numPoints);CHKERRQ(ierr);
13965680f57bSMatthew G. Knepley   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), numPoints, points, PETSC_COPY_VALUES, &p->partition);CHKERRQ(ierr);
13975680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
13985680f57bSMatthew G. Knepley }
13995680f57bSMatthew G. Knepley 
1400077101c0SMatthew G. Knepley /*@
1401077101c0SMatthew G. Knepley   PetscPartitionerShellSetRandom - Set the flag to use a random partition
1402077101c0SMatthew G. Knepley 
1403fe2efc57SMark   Collective on PetscPartitioner
1404077101c0SMatthew G. Knepley 
1405077101c0SMatthew G. Knepley   Input Parameters:
1406077101c0SMatthew G. Knepley + part   - The PetscPartitioner
1407077101c0SMatthew G. Knepley - random - The flag to use a random partition
1408077101c0SMatthew G. Knepley 
1409077101c0SMatthew G. Knepley   Level: intermediate
1410077101c0SMatthew G. Knepley 
1411077101c0SMatthew G. Knepley .seealso PetscPartitionerShellGetRandom(), PetscPartitionerCreate()
1412077101c0SMatthew G. Knepley @*/
1413077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellSetRandom(PetscPartitioner part, PetscBool random)
1414077101c0SMatthew G. Knepley {
1415077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1416077101c0SMatthew G. Knepley 
1417077101c0SMatthew G. Knepley   PetscFunctionBegin;
1418077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1419077101c0SMatthew G. Knepley   p->random = random;
1420077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1421077101c0SMatthew G. Knepley }
1422077101c0SMatthew G. Knepley 
1423077101c0SMatthew G. Knepley /*@
1424077101c0SMatthew G. Knepley   PetscPartitionerShellGetRandom - get the flag to use a random partition
1425077101c0SMatthew G. Knepley 
1426fe2efc57SMark   Collective on PetscPartitioner
1427077101c0SMatthew G. Knepley 
1428077101c0SMatthew G. Knepley   Input Parameter:
1429077101c0SMatthew G. Knepley . part   - The PetscPartitioner
1430077101c0SMatthew G. Knepley 
1431077101c0SMatthew G. Knepley   Output Parameter
1432077101c0SMatthew G. Knepley . random - The flag to use a random partition
1433077101c0SMatthew G. Knepley 
1434077101c0SMatthew G. Knepley   Level: intermediate
1435077101c0SMatthew G. Knepley 
1436077101c0SMatthew G. Knepley .seealso PetscPartitionerShellSetRandom(), PetscPartitionerCreate()
1437077101c0SMatthew G. Knepley @*/
1438077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellGetRandom(PetscPartitioner part, PetscBool *random)
1439077101c0SMatthew G. Knepley {
1440077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1441077101c0SMatthew G. Knepley 
1442077101c0SMatthew G. Knepley   PetscFunctionBegin;
1443077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1444077101c0SMatthew G. Knepley   PetscValidPointer(random, 2);
1445077101c0SMatthew G. Knepley   *random = p->random;
1446077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1447077101c0SMatthew G. Knepley }
1448077101c0SMatthew G. Knepley 
1449d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Simple(PetscPartitioner part)
1450555a9cf8SMatthew G. Knepley {
1451555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p = (PetscPartitioner_Simple *) part->data;
1452555a9cf8SMatthew G. Knepley   PetscErrorCode          ierr;
1453555a9cf8SMatthew G. Knepley 
1454555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1455555a9cf8SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
1456555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1457555a9cf8SMatthew G. Knepley }
1458555a9cf8SMatthew G. Knepley 
1459d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple_Ascii(PetscPartitioner part, PetscViewer viewer)
1460555a9cf8SMatthew G. Knepley {
1461555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1462555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1463555a9cf8SMatthew G. Knepley }
1464555a9cf8SMatthew G. Knepley 
1465d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple(PetscPartitioner part, PetscViewer viewer)
1466555a9cf8SMatthew G. Knepley {
1467555a9cf8SMatthew G. Knepley   PetscBool      iascii;
1468555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1469555a9cf8SMatthew G. Knepley 
1470555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1471555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1472555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1473555a9cf8SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1474555a9cf8SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Simple_Ascii(part, viewer);CHKERRQ(ierr);}
1475555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1476555a9cf8SMatthew G. Knepley }
1477555a9cf8SMatthew G. Knepley 
1478*3c41b853SStefano Zampini static PetscErrorCode PetscPartitionerPartition_Simple(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertSection, PetscSection targetSection, PetscSection partSection, IS *partition)
1479555a9cf8SMatthew G. Knepley {
1480cead94edSToby Isaac   MPI_Comm       comm;
1481*3c41b853SStefano Zampini   PetscInt       np, *tpwgts = NULL, sumw = 0, numVerticesGlobal  = 0;
1482cead94edSToby Isaac   PetscMPIInt    size;
1483555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1484555a9cf8SMatthew G. Knepley 
1485555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1486*3c41b853SStefano Zampini   if (vertSection) { ierr = PetscInfo(part,"PETSCPARTITIONERSIMPLE ignores vertex weights\n");CHKERRQ(ierr); }
148704ba2274SStefano Zampini   comm = PetscObjectComm((PetscObject)part);
1488cead94edSToby Isaac   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1489*3c41b853SStefano Zampini   if (targetSection) {
1490*3c41b853SStefano Zampini     ierr = MPIU_Allreduce(&numVertices, &numVerticesGlobal, 1, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
1491*3c41b853SStefano Zampini     ierr = PetscCalloc1(nparts,&tpwgts);CHKERRQ(ierr);
1492*3c41b853SStefano Zampini     for (np = 0; np < nparts; ++np) {
1493*3c41b853SStefano Zampini       ierr = PetscSectionGetDof(targetSection,np,&tpwgts[np]);CHKERRQ(ierr);
1494*3c41b853SStefano Zampini       sumw += tpwgts[np];
1495*3c41b853SStefano Zampini     }
1496*3c41b853SStefano Zampini     if (!sumw) {
1497*3c41b853SStefano Zampini       ierr = PetscFree(tpwgts);CHKERRQ(ierr);
1498*3c41b853SStefano Zampini     } else {
1499*3c41b853SStefano Zampini       PetscInt m,mp;
1500*3c41b853SStefano Zampini       for (np = 0; np < nparts; ++np) tpwgts[np] = (tpwgts[np]*numVerticesGlobal)/sumw;
1501*3c41b853SStefano Zampini       for (np = 0, m = -1, mp = 0, sumw = 0; np < nparts; ++np) {
1502*3c41b853SStefano Zampini         if (m < tpwgts[np]) { m = tpwgts[np]; mp = np; }
1503*3c41b853SStefano Zampini         sumw += tpwgts[np];
1504*3c41b853SStefano Zampini       }
1505*3c41b853SStefano Zampini       if (sumw != numVerticesGlobal) tpwgts[mp] += numVerticesGlobal - sumw;
1506*3c41b853SStefano Zampini     }
1507*3c41b853SStefano Zampini   }
1508*3c41b853SStefano Zampini 
1509555a9cf8SMatthew G. Knepley   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1510cead94edSToby Isaac   if (size == 1) {
1511*3c41b853SStefano Zampini     if (tpwgts) {
1512*3c41b853SStefano Zampini       for (np = 0; np < nparts; ++np) {
1513*3c41b853SStefano Zampini         ierr = PetscSectionSetDof(partSection, np, tpwgts[np]);CHKERRQ(ierr);
1514*3c41b853SStefano Zampini       }
1515*3c41b853SStefano Zampini     } else {
1516*3c41b853SStefano Zampini       for (np = 0; np < nparts; ++np) {
1517*3c41b853SStefano Zampini         ierr = PetscSectionSetDof(partSection, np, numVertices/nparts + ((numVertices % nparts) > np));CHKERRQ(ierr);
1518*3c41b853SStefano Zampini       }
1519*3c41b853SStefano Zampini     }
1520*3c41b853SStefano Zampini   } else {
1521*3c41b853SStefano Zampini     if (tpwgts) {
1522*3c41b853SStefano Zampini       Vec         v;
1523*3c41b853SStefano Zampini       PetscScalar *array;
1524*3c41b853SStefano Zampini       PetscInt    st,j;
1525*3c41b853SStefano Zampini       PetscMPIInt rank;
1526*3c41b853SStefano Zampini 
1527*3c41b853SStefano Zampini       ierr = VecCreate(comm,&v);CHKERRQ(ierr);
1528*3c41b853SStefano Zampini       ierr = VecSetSizes(v,numVertices,numVerticesGlobal);CHKERRQ(ierr);
1529*3c41b853SStefano Zampini       ierr = VecSetType(v,VECSTANDARD);CHKERRQ(ierr);
1530*3c41b853SStefano Zampini       ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1531*3c41b853SStefano Zampini       for (np = 0,st = 0; np < nparts; ++np) {
1532*3c41b853SStefano Zampini         if (rank == np || (rank == size-1 && size < nparts && np >= size)) {
1533*3c41b853SStefano Zampini           for (j = 0; j < tpwgts[np]; j++) {
1534*3c41b853SStefano Zampini             ierr = VecSetValue(v,st+j,np,INSERT_VALUES);CHKERRQ(ierr);
1535*3c41b853SStefano Zampini           }
1536*3c41b853SStefano Zampini         }
1537*3c41b853SStefano Zampini         st += tpwgts[np];
1538*3c41b853SStefano Zampini       }
1539*3c41b853SStefano Zampini       ierr = VecAssemblyBegin(v);CHKERRQ(ierr);
1540*3c41b853SStefano Zampini       ierr = VecAssemblyEnd(v);CHKERRQ(ierr);
1541*3c41b853SStefano Zampini       ierr = VecGetArray(v,&array);CHKERRQ(ierr);
1542*3c41b853SStefano Zampini       for (j = 0; j < numVertices; ++j) {
1543*3c41b853SStefano Zampini         ierr = PetscSectionAddDof(partSection,PetscRealPart(array[j]),1);CHKERRQ(ierr);
1544*3c41b853SStefano Zampini       }
1545*3c41b853SStefano Zampini       ierr = VecRestoreArray(v,&array);CHKERRQ(ierr);
1546*3c41b853SStefano Zampini       ierr = VecDestroy(&v);CHKERRQ(ierr);
154704ba2274SStefano Zampini     } else {
1548cead94edSToby Isaac       PetscMPIInt rank;
1549cead94edSToby Isaac       PetscInt nvGlobal, *offsets, myFirst, myLast;
1550cead94edSToby Isaac 
1551a679a563SToby Isaac       ierr = PetscMalloc1(size+1,&offsets);CHKERRQ(ierr);
1552cead94edSToby Isaac       offsets[0] = 0;
1553cead94edSToby Isaac       ierr = MPI_Allgather(&numVertices,1,MPIU_INT,&offsets[1],1,MPIU_INT,comm);CHKERRQ(ierr);
1554cead94edSToby Isaac       for (np = 2; np <= size; np++) {
1555cead94edSToby Isaac         offsets[np] += offsets[np-1];
1556cead94edSToby Isaac       }
1557cead94edSToby Isaac       nvGlobal = offsets[size];
1558cead94edSToby Isaac       ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1559cead94edSToby Isaac       myFirst = offsets[rank];
1560cead94edSToby Isaac       myLast  = offsets[rank + 1] - 1;
1561cead94edSToby Isaac       ierr = PetscFree(offsets);CHKERRQ(ierr);
1562cead94edSToby Isaac       if (numVertices) {
1563cead94edSToby Isaac         PetscInt firstPart = 0, firstLargePart = 0;
1564cead94edSToby Isaac         PetscInt lastPart = 0, lastLargePart = 0;
1565cead94edSToby Isaac         PetscInt rem = nvGlobal % nparts;
1566cead94edSToby Isaac         PetscInt pSmall = nvGlobal/nparts;
1567cead94edSToby Isaac         PetscInt pBig = nvGlobal/nparts + 1;
1568cead94edSToby Isaac 
1569cead94edSToby Isaac         if (rem) {
1570cead94edSToby Isaac           firstLargePart = myFirst / pBig;
1571cead94edSToby Isaac           lastLargePart  = myLast  / pBig;
1572cead94edSToby Isaac 
1573cead94edSToby Isaac           if (firstLargePart < rem) {
1574cead94edSToby Isaac             firstPart = firstLargePart;
157504ba2274SStefano Zampini           } else {
1576cead94edSToby Isaac             firstPart = rem + (myFirst - (rem * pBig)) / pSmall;
1577cead94edSToby Isaac           }
1578cead94edSToby Isaac           if (lastLargePart < rem) {
1579cead94edSToby Isaac             lastPart = lastLargePart;
158004ba2274SStefano Zampini           } else {
1581cead94edSToby Isaac             lastPart = rem + (myLast - (rem * pBig)) / pSmall;
1582cead94edSToby Isaac           }
158304ba2274SStefano Zampini         } else {
1584cead94edSToby Isaac           firstPart = myFirst / (nvGlobal/nparts);
1585cead94edSToby Isaac           lastPart  = myLast  / (nvGlobal/nparts);
1586cead94edSToby Isaac         }
1587cead94edSToby Isaac 
1588cead94edSToby Isaac         for (np = firstPart; np <= lastPart; np++) {
1589cead94edSToby Isaac           PetscInt PartStart =  np    * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np);
1590cead94edSToby Isaac           PetscInt PartEnd   = (np+1) * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np+1);
1591cead94edSToby Isaac 
1592cead94edSToby Isaac           PartStart = PetscMax(PartStart,myFirst);
1593cead94edSToby Isaac           PartEnd   = PetscMin(PartEnd,myLast+1);
1594cead94edSToby Isaac           ierr = PetscSectionSetDof(partSection,np,PartEnd-PartStart);CHKERRQ(ierr);
1595cead94edSToby Isaac         }
1596cead94edSToby Isaac       }
1597cead94edSToby Isaac     }
1598*3c41b853SStefano Zampini   }
1599*3c41b853SStefano Zampini   ierr = PetscFree(tpwgts);CHKERRQ(ierr);
1600555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1601555a9cf8SMatthew G. Knepley }
1602555a9cf8SMatthew G. Knepley 
1603d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Simple(PetscPartitioner part)
1604555a9cf8SMatthew G. Knepley {
1605555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1606074d466cSStefano Zampini   part->noGraph        = PETSC_TRUE;
1607555a9cf8SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Simple;
1608555a9cf8SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Simple;
1609555a9cf8SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Simple;
1610555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1611555a9cf8SMatthew G. Knepley }
1612555a9cf8SMatthew G. Knepley 
1613555a9cf8SMatthew G. Knepley /*MC
1614555a9cf8SMatthew G. Knepley   PETSCPARTITIONERSIMPLE = "simple" - A PetscPartitioner object
1615555a9cf8SMatthew G. Knepley 
1616555a9cf8SMatthew G. Knepley   Level: intermediate
1617555a9cf8SMatthew G. Knepley 
1618555a9cf8SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1619555a9cf8SMatthew G. Knepley M*/
1620555a9cf8SMatthew G. Knepley 
1621555a9cf8SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Simple(PetscPartitioner part)
1622555a9cf8SMatthew G. Knepley {
1623555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p;
1624555a9cf8SMatthew G. Knepley   PetscErrorCode           ierr;
1625555a9cf8SMatthew G. Knepley 
1626555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1627555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1628555a9cf8SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1629555a9cf8SMatthew G. Knepley   part->data = p;
1630555a9cf8SMatthew G. Knepley 
1631555a9cf8SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Simple(part);CHKERRQ(ierr);
1632555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1633555a9cf8SMatthew G. Knepley }
1634555a9cf8SMatthew G. Knepley 
1635d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Gather(PetscPartitioner part)
1636dae52e14SToby Isaac {
1637dae52e14SToby Isaac   PetscPartitioner_Gather *p = (PetscPartitioner_Gather *) part->data;
1638dae52e14SToby Isaac   PetscErrorCode          ierr;
1639dae52e14SToby Isaac 
1640dae52e14SToby Isaac   PetscFunctionBegin;
1641dae52e14SToby Isaac   ierr = PetscFree(p);CHKERRQ(ierr);
1642dae52e14SToby Isaac   PetscFunctionReturn(0);
1643dae52e14SToby Isaac }
1644dae52e14SToby Isaac 
1645d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather_Ascii(PetscPartitioner part, PetscViewer viewer)
1646dae52e14SToby Isaac {
1647dae52e14SToby Isaac   PetscFunctionBegin;
1648dae52e14SToby Isaac   PetscFunctionReturn(0);
1649dae52e14SToby Isaac }
1650dae52e14SToby Isaac 
1651d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather(PetscPartitioner part, PetscViewer viewer)
1652dae52e14SToby Isaac {
1653dae52e14SToby Isaac   PetscBool      iascii;
1654dae52e14SToby Isaac   PetscErrorCode ierr;
1655dae52e14SToby Isaac 
1656dae52e14SToby Isaac   PetscFunctionBegin;
1657dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1658dae52e14SToby Isaac   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1659dae52e14SToby Isaac   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1660dae52e14SToby Isaac   if (iascii) {ierr = PetscPartitionerView_Gather_Ascii(part, viewer);CHKERRQ(ierr);}
1661dae52e14SToby Isaac   PetscFunctionReturn(0);
1662dae52e14SToby Isaac }
1663dae52e14SToby Isaac 
1664*3c41b853SStefano Zampini static PetscErrorCode PetscPartitionerPartition_Gather(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertSection, PetscSection targetSection, PetscSection partSection, IS *partition)
1665dae52e14SToby Isaac {
1666dae52e14SToby Isaac   PetscInt       np;
1667dae52e14SToby Isaac   PetscErrorCode ierr;
1668dae52e14SToby Isaac 
1669dae52e14SToby Isaac   PetscFunctionBegin;
1670dae52e14SToby Isaac   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1671dae52e14SToby Isaac   ierr = PetscSectionSetDof(partSection,0,numVertices);CHKERRQ(ierr);
1672dae52e14SToby Isaac   for (np = 1; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, 0);CHKERRQ(ierr);}
1673dae52e14SToby Isaac   PetscFunctionReturn(0);
1674dae52e14SToby Isaac }
1675dae52e14SToby Isaac 
1676d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Gather(PetscPartitioner part)
1677dae52e14SToby Isaac {
1678dae52e14SToby Isaac   PetscFunctionBegin;
1679074d466cSStefano Zampini   part->noGraph        = PETSC_TRUE;
1680dae52e14SToby Isaac   part->ops->view      = PetscPartitionerView_Gather;
1681dae52e14SToby Isaac   part->ops->destroy   = PetscPartitionerDestroy_Gather;
1682dae52e14SToby Isaac   part->ops->partition = PetscPartitionerPartition_Gather;
1683dae52e14SToby Isaac   PetscFunctionReturn(0);
1684dae52e14SToby Isaac }
1685dae52e14SToby Isaac 
1686dae52e14SToby Isaac /*MC
1687dae52e14SToby Isaac   PETSCPARTITIONERGATHER = "gather" - A PetscPartitioner object
1688dae52e14SToby Isaac 
1689dae52e14SToby Isaac   Level: intermediate
1690dae52e14SToby Isaac 
1691dae52e14SToby Isaac .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1692dae52e14SToby Isaac M*/
1693dae52e14SToby Isaac 
1694dae52e14SToby Isaac PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Gather(PetscPartitioner part)
1695dae52e14SToby Isaac {
1696dae52e14SToby Isaac   PetscPartitioner_Gather *p;
1697dae52e14SToby Isaac   PetscErrorCode           ierr;
1698dae52e14SToby Isaac 
1699dae52e14SToby Isaac   PetscFunctionBegin;
1700dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1701dae52e14SToby Isaac   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1702dae52e14SToby Isaac   part->data = p;
1703dae52e14SToby Isaac 
1704dae52e14SToby Isaac   ierr = PetscPartitionerInitialize_Gather(part);CHKERRQ(ierr);
1705dae52e14SToby Isaac   PetscFunctionReturn(0);
1706dae52e14SToby Isaac }
1707dae52e14SToby Isaac 
1708dae52e14SToby Isaac 
1709d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Chaco(PetscPartitioner part)
171077623264SMatthew G. Knepley {
171177623264SMatthew G. Knepley   PetscPartitioner_Chaco *p = (PetscPartitioner_Chaco *) part->data;
171277623264SMatthew G. Knepley   PetscErrorCode          ierr;
171377623264SMatthew G. Knepley 
171477623264SMatthew G. Knepley   PetscFunctionBegin;
171577623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
171677623264SMatthew G. Knepley   PetscFunctionReturn(0);
171777623264SMatthew G. Knepley }
171877623264SMatthew G. Knepley 
1719d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco_Ascii(PetscPartitioner part, PetscViewer viewer)
172077623264SMatthew G. Knepley {
172177623264SMatthew G. Knepley   PetscFunctionBegin;
172277623264SMatthew G. Knepley   PetscFunctionReturn(0);
172377623264SMatthew G. Knepley }
172477623264SMatthew G. Knepley 
1725d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco(PetscPartitioner part, PetscViewer viewer)
172677623264SMatthew G. Knepley {
172777623264SMatthew G. Knepley   PetscBool      iascii;
172877623264SMatthew G. Knepley   PetscErrorCode ierr;
172977623264SMatthew G. Knepley 
173077623264SMatthew G. Knepley   PetscFunctionBegin;
173177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
173277623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
173377623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
173477623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Chaco_Ascii(part, viewer);CHKERRQ(ierr);}
173577623264SMatthew G. Knepley   PetscFunctionReturn(0);
173677623264SMatthew G. Knepley }
173777623264SMatthew G. Knepley 
173870034214SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
173970034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
174070034214SMatthew G. Knepley #include <unistd.h>
174170034214SMatthew G. Knepley #endif
174211d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
174311d1e910SBarry Smith #include <chaco.h>
174411d1e910SBarry Smith #else
174511d1e910SBarry Smith /* Older versions of Chaco do not have an include file */
174670034214SMatthew G. Knepley PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
174770034214SMatthew G. Knepley                        float *ewgts, float *x, float *y, float *z, char *outassignname,
174870034214SMatthew G. Knepley                        char *outfilename, short *assignment, int architecture, int ndims_tot,
174970034214SMatthew G. Knepley                        int mesh_dims[3], double *goal, int global_method, int local_method,
175070034214SMatthew G. Knepley                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
175111d1e910SBarry Smith #endif
175270034214SMatthew G. Knepley extern int FREE_GRAPH;
175377623264SMatthew G. Knepley #endif
175470034214SMatthew G. Knepley 
1755*3c41b853SStefano Zampini static PetscErrorCode PetscPartitionerPartition_Chaco(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertSection, PetscSection targetSection, PetscSection partSection, IS *partition)
175670034214SMatthew G. Knepley {
175777623264SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
175870034214SMatthew G. Knepley   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
175970034214SMatthew G. Knepley   MPI_Comm       comm;
176070034214SMatthew G. Knepley   int            nvtxs          = numVertices; /* number of vertices in full graph */
176170034214SMatthew G. Knepley   int           *vwgts          = NULL;   /* weights for all vertices */
176270034214SMatthew G. Knepley   float         *ewgts          = NULL;   /* weights for all edges */
176370034214SMatthew G. Knepley   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
176470034214SMatthew G. Knepley   char          *outassignname  = NULL;   /*  name of assignment output file */
176570034214SMatthew G. Knepley   char          *outfilename    = NULL;   /* output file name */
176670034214SMatthew G. Knepley   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
176770034214SMatthew G. Knepley   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
176870034214SMatthew G. Knepley   int            mesh_dims[3];            /* dimensions of mesh of processors */
176970034214SMatthew G. Knepley   double        *goal          = NULL;    /* desired set sizes for each set */
177070034214SMatthew G. Knepley   int            global_method = 1;       /* global partitioning algorithm */
177170034214SMatthew G. Knepley   int            local_method  = 1;       /* local partitioning algorithm */
177270034214SMatthew G. Knepley   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
177370034214SMatthew G. Knepley   int            vmax          = 200;     /* how many vertices to coarsen down to? */
177470034214SMatthew G. Knepley   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
177570034214SMatthew G. Knepley   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
177670034214SMatthew G. Knepley   long           seed          = 123636512; /* for random graph mutations */
177711d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
177811d1e910SBarry Smith   int           *assignment;              /* Output partition */
177911d1e910SBarry Smith #else
178070034214SMatthew G. Knepley   short int     *assignment;              /* Output partition */
178111d1e910SBarry Smith #endif
178270034214SMatthew G. Knepley   int            fd_stdout, fd_pipe[2];
178370034214SMatthew G. Knepley   PetscInt      *points;
178470034214SMatthew G. Knepley   int            i, v, p;
178570034214SMatthew G. Knepley   PetscErrorCode ierr;
178670034214SMatthew G. Knepley 
178770034214SMatthew G. Knepley   PetscFunctionBegin;
1788*3c41b853SStefano Zampini   ierr = PetscObjectGetComm((PetscObject)part,&comm);CHKERRQ(ierr);
178907ed3857SLisandro Dalcin #if defined (PETSC_USE_DEBUG)
179007ed3857SLisandro Dalcin   {
179107ed3857SLisandro Dalcin     int ival,isum;
179207ed3857SLisandro Dalcin     PetscBool distributed;
179307ed3857SLisandro Dalcin 
179407ed3857SLisandro Dalcin     ival = (numVertices > 0);
179507ed3857SLisandro Dalcin     ierr = MPI_Allreduce(&ival, &isum, 1, MPI_INT, MPI_SUM, comm);CHKERRQ(ierr);
179607ed3857SLisandro Dalcin     distributed = (isum > 1) ? PETSC_TRUE : PETSC_FALSE;
179707ed3857SLisandro Dalcin     if (distributed) SETERRQ(comm, PETSC_ERR_SUP, "Chaco cannot partition a distributed graph");
179807ed3857SLisandro Dalcin   }
179907ed3857SLisandro Dalcin #endif
1800*3c41b853SStefano Zampini   if (!numVertices) { /* distributed case, return if not holding the graph */
180170034214SMatthew G. Knepley     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
180270034214SMatthew G. Knepley     PetscFunctionReturn(0);
180370034214SMatthew G. Knepley   }
180470034214SMatthew G. Knepley   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
180570034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
180670034214SMatthew G. Knepley 
180770034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
180870034214SMatthew G. Knepley     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
1809*3c41b853SStefano Zampini     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
181070034214SMatthew G. Knepley   }
181177623264SMatthew G. Knepley   mesh_dims[0] = nparts;
181270034214SMatthew G. Knepley   mesh_dims[1] = 1;
181370034214SMatthew G. Knepley   mesh_dims[2] = 1;
181470034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &assignment);CHKERRQ(ierr);
181570034214SMatthew G. Knepley   /* Chaco outputs to stdout. We redirect this to a buffer. */
181670034214SMatthew G. Knepley   /* TODO: check error codes for UNIX calls */
181770034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
181870034214SMatthew G. Knepley   {
181970034214SMatthew G. Knepley     int piperet;
182070034214SMatthew G. Knepley     piperet = pipe(fd_pipe);
1821*3c41b853SStefano Zampini     if (piperet) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Could not create pipe");
182270034214SMatthew G. Knepley     fd_stdout = dup(1);
182370034214SMatthew G. Knepley     close(1);
182470034214SMatthew G. Knepley     dup2(fd_pipe[1], 1);
182570034214SMatthew G. Knepley   }
182670034214SMatthew G. Knepley #endif
1827*3c41b853SStefano Zampini   if (part->usevwgt) { ierr = PetscInfo(part,"PETSCPARTITIONERCHACO ignores vertex weights\n");CHKERRQ(ierr); }
182870034214SMatthew G. Knepley   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
182970034214SMatthew G. Knepley                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
183070034214SMatthew G. Knepley                    vmax, ndims, eigtol, seed);
183170034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
183270034214SMatthew G. Knepley   {
183370034214SMatthew G. Knepley     char msgLog[10000];
183470034214SMatthew G. Knepley     int  count;
183570034214SMatthew G. Knepley 
183670034214SMatthew G. Knepley     fflush(stdout);
183770034214SMatthew G. Knepley     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
183870034214SMatthew G. Knepley     if (count < 0) count = 0;
183970034214SMatthew G. Knepley     msgLog[count] = 0;
184070034214SMatthew G. Knepley     close(1);
184170034214SMatthew G. Knepley     dup2(fd_stdout, 1);
184270034214SMatthew G. Knepley     close(fd_stdout);
184370034214SMatthew G. Knepley     close(fd_pipe[0]);
184470034214SMatthew G. Knepley     close(fd_pipe[1]);
1845*3c41b853SStefano Zampini     if (ierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
184670034214SMatthew G. Knepley   }
184707ed3857SLisandro Dalcin #else
1848*3c41b853SStefano Zampini   if (ierr) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in Chaco library: %s", "error in stdout");
184970034214SMatthew G. Knepley #endif
185070034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
185170034214SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {
185277623264SMatthew G. Knepley     ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);
185370034214SMatthew G. Knepley   }
185470034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
185577623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
185670034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
185770034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
185870034214SMatthew G. Knepley     }
185970034214SMatthew G. Knepley   }
1860*3c41b853SStefano Zampini   if (i != nvtxs) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
186170034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
186270034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
186370034214SMatthew G. Knepley     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
186470034214SMatthew G. Knepley   }
186570034214SMatthew G. Knepley   ierr = PetscFree(assignment);CHKERRQ(ierr);
186670034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
186770034214SMatthew G. Knepley   PetscFunctionReturn(0);
186877623264SMatthew G. Knepley #else
186977623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
187070034214SMatthew G. Knepley #endif
187177623264SMatthew G. Knepley }
187277623264SMatthew G. Knepley 
1873d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Chaco(PetscPartitioner part)
187477623264SMatthew G. Knepley {
187577623264SMatthew G. Knepley   PetscFunctionBegin;
1876074d466cSStefano Zampini   part->noGraph        = PETSC_FALSE;
187777623264SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Chaco;
187877623264SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Chaco;
187977623264SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Chaco;
188077623264SMatthew G. Knepley   PetscFunctionReturn(0);
188177623264SMatthew G. Knepley }
188277623264SMatthew G. Knepley 
188377623264SMatthew G. Knepley /*MC
188477623264SMatthew G. Knepley   PETSCPARTITIONERCHACO = "chaco" - A PetscPartitioner object using the Chaco library
188577623264SMatthew G. Knepley 
188677623264SMatthew G. Knepley   Level: intermediate
188777623264SMatthew G. Knepley 
188877623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
188977623264SMatthew G. Knepley M*/
189077623264SMatthew G. Knepley 
189177623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Chaco(PetscPartitioner part)
189277623264SMatthew G. Knepley {
189377623264SMatthew G. Knepley   PetscPartitioner_Chaco *p;
189477623264SMatthew G. Knepley   PetscErrorCode          ierr;
189577623264SMatthew G. Knepley 
189677623264SMatthew G. Knepley   PetscFunctionBegin;
189777623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
189877623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
189977623264SMatthew G. Knepley   part->data = p;
190077623264SMatthew G. Knepley 
190177623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Chaco(part);CHKERRQ(ierr);
190277623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ChacoPartitionerCitation, &ChacoPartitionercite);CHKERRQ(ierr);
190377623264SMatthew G. Knepley   PetscFunctionReturn(0);
190477623264SMatthew G. Knepley }
190577623264SMatthew G. Knepley 
19065b440754SMatthew G. Knepley static const char *ptypes[] = {"kway", "rb"};
19075b440754SMatthew G. Knepley 
1908d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_ParMetis(PetscPartitioner part)
190977623264SMatthew G. Knepley {
191077623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
191177623264SMatthew G. Knepley   PetscErrorCode             ierr;
191277623264SMatthew G. Knepley 
191377623264SMatthew G. Knepley   PetscFunctionBegin;
1914*3c41b853SStefano Zampini   ierr = MPI_Comm_free(&p->pcomm);CHKERRQ(ierr);
191577623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
191677623264SMatthew G. Knepley   PetscFunctionReturn(0);
191777623264SMatthew G. Knepley }
191877623264SMatthew G. Knepley 
1919d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis_Ascii(PetscPartitioner part, PetscViewer viewer)
192077623264SMatthew G. Knepley {
19212abdaa70SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
192277623264SMatthew G. Knepley   PetscErrorCode             ierr;
192377623264SMatthew G. Knepley 
192477623264SMatthew G. Knepley   PetscFunctionBegin;
19252abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
19262abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "ParMetis type: %s\n", ptypes[p->ptype]);CHKERRQ(ierr);
19272abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "load imbalance ratio %g\n", (double) p->imbalanceRatio);CHKERRQ(ierr);
19282abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "debug flag %D\n", p->debugFlag);CHKERRQ(ierr);
19299d459c0eSStefano Zampini   ierr = PetscViewerASCIIPrintf(viewer, "random seed %D\n", p->randomSeed);CHKERRQ(ierr);
19302abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
193177623264SMatthew G. Knepley   PetscFunctionReturn(0);
193277623264SMatthew G. Knepley }
193377623264SMatthew G. Knepley 
1934d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis(PetscPartitioner part, PetscViewer viewer)
193577623264SMatthew G. Knepley {
193677623264SMatthew G. Knepley   PetscBool      iascii;
193777623264SMatthew G. Knepley   PetscErrorCode ierr;
193877623264SMatthew G. Knepley 
193977623264SMatthew G. Knepley   PetscFunctionBegin;
194077623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
194177623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
194277623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
194377623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_ParMetis_Ascii(part, viewer);CHKERRQ(ierr);}
194477623264SMatthew G. Knepley   PetscFunctionReturn(0);
194577623264SMatthew G. Knepley }
194670034214SMatthew G. Knepley 
194744d8be81SLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_ParMetis(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
194844d8be81SLisandro Dalcin {
194944d8be81SLisandro Dalcin   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
195044d8be81SLisandro Dalcin   PetscErrorCode            ierr;
195144d8be81SLisandro Dalcin 
195244d8be81SLisandro Dalcin   PetscFunctionBegin;
195344d8be81SLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner ParMetis Options");CHKERRQ(ierr);
195444d8be81SLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_parmetis_type", "Partitioning method", "", ptypes, 2, ptypes[p->ptype], &p->ptype, NULL);CHKERRQ(ierr);
19555b440754SMatthew G. Knepley   ierr = PetscOptionsReal("-petscpartitioner_parmetis_imbalance_ratio", "Load imbalance ratio limit", "", p->imbalanceRatio, &p->imbalanceRatio, NULL);CHKERRQ(ierr);
19565b440754SMatthew G. Knepley   ierr = PetscOptionsInt("-petscpartitioner_parmetis_debug", "Debugging flag", "", p->debugFlag, &p->debugFlag, NULL);CHKERRQ(ierr);
19579d459c0eSStefano Zampini   ierr = PetscOptionsInt("-petscpartitioner_parmetis_seed", "Random seed", "", p->randomSeed, &p->randomSeed, NULL);CHKERRQ(ierr);
195844d8be81SLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
195944d8be81SLisandro Dalcin   PetscFunctionReturn(0);
196044d8be81SLisandro Dalcin }
196144d8be81SLisandro Dalcin 
196270034214SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
196370034214SMatthew G. Knepley #include <parmetis.h>
196477623264SMatthew G. Knepley #endif
196570034214SMatthew G. Knepley 
1966*3c41b853SStefano Zampini static PetscErrorCode PetscPartitionerPartition_ParMetis(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertSection, PetscSection targetSection, PetscSection partSection, IS *partition)
196770034214SMatthew G. Knepley {
196877623264SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
19695b440754SMatthew G. Knepley   PetscPartitioner_ParMetis *pm = (PetscPartitioner_ParMetis *) part->data;
197070034214SMatthew G. Knepley   MPI_Comm       comm;
197170034214SMatthew G. Knepley   PetscInt       nvtxs       = numVertices; /* The number of vertices in full graph */
197270034214SMatthew G. Knepley   PetscInt      *vtxdist;                   /* Distribution of vertices across processes */
197370034214SMatthew G. Knepley   PetscInt      *xadj        = start;       /* Start of edge list for each vertex */
197470034214SMatthew G. Knepley   PetscInt      *adjncy      = adjacency;   /* Edge lists for all vertices */
197570034214SMatthew G. Knepley   PetscInt      *vwgt        = NULL;        /* Vertex weights */
197670034214SMatthew G. Knepley   PetscInt      *adjwgt      = NULL;        /* Edge weights */
197770034214SMatthew G. Knepley   PetscInt       wgtflag     = 0;           /* Indicates which weights are present */
197870034214SMatthew G. Knepley   PetscInt       numflag     = 0;           /* Indicates initial offset (0 or 1) */
197970034214SMatthew G. Knepley   PetscInt       ncon        = 1;           /* The number of weights per vertex */
19805b440754SMatthew G. Knepley   PetscInt       metis_ptype = pm->ptype;   /* kway or recursive bisection */
1981fb83b9f2SMichael Gegg   real_t        *tpwgts;                    /* The fraction of vertex weights assigned to each partition */
1982fb83b9f2SMichael Gegg   real_t        *ubvec;                     /* The balance intolerance for vertex weights */
1983b3ce585bSLisandro Dalcin   PetscInt       options[64];               /* Options */
1984b3ce585bSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
1985*3c41b853SStefano Zampini   PetscMPIInt    p, size, rank;
1986*3c41b853SStefano Zampini   PetscBool      hasempty = PETSC_FALSE;
198770034214SMatthew G. Knepley   PetscErrorCode ierr;
198870034214SMatthew G. Knepley 
198970034214SMatthew G. Knepley   PetscFunctionBegin;
199077623264SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) part, &comm);CHKERRQ(ierr);
1991b3ce585bSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
199270034214SMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
199370034214SMatthew G. Knepley   /* Calculate vertex distribution */
1994*3c41b853SStefano Zampini   ierr = PetscMalloc4(size+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment);CHKERRQ(ierr);
199570034214SMatthew G. Knepley   vtxdist[0] = 0;
199670034214SMatthew G. Knepley   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
1997b3ce585bSLisandro Dalcin   for (p = 2; p <= size; ++p) {
1998*3c41b853SStefano Zampini     hasempty = (PetscBool)(hasempty || !vtxdist[p-1] || !vtxdist[p]);
199970034214SMatthew G. Knepley     vtxdist[p] += vtxdist[p-1];
200070034214SMatthew G. Knepley   }
2001*3c41b853SStefano Zampini   /* null graph */
2002*3c41b853SStefano Zampini   if (vtxdist[size] == 0) {
2003*3c41b853SStefano Zampini     ierr = PetscFree4(vtxdist,tpwgts,ubvec,assignment);CHKERRQ(ierr);
2004*3c41b853SStefano Zampini     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2005*3c41b853SStefano Zampini     PetscFunctionReturn(0);
2006*3c41b853SStefano Zampini   }
200744d8be81SLisandro Dalcin   /* Calculate partition weights */
2008*3c41b853SStefano Zampini   if (targetSection) {
2009*3c41b853SStefano Zampini     PetscInt p;
2010*3c41b853SStefano Zampini     real_t   sumt = 0.0;
2011*3c41b853SStefano Zampini 
201270034214SMatthew G. Knepley     for (p = 0; p < nparts; ++p) {
2013*3c41b853SStefano Zampini       PetscInt tpd;
2014*3c41b853SStefano Zampini 
2015*3c41b853SStefano Zampini       ierr = PetscSectionGetDof(targetSection,p,&tpd);CHKERRQ(ierr);
2016*3c41b853SStefano Zampini       sumt += tpd;
2017*3c41b853SStefano Zampini       tpwgts[p] = tpd;
2018*3c41b853SStefano Zampini     }
2019*3c41b853SStefano Zampini     if (sumt) { /* METIS/ParMETIS do not like exactly zero weight */
2020*3c41b853SStefano Zampini       for (p = 0, sumt = 0.0; p < nparts; ++p) {
2021*3c41b853SStefano Zampini         tpwgts[p] = PetscMax(tpwgts[p],PETSC_SMALL);
2022*3c41b853SStefano Zampini         sumt += tpwgts[p];
2023*3c41b853SStefano Zampini       }
2024*3c41b853SStefano Zampini       for (p = 0; p < nparts; ++p) tpwgts[p] /= sumt;
2025*3c41b853SStefano Zampini       for (p = 0, sumt = 0.0; p < nparts-1; ++p) sumt += tpwgts[p];
2026*3c41b853SStefano Zampini       tpwgts[nparts - 1] = 1. - sumt;
2027*3c41b853SStefano Zampini     }
2028*3c41b853SStefano Zampini   } else {
2029*3c41b853SStefano Zampini     for (p = 0; p < nparts; ++p) tpwgts[p] = 1.0/nparts;
203070034214SMatthew G. Knepley   }
20315b440754SMatthew G. Knepley   ubvec[0] = pm->imbalanceRatio;
203270034214SMatthew G. Knepley 
2033*3c41b853SStefano Zampini   /* Weight cells */
2034*3c41b853SStefano Zampini   if (vertSection) {
2035*3c41b853SStefano Zampini     ierr = PetscMalloc1(nvtxs,&vwgt);CHKERRQ(ierr);
2036*3c41b853SStefano Zampini     for (v = 0; v < nvtxs; ++v) {
2037*3c41b853SStefano Zampini       ierr = PetscSectionGetDof(vertSection, v, &vwgt[v]);CHKERRQ(ierr);
2038cd0de0f2SShri     }
203944d8be81SLisandro Dalcin     wgtflag |= 2; /* have weights on graph vertices */
2040*3c41b853SStefano Zampini   }
2041cd0de0f2SShri 
2042b3ce585bSLisandro Dalcin   for (p = 0; !vtxdist[p+1] && p < size; ++p);
2043b3ce585bSLisandro Dalcin   if (vtxdist[p+1] == vtxdist[size]) {
2044b3ce585bSLisandro Dalcin     if (rank == p) {
204544d8be81SLisandro Dalcin       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
204642678178SLisandro Dalcin       options[METIS_OPTION_DBGLVL] = pm->debugFlag;
20479d459c0eSStefano Zampini       options[METIS_OPTION_SEED]   = pm->randomSeed;
204844d8be81SLisandro Dalcin       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
204944d8be81SLisandro Dalcin       if (metis_ptype == 1) {
205044d8be81SLisandro Dalcin         PetscStackPush("METIS_PartGraphRecursive");
205172379da4SMatthew G. Knepley         ierr = METIS_PartGraphRecursive(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
205244d8be81SLisandro Dalcin         PetscStackPop;
205344d8be81SLisandro Dalcin         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphRecursive()");
205444d8be81SLisandro Dalcin       } else {
205544d8be81SLisandro Dalcin         /*
205644d8be81SLisandro Dalcin          It would be nice to activate the two options below, but they would need some actual testing.
205744d8be81SLisandro Dalcin          - Turning on these options may exercise path of the METIS code that have bugs and may break production runs.
205844d8be81SLisandro 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.
205944d8be81SLisandro Dalcin         */
206044d8be81SLisandro Dalcin         /* options[METIS_OPTION_CONTIG]  = 1; */ /* try to produce partitions that are contiguous */
206144d8be81SLisandro Dalcin         /* options[METIS_OPTION_MINCONN] = 1; */ /* minimize the maximum degree of the subdomain graph */
206270034214SMatthew G. Knepley         PetscStackPush("METIS_PartGraphKway");
206372379da4SMatthew G. Knepley         ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
206470034214SMatthew G. Knepley         PetscStackPop;
206570034214SMatthew G. Knepley         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
206670034214SMatthew G. Knepley       }
206744d8be81SLisandro Dalcin     }
206870034214SMatthew G. Knepley   } else {
2069*3c41b853SStefano Zampini     MPI_Comm pcomm;
2070*3c41b853SStefano Zampini 
207142678178SLisandro Dalcin     options[0] = 1; /*use options */
20725b440754SMatthew G. Knepley     options[1] = pm->debugFlag;
20739d459c0eSStefano Zampini     options[2] = (pm->randomSeed == -1) ? 15 : pm->randomSeed; /* default is GLOBAL_SEED=15 from `libparmetis/defs.h` */
2074*3c41b853SStefano Zampini 
2075*3c41b853SStefano Zampini     if (hasempty) { /* parmetis does not support empty graphs on some of the processes */
2076*3c41b853SStefano Zampini       PetscInt cnt;
2077*3c41b853SStefano Zampini 
2078*3c41b853SStefano Zampini       ierr = MPI_Comm_split(pm->pcomm,!!nvtxs,rank,&pcomm);CHKERRQ(ierr);
2079*3c41b853SStefano Zampini       for (p=0,cnt=0;p<size;p++) {
2080*3c41b853SStefano Zampini         if (vtxdist[p+1] != vtxdist[p]) {
2081*3c41b853SStefano Zampini           vtxdist[cnt+1] = vtxdist[p+1];
2082*3c41b853SStefano Zampini           cnt++;
2083*3c41b853SStefano Zampini         }
2084*3c41b853SStefano Zampini       }
2085*3c41b853SStefano Zampini     } else pcomm = pm->pcomm;
2086*3c41b853SStefano Zampini     if (nvtxs) {
208770034214SMatthew G. Knepley       PetscStackPush("ParMETIS_V3_PartKway");
2088*3c41b853SStefano Zampini       ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment, &pcomm);
208970034214SMatthew G. Knepley       PetscStackPop;
2090c717d290SMatthew G. Knepley       if (ierr != METIS_OK) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error %d in ParMETIS_V3_PartKway()", ierr);
209170034214SMatthew G. Knepley     }
2092*3c41b853SStefano Zampini     if (hasempty) {
2093*3c41b853SStefano Zampini       ierr = MPI_Comm_free(&pcomm);CHKERRQ(ierr);
209470034214SMatthew G. Knepley     }
2095*3c41b853SStefano Zampini   }
2096*3c41b853SStefano Zampini 
209770034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
209877623264SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
209970034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
210077623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
210170034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
210270034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
210370034214SMatthew G. Knepley     }
210470034214SMatthew G. Knepley   }
210570034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
210670034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2107*3c41b853SStefano Zampini   ierr = PetscFree4(vtxdist,tpwgts,ubvec,assignment);CHKERRQ(ierr);
2108*3c41b853SStefano Zampini   ierr = PetscFree(vwgt);CHKERRQ(ierr);
21099b80ac48SMatthew G. Knepley   PetscFunctionReturn(0);
211070034214SMatthew G. Knepley #else
211177623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
211270034214SMatthew G. Knepley #endif
211370034214SMatthew G. Knepley }
211470034214SMatthew G. Knepley 
2115d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_ParMetis(PetscPartitioner part)
211677623264SMatthew G. Knepley {
211777623264SMatthew G. Knepley   PetscFunctionBegin;
2118074d466cSStefano Zampini   part->noGraph             = PETSC_FALSE;
211977623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_ParMetis;
212044d8be81SLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_ParMetis;
212177623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_ParMetis;
212277623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_ParMetis;
212377623264SMatthew G. Knepley   PetscFunctionReturn(0);
212477623264SMatthew G. Knepley }
212577623264SMatthew G. Knepley 
212677623264SMatthew G. Knepley /*MC
2127*3c41b853SStefano Zampini   PETSCPARTITIONERPARMETIS = "parmetis" - A PetscPartitioner object using the ParMETIS library
212877623264SMatthew G. Knepley 
212977623264SMatthew G. Knepley   Level: intermediate
213077623264SMatthew G. Knepley 
2131*3c41b853SStefano Zampini   Options Database Keys:
2132*3c41b853SStefano Zampini +  -petscpartitioner_parmetis_type <string> - ParMETIS partitioning type. Either "kway" or "rb" (recursive bisection)
2133*3c41b853SStefano Zampini .  -petscpartitioner_parmetis_imbalance_ratio <value> - Load imbalance ratio limit
2134*3c41b853SStefano Zampini .  -petscpartitioner_parmetis_debug <int> - Debugging flag passed to ParMETIS/METIS routines
2135*3c41b853SStefano Zampini -  -petscpartitioner_parmetis_seed <int> - Random seed
2136*3c41b853SStefano Zampini 
2137*3c41b853SStefano Zampini   Notes: when the graph is on a single process, this partitioner actually calls METIS and not ParMETIS
2138*3c41b853SStefano Zampini 
213977623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
214077623264SMatthew G. Knepley M*/
214177623264SMatthew G. Knepley 
214277623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_ParMetis(PetscPartitioner part)
214377623264SMatthew G. Knepley {
214477623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p;
214577623264SMatthew G. Knepley   PetscErrorCode          ierr;
214677623264SMatthew G. Knepley 
214777623264SMatthew G. Knepley   PetscFunctionBegin;
214877623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
214977623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
215077623264SMatthew G. Knepley   part->data = p;
215177623264SMatthew G. Knepley 
2152*3c41b853SStefano Zampini   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)part),&p->pcomm);CHKERRQ(ierr);
21535b440754SMatthew G. Knepley   p->ptype          = 0;
21545b440754SMatthew G. Knepley   p->imbalanceRatio = 1.05;
21555b440754SMatthew G. Knepley   p->debugFlag      = 0;
21569d459c0eSStefano Zampini   p->randomSeed     = -1; /* defaults to GLOBAL_SEED=15 from `libparmetis/defs.h` */
21575b440754SMatthew G. Knepley 
215877623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_ParMetis(part);CHKERRQ(ierr);
215977623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ParMetisPartitionerCitation, &ParMetisPartitionercite);CHKERRQ(ierr);
216070034214SMatthew G. Knepley   PetscFunctionReturn(0);
216170034214SMatthew G. Knepley }
216270034214SMatthew G. Knepley 
2163137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
2164137cd93aSLisandro Dalcin 
2165137cd93aSLisandro Dalcin EXTERN_C_BEGIN
2166137cd93aSLisandro Dalcin #include <ptscotch.h>
2167137cd93aSLisandro Dalcin EXTERN_C_END
2168137cd93aSLisandro Dalcin 
2169137cd93aSLisandro Dalcin #define CHKERRPTSCOTCH(ierr) do { if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error calling PT-Scotch library"); } while(0)
2170137cd93aSLisandro Dalcin 
2171137cd93aSLisandro Dalcin static int PTScotch_Strategy(PetscInt strategy)
2172137cd93aSLisandro Dalcin {
2173137cd93aSLisandro Dalcin   switch (strategy) {
2174137cd93aSLisandro Dalcin   case  0: return SCOTCH_STRATDEFAULT;
2175137cd93aSLisandro Dalcin   case  1: return SCOTCH_STRATQUALITY;
2176137cd93aSLisandro Dalcin   case  2: return SCOTCH_STRATSPEED;
2177137cd93aSLisandro Dalcin   case  3: return SCOTCH_STRATBALANCE;
2178137cd93aSLisandro Dalcin   case  4: return SCOTCH_STRATSAFETY;
2179137cd93aSLisandro Dalcin   case  5: return SCOTCH_STRATSCALABILITY;
2180137cd93aSLisandro Dalcin   case  6: return SCOTCH_STRATRECURSIVE;
2181137cd93aSLisandro Dalcin   case  7: return SCOTCH_STRATREMAP;
2182137cd93aSLisandro Dalcin   default: return SCOTCH_STRATDEFAULT;
2183137cd93aSLisandro Dalcin   }
2184137cd93aSLisandro Dalcin }
2185137cd93aSLisandro Dalcin 
2186137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_Seq(SCOTCH_Num strategy, double imbalance, SCOTCH_Num n, SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
2187*3c41b853SStefano Zampini                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num tpart[], SCOTCH_Num part[])
2188137cd93aSLisandro Dalcin {
2189137cd93aSLisandro Dalcin   SCOTCH_Graph   grafdat;
2190137cd93aSLisandro Dalcin   SCOTCH_Strat   stradat;
2191137cd93aSLisandro Dalcin   SCOTCH_Num     vertnbr = n;
2192137cd93aSLisandro Dalcin   SCOTCH_Num     edgenbr = xadj[n];
2193137cd93aSLisandro Dalcin   SCOTCH_Num*    velotab = vtxwgt;
2194137cd93aSLisandro Dalcin   SCOTCH_Num*    edlotab = adjwgt;
2195137cd93aSLisandro Dalcin   SCOTCH_Num     flagval = strategy;
2196137cd93aSLisandro Dalcin   double         kbalval = imbalance;
2197137cd93aSLisandro Dalcin   PetscErrorCode ierr;
2198137cd93aSLisandro Dalcin 
2199137cd93aSLisandro Dalcin   PetscFunctionBegin;
2200d99a0000SVaclav Hapla   {
2201d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
2202*3c41b853SStefano Zampini     ierr = PetscOptionsDeprecatedNoObject("-petscpartititoner_ptscotch_vertex_weight",NULL,"3.13","Use -petscpartitioner_use_vertex_weights");CHKERRQ(ierr);
2203d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
2204d99a0000SVaclav Hapla     if (!flg) velotab = NULL;
2205d99a0000SVaclav Hapla   }
2206137cd93aSLisandro Dalcin   ierr = SCOTCH_graphInit(&grafdat);CHKERRPTSCOTCH(ierr);
2207137cd93aSLisandro Dalcin   ierr = SCOTCH_graphBuild(&grafdat, 0, vertnbr, xadj, xadj + 1, velotab, NULL, edgenbr, adjncy, edlotab);CHKERRPTSCOTCH(ierr);
2208137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
2209137cd93aSLisandro Dalcin   ierr = SCOTCH_stratGraphMapBuild(&stradat, flagval, nparts, kbalval);CHKERRPTSCOTCH(ierr);
2210*3c41b853SStefano Zampini   if (tpart) {
2211*3c41b853SStefano Zampini     SCOTCH_Arch archdat;
2212*3c41b853SStefano Zampini     ierr = SCOTCH_archInit(&archdat);CHKERRPTSCOTCH(ierr);
2213*3c41b853SStefano Zampini     ierr = SCOTCH_archCmpltw(&archdat, nparts, tpart);CHKERRPTSCOTCH(ierr);
2214*3c41b853SStefano Zampini     ierr = SCOTCH_graphMap(&grafdat, &archdat, &stradat, part);CHKERRPTSCOTCH(ierr);
2215*3c41b853SStefano Zampini     SCOTCH_archExit(&archdat);
2216*3c41b853SStefano Zampini   } else {
2217137cd93aSLisandro Dalcin     ierr = SCOTCH_graphPart(&grafdat, nparts, &stradat, part);CHKERRPTSCOTCH(ierr);
2218*3c41b853SStefano Zampini   }
2219137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
2220137cd93aSLisandro Dalcin   SCOTCH_graphExit(&grafdat);
2221137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2222137cd93aSLisandro Dalcin }
2223137cd93aSLisandro Dalcin 
2224137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_MPI(SCOTCH_Num strategy, double imbalance, SCOTCH_Num vtxdist[], SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
2225*3c41b853SStefano Zampini                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num tpart[], SCOTCH_Num part[], MPI_Comm comm)
2226137cd93aSLisandro Dalcin {
2227137cd93aSLisandro Dalcin   PetscMPIInt     procglbnbr;
2228137cd93aSLisandro Dalcin   PetscMPIInt     proclocnum;
2229137cd93aSLisandro Dalcin   SCOTCH_Arch     archdat;
2230137cd93aSLisandro Dalcin   SCOTCH_Dgraph   grafdat;
2231137cd93aSLisandro Dalcin   SCOTCH_Dmapping mappdat;
2232137cd93aSLisandro Dalcin   SCOTCH_Strat    stradat;
2233137cd93aSLisandro Dalcin   SCOTCH_Num      vertlocnbr;
2234137cd93aSLisandro Dalcin   SCOTCH_Num      edgelocnbr;
2235137cd93aSLisandro Dalcin   SCOTCH_Num*     veloloctab = vtxwgt;
2236137cd93aSLisandro Dalcin   SCOTCH_Num*     edloloctab = adjwgt;
2237137cd93aSLisandro Dalcin   SCOTCH_Num      flagval = strategy;
2238137cd93aSLisandro Dalcin   double          kbalval = imbalance;
2239137cd93aSLisandro Dalcin   PetscErrorCode  ierr;
2240137cd93aSLisandro Dalcin 
2241137cd93aSLisandro Dalcin   PetscFunctionBegin;
2242d99a0000SVaclav Hapla   {
2243d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
2244*3c41b853SStefano Zampini     ierr = PetscOptionsDeprecatedNoObject("-petscpartititoner_ptscotch_vertex_weight",NULL,"3.13","Use -petscpartitioner_use_vertex_weights");CHKERRQ(ierr);
2245d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
2246d99a0000SVaclav Hapla     if (!flg) veloloctab = NULL;
2247d99a0000SVaclav Hapla   }
2248137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &procglbnbr);CHKERRQ(ierr);
2249137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &proclocnum);CHKERRQ(ierr);
2250137cd93aSLisandro Dalcin   vertlocnbr = vtxdist[proclocnum + 1] - vtxdist[proclocnum];
2251137cd93aSLisandro Dalcin   edgelocnbr = xadj[vertlocnbr];
2252137cd93aSLisandro Dalcin 
2253137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphInit(&grafdat, comm);CHKERRPTSCOTCH(ierr);
2254137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphBuild(&grafdat, 0, vertlocnbr, vertlocnbr, xadj, xadj + 1, veloloctab, NULL, edgelocnbr, edgelocnbr, adjncy, NULL, edloloctab);CHKERRPTSCOTCH(ierr);
2255137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
2256137cd93aSLisandro Dalcin   ierr = SCOTCH_stratDgraphMapBuild(&stradat, flagval, procglbnbr, nparts, kbalval);CHKERRQ(ierr);
2257137cd93aSLisandro Dalcin   ierr = SCOTCH_archInit(&archdat);CHKERRPTSCOTCH(ierr);
2258*3c41b853SStefano Zampini   if (tpart) { /* target partition weights */
2259*3c41b853SStefano Zampini     ierr = SCOTCH_archCmpltw(&archdat, nparts, tpart);CHKERRPTSCOTCH(ierr);
2260*3c41b853SStefano Zampini   } else {
2261137cd93aSLisandro Dalcin     ierr = SCOTCH_archCmplt(&archdat, nparts);CHKERRPTSCOTCH(ierr);
2262*3c41b853SStefano Zampini   }
2263137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapInit(&grafdat, &mappdat, &archdat, part);CHKERRPTSCOTCH(ierr);
2264cb87ef4cSFlorian Wechsung 
2265137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapCompute(&grafdat, &mappdat, &stradat);CHKERRPTSCOTCH(ierr);
2266137cd93aSLisandro Dalcin   SCOTCH_dgraphMapExit(&grafdat, &mappdat);
2267137cd93aSLisandro Dalcin   SCOTCH_archExit(&archdat);
2268137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
2269137cd93aSLisandro Dalcin   SCOTCH_dgraphExit(&grafdat);
2270137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2271137cd93aSLisandro Dalcin }
2272137cd93aSLisandro Dalcin 
2273137cd93aSLisandro Dalcin #endif /* PETSC_HAVE_PTSCOTCH */
2274137cd93aSLisandro Dalcin 
2275137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerDestroy_PTScotch(PetscPartitioner part)
2276137cd93aSLisandro Dalcin {
2277137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2278137cd93aSLisandro Dalcin   PetscErrorCode             ierr;
2279137cd93aSLisandro Dalcin 
2280137cd93aSLisandro Dalcin   PetscFunctionBegin;
2281*3c41b853SStefano Zampini   ierr = MPI_Comm_free(&p->pcomm);CHKERRQ(ierr);
2282137cd93aSLisandro Dalcin   ierr = PetscFree(p);CHKERRQ(ierr);
2283137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2284137cd93aSLisandro Dalcin }
2285137cd93aSLisandro Dalcin 
2286137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch_Ascii(PetscPartitioner part, PetscViewer viewer)
2287137cd93aSLisandro Dalcin {
2288137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2289137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
2290137cd93aSLisandro Dalcin 
2291137cd93aSLisandro Dalcin   PetscFunctionBegin;
2292137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
2293137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer,"using partitioning strategy %s\n",PTScotchStrategyList[p->strategy]);CHKERRQ(ierr);
2294137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer,"using load imbalance ratio %g\n",(double)p->imbalance);CHKERRQ(ierr);
2295137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
2296137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2297137cd93aSLisandro Dalcin }
2298137cd93aSLisandro Dalcin 
2299137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch(PetscPartitioner part, PetscViewer viewer)
2300137cd93aSLisandro Dalcin {
2301137cd93aSLisandro Dalcin   PetscBool      iascii;
2302137cd93aSLisandro Dalcin   PetscErrorCode ierr;
2303137cd93aSLisandro Dalcin 
2304137cd93aSLisandro Dalcin   PetscFunctionBegin;
2305137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
2306137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2307137cd93aSLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
2308137cd93aSLisandro Dalcin   if (iascii) {ierr = PetscPartitionerView_PTScotch_Ascii(part, viewer);CHKERRQ(ierr);}
2309137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2310137cd93aSLisandro Dalcin }
2311137cd93aSLisandro Dalcin 
2312137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_PTScotch(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
2313137cd93aSLisandro Dalcin {
2314137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2315137cd93aSLisandro Dalcin   const char *const         *slist = PTScotchStrategyList;
2316137cd93aSLisandro Dalcin   PetscInt                  nlist = (PetscInt)(sizeof(PTScotchStrategyList)/sizeof(PTScotchStrategyList[0]));
2317137cd93aSLisandro Dalcin   PetscBool                 flag;
2318137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
2319137cd93aSLisandro Dalcin 
2320137cd93aSLisandro Dalcin   PetscFunctionBegin;
2321137cd93aSLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner PTScotch Options");CHKERRQ(ierr);
2322137cd93aSLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_ptscotch_strategy","Partitioning strategy","",slist,nlist,slist[p->strategy],&p->strategy,&flag);CHKERRQ(ierr);
2323137cd93aSLisandro Dalcin   ierr = PetscOptionsReal("-petscpartitioner_ptscotch_imbalance","Load imbalance ratio","",p->imbalance,&p->imbalance,&flag);CHKERRQ(ierr);
2324137cd93aSLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
2325137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2326137cd93aSLisandro Dalcin }
2327137cd93aSLisandro Dalcin 
2328*3c41b853SStefano Zampini static PetscErrorCode PetscPartitionerPartition_PTScotch(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertSection, PetscSection targetSection, PetscSection partSection, IS *partition)
2329137cd93aSLisandro Dalcin {
2330137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
2331*3c41b853SStefano Zampini   MPI_Comm       comm;
2332137cd93aSLisandro Dalcin   PetscInt       nvtxs = numVertices;   /* The number of vertices in full graph */
2333137cd93aSLisandro Dalcin   PetscInt       *vtxdist;              /* Distribution of vertices across processes */
2334137cd93aSLisandro Dalcin   PetscInt       *xadj   = start;       /* Start of edge list for each vertex */
2335137cd93aSLisandro Dalcin   PetscInt       *adjncy = adjacency;   /* Edge lists for all vertices */
2336137cd93aSLisandro Dalcin   PetscInt       *vwgt   = NULL;        /* Vertex weights */
2337137cd93aSLisandro Dalcin   PetscInt       *adjwgt = NULL;        /* Edge weights */
2338137cd93aSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
2339137cd93aSLisandro Dalcin   PetscMPIInt    size, rank, p;
2340*3c41b853SStefano Zampini   PetscBool      hasempty = PETSC_FALSE;
2341*3c41b853SStefano Zampini   PetscInt       *tpwgts = NULL;
2342137cd93aSLisandro Dalcin   PetscErrorCode ierr;
2343137cd93aSLisandro Dalcin 
2344137cd93aSLisandro Dalcin   PetscFunctionBegin;
2345*3c41b853SStefano Zampini   ierr = PetscObjectGetComm((PetscObject)part,&comm);CHKERRQ(ierr);
2346137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
2347137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
234899b53901SStefano Zampini   ierr = PetscMalloc2(size+1,&vtxdist,PetscMax(nvtxs,1),&assignment);CHKERRQ(ierr);
2349137cd93aSLisandro Dalcin   /* Calculate vertex distribution */
2350137cd93aSLisandro Dalcin   vtxdist[0] = 0;
2351137cd93aSLisandro Dalcin   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
2352137cd93aSLisandro Dalcin   for (p = 2; p <= size; ++p) {
2353*3c41b853SStefano Zampini     hasempty = (PetscBool)(hasempty || !vtxdist[p-1] || !vtxdist[p]);
2354137cd93aSLisandro Dalcin     vtxdist[p] += vtxdist[p-1];
2355137cd93aSLisandro Dalcin   }
2356*3c41b853SStefano Zampini   /* null graph */
2357*3c41b853SStefano Zampini   if (vtxdist[size] == 0) {
2358*3c41b853SStefano Zampini     ierr = PetscFree2(vtxdist, assignment);CHKERRQ(ierr);
2359*3c41b853SStefano Zampini     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2360*3c41b853SStefano Zampini     PetscFunctionReturn(0);
2361*3c41b853SStefano Zampini   }
2362137cd93aSLisandro Dalcin 
2363*3c41b853SStefano Zampini   /* Calculate vertex weights */
2364*3c41b853SStefano Zampini   if (vertSection) {
2365*3c41b853SStefano Zampini     ierr = PetscMalloc1(nvtxs,&vwgt);CHKERRQ(ierr);
2366*3c41b853SStefano Zampini     for (v = 0; v < nvtxs; ++v) {
2367*3c41b853SStefano Zampini       ierr = PetscSectionGetDof(vertSection, v, &vwgt[v]);CHKERRQ(ierr);
2368137cd93aSLisandro Dalcin     }
2369137cd93aSLisandro Dalcin   }
2370*3c41b853SStefano Zampini 
2371*3c41b853SStefano Zampini   /* Calculate partition weights */
2372*3c41b853SStefano Zampini   if (targetSection) {
2373*3c41b853SStefano Zampini     PetscInt sumw;
2374*3c41b853SStefano Zampini 
2375*3c41b853SStefano Zampini     ierr = PetscCalloc1(nparts,&tpwgts);CHKERRQ(ierr);
2376*3c41b853SStefano Zampini     for (p = 0, sumw = 0; p < nparts; ++p) {
2377*3c41b853SStefano Zampini       ierr = PetscSectionGetDof(targetSection,p,&tpwgts[p]);CHKERRQ(ierr);
2378*3c41b853SStefano Zampini       sumw += tpwgts[p];
2379*3c41b853SStefano Zampini     }
2380*3c41b853SStefano Zampini     if (!sumw) {
2381*3c41b853SStefano Zampini       ierr = PetscFree(tpwgts);CHKERRQ(ierr);
2382*3c41b853SStefano Zampini     }
2383*3c41b853SStefano Zampini   }
2384*3c41b853SStefano Zampini 
2385137cd93aSLisandro Dalcin   {
2386137cd93aSLisandro Dalcin     PetscPartitioner_PTScotch *pts = (PetscPartitioner_PTScotch *) part->data;
2387137cd93aSLisandro Dalcin     int                       strat = PTScotch_Strategy(pts->strategy);
2388137cd93aSLisandro Dalcin     double                    imbal = (double)pts->imbalance;
2389137cd93aSLisandro Dalcin 
2390137cd93aSLisandro Dalcin     for (p = 0; !vtxdist[p+1] && p < size; ++p);
2391137cd93aSLisandro Dalcin     if (vtxdist[p+1] == vtxdist[size]) {
2392137cd93aSLisandro Dalcin       if (rank == p) {
2393*3c41b853SStefano Zampini         ierr = PTScotch_PartGraph_Seq(strat, imbal, nvtxs, xadj, adjncy, vwgt, adjwgt, nparts, tpwgts, assignment);CHKERRQ(ierr);
2394137cd93aSLisandro Dalcin       }
2395137cd93aSLisandro Dalcin     } else {
2396*3c41b853SStefano Zampini       PetscInt cnt;
2397*3c41b853SStefano Zampini       MPI_Comm pcomm;
2398*3c41b853SStefano Zampini 
2399*3c41b853SStefano Zampini       if (hasempty) {
2400*3c41b853SStefano Zampini         ierr = MPI_Comm_split(pts->pcomm,!!nvtxs,rank,&pcomm);CHKERRQ(ierr);
2401*3c41b853SStefano Zampini         for (p=0,cnt=0;p<size;p++) {
2402*3c41b853SStefano Zampini           if (vtxdist[p+1] != vtxdist[p]) {
2403*3c41b853SStefano Zampini             vtxdist[cnt+1] = vtxdist[p+1];
2404*3c41b853SStefano Zampini             cnt++;
2405*3c41b853SStefano Zampini           }
2406*3c41b853SStefano Zampini         }
2407*3c41b853SStefano Zampini       } else pcomm = pts->pcomm;
2408*3c41b853SStefano Zampini       if (nvtxs) {
2409*3c41b853SStefano Zampini         ierr = PTScotch_PartGraph_MPI(strat, imbal, vtxdist, xadj, adjncy, vwgt, adjwgt, nparts, tpwgts, assignment, pcomm);CHKERRQ(ierr);
2410*3c41b853SStefano Zampini       }
2411*3c41b853SStefano Zampini       if (hasempty) {
2412*3c41b853SStefano Zampini         ierr = MPI_Comm_free(&pcomm);CHKERRQ(ierr);
2413*3c41b853SStefano Zampini       }
2414137cd93aSLisandro Dalcin     }
2415137cd93aSLisandro Dalcin   }
2416137cd93aSLisandro Dalcin   ierr = PetscFree(vwgt);CHKERRQ(ierr);
2417*3c41b853SStefano Zampini   ierr = PetscFree(tpwgts);CHKERRQ(ierr);
2418137cd93aSLisandro Dalcin 
2419137cd93aSLisandro Dalcin   /* Convert to PetscSection+IS */
2420137cd93aSLisandro Dalcin   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
2421137cd93aSLisandro Dalcin   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
2422137cd93aSLisandro Dalcin   for (p = 0, i = 0; p < nparts; ++p) {
2423137cd93aSLisandro Dalcin     for (v = 0; v < nvtxs; ++v) {
2424137cd93aSLisandro Dalcin       if (assignment[v] == p) points[i++] = v;
2425137cd93aSLisandro Dalcin     }
2426137cd93aSLisandro Dalcin   }
2427137cd93aSLisandro Dalcin   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2428137cd93aSLisandro Dalcin   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2429137cd93aSLisandro Dalcin 
2430137cd93aSLisandro Dalcin   ierr = PetscFree2(vtxdist,assignment);CHKERRQ(ierr);
2431137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2432137cd93aSLisandro Dalcin #else
2433137cd93aSLisandro Dalcin   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-ptscotch.");
2434137cd93aSLisandro Dalcin #endif
2435137cd93aSLisandro Dalcin }
2436137cd93aSLisandro Dalcin 
2437137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerInitialize_PTScotch(PetscPartitioner part)
2438137cd93aSLisandro Dalcin {
2439137cd93aSLisandro Dalcin   PetscFunctionBegin;
2440074d466cSStefano Zampini   part->noGraph             = PETSC_FALSE;
2441137cd93aSLisandro Dalcin   part->ops->view           = PetscPartitionerView_PTScotch;
2442137cd93aSLisandro Dalcin   part->ops->destroy        = PetscPartitionerDestroy_PTScotch;
2443137cd93aSLisandro Dalcin   part->ops->partition      = PetscPartitionerPartition_PTScotch;
2444137cd93aSLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_PTScotch;
2445137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2446137cd93aSLisandro Dalcin }
2447137cd93aSLisandro Dalcin 
2448137cd93aSLisandro Dalcin /*MC
2449137cd93aSLisandro Dalcin   PETSCPARTITIONERPTSCOTCH = "ptscotch" - A PetscPartitioner object using the PT-Scotch library
2450137cd93aSLisandro Dalcin 
2451137cd93aSLisandro Dalcin   Level: intermediate
2452137cd93aSLisandro Dalcin 
2453*3c41b853SStefano Zampini   Options Database Keys:
2454*3c41b853SStefano Zampini +  -petscpartitioner_ptscotch_strategy <string> - PT-Scotch strategy. Choose one of default quality speed balance safety scalability recursive remap
2455*3c41b853SStefano Zampini -  -petscpartitioner_ptscotch_imbalance <val> - Load imbalance ratio
2456*3c41b853SStefano Zampini 
2457*3c41b853SStefano Zampini   Notes: when the graph is on a single process, this partitioner actually uses Scotch and not PT-Scotch
2458*3c41b853SStefano Zampini 
2459137cd93aSLisandro Dalcin .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
2460137cd93aSLisandro Dalcin M*/
2461137cd93aSLisandro Dalcin 
2462137cd93aSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_PTScotch(PetscPartitioner part)
2463137cd93aSLisandro Dalcin {
2464137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p;
2465137cd93aSLisandro Dalcin   PetscErrorCode          ierr;
2466137cd93aSLisandro Dalcin 
2467137cd93aSLisandro Dalcin   PetscFunctionBegin;
2468137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
2469137cd93aSLisandro Dalcin   ierr = PetscNewLog(part, &p);CHKERRQ(ierr);
2470137cd93aSLisandro Dalcin   part->data = p;
2471137cd93aSLisandro Dalcin 
2472*3c41b853SStefano Zampini   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)part),&p->pcomm);CHKERRQ(ierr);
2473137cd93aSLisandro Dalcin   p->strategy  = 0;
2474137cd93aSLisandro Dalcin   p->imbalance = 0.01;
2475137cd93aSLisandro Dalcin 
2476137cd93aSLisandro Dalcin   ierr = PetscPartitionerInitialize_PTScotch(part);CHKERRQ(ierr);
2477137cd93aSLisandro Dalcin   ierr = PetscCitationsRegister(PTScotchPartitionerCitation, &PTScotchPartitionercite);CHKERRQ(ierr);
2478137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2479137cd93aSLisandro Dalcin }
2480137cd93aSLisandro Dalcin 
24815680f57bSMatthew G. Knepley /*@
24825680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
24835680f57bSMatthew G. Knepley 
24845680f57bSMatthew G. Knepley   Not collective
24855680f57bSMatthew G. Knepley 
24865680f57bSMatthew G. Knepley   Input Parameter:
24875680f57bSMatthew G. Knepley . dm - The DM
24885680f57bSMatthew G. Knepley 
24895680f57bSMatthew G. Knepley   Output Parameter:
24905680f57bSMatthew G. Knepley . part - The PetscPartitioner
24915680f57bSMatthew G. Knepley 
24925680f57bSMatthew G. Knepley   Level: developer
24935680f57bSMatthew G. Knepley 
249498599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
249598599a47SLawrence Mitchell 
2496*3c41b853SStefano Zampini .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerDMPlexPartition(), PetscPartitionerCreate()
24975680f57bSMatthew G. Knepley @*/
24985680f57bSMatthew G. Knepley PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
24995680f57bSMatthew G. Knepley {
25005680f57bSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex *) dm->data;
25015680f57bSMatthew G. Knepley 
25025680f57bSMatthew G. Knepley   PetscFunctionBegin;
25035680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
25045680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
25055680f57bSMatthew G. Knepley   *part = mesh->partitioner;
25065680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
25075680f57bSMatthew G. Knepley }
25085680f57bSMatthew G. Knepley 
250971bb2955SLawrence Mitchell /*@
251071bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
251171bb2955SLawrence Mitchell 
2512fe2efc57SMark   logically collective on DM
251371bb2955SLawrence Mitchell 
251471bb2955SLawrence Mitchell   Input Parameters:
251571bb2955SLawrence Mitchell + dm - The DM
251671bb2955SLawrence Mitchell - part - The partitioner
251771bb2955SLawrence Mitchell 
251871bb2955SLawrence Mitchell   Level: developer
251971bb2955SLawrence Mitchell 
252071bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
252171bb2955SLawrence Mitchell 
252271bb2955SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate()
252371bb2955SLawrence Mitchell @*/
252471bb2955SLawrence Mitchell PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
252571bb2955SLawrence Mitchell {
252671bb2955SLawrence Mitchell   DM_Plex       *mesh = (DM_Plex *) dm->data;
252771bb2955SLawrence Mitchell   PetscErrorCode ierr;
252871bb2955SLawrence Mitchell 
252971bb2955SLawrence Mitchell   PetscFunctionBegin;
253071bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
253171bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
253271bb2955SLawrence Mitchell   ierr = PetscObjectReference((PetscObject)part);CHKERRQ(ierr);
253371bb2955SLawrence Mitchell   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
253471bb2955SLawrence Mitchell   mesh->partitioner = part;
253571bb2955SLawrence Mitchell   PetscFunctionReturn(0);
253671bb2955SLawrence Mitchell }
253771bb2955SLawrence Mitchell 
25388e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point)
25398e330a33SStefano Zampini {
25408e330a33SStefano Zampini   const PetscInt *cone;
25418e330a33SStefano Zampini   PetscInt       coneSize, c;
25428e330a33SStefano Zampini   PetscBool      missing;
25438e330a33SStefano Zampini   PetscErrorCode ierr;
25448e330a33SStefano Zampini 
25458e330a33SStefano Zampini   PetscFunctionBeginHot;
25468e330a33SStefano Zampini   ierr = PetscHSetIQueryAdd(ht, point, &missing);CHKERRQ(ierr);
25478e330a33SStefano Zampini   if (missing) {
25488e330a33SStefano Zampini     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
25498e330a33SStefano Zampini     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
25508e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
25518e330a33SStefano Zampini       ierr = DMPlexAddClosure_Private(dm, ht, cone[c]);CHKERRQ(ierr);
25528e330a33SStefano Zampini     }
25538e330a33SStefano Zampini   }
25548e330a33SStefano Zampini   PetscFunctionReturn(0);
25558e330a33SStefano Zampini }
25568e330a33SStefano Zampini 
25578e330a33SStefano Zampini PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
2558270bba0cSToby Isaac {
2559270bba0cSToby Isaac   PetscErrorCode ierr;
2560270bba0cSToby Isaac 
2561270bba0cSToby Isaac   PetscFunctionBegin;
25626a5a2ffdSToby Isaac   if (up) {
25636a5a2ffdSToby Isaac     PetscInt parent;
25646a5a2ffdSToby Isaac 
2565270bba0cSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
25666a5a2ffdSToby Isaac     if (parent != point) {
25676a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
25686a5a2ffdSToby Isaac 
2569270bba0cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
2570270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
2571270bba0cSToby Isaac         PetscInt cpoint = closure[2*i];
2572270bba0cSToby Isaac 
2573e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
25741b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
2575270bba0cSToby Isaac       }
2576270bba0cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
25776a5a2ffdSToby Isaac     }
25786a5a2ffdSToby Isaac   }
25796a5a2ffdSToby Isaac   if (down) {
25806a5a2ffdSToby Isaac     PetscInt numChildren;
25816a5a2ffdSToby Isaac     const PetscInt *children;
25826a5a2ffdSToby Isaac 
25836a5a2ffdSToby Isaac     ierr = DMPlexGetTreeChildren(dm,point,&numChildren,&children);CHKERRQ(ierr);
25846a5a2ffdSToby Isaac     if (numChildren) {
25856a5a2ffdSToby Isaac       PetscInt i;
25866a5a2ffdSToby Isaac 
25876a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
25886a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
25896a5a2ffdSToby Isaac 
2590e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
25911b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
25926a5a2ffdSToby Isaac       }
25936a5a2ffdSToby Isaac     }
25946a5a2ffdSToby Isaac   }
2595270bba0cSToby Isaac   PetscFunctionReturn(0);
2596270bba0cSToby Isaac }
2597270bba0cSToby Isaac 
25988e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point)
25998e330a33SStefano Zampini {
26008e330a33SStefano Zampini   PetscInt       parent;
26018e330a33SStefano Zampini   PetscErrorCode ierr;
2602825f8a23SLisandro Dalcin 
26038e330a33SStefano Zampini   PetscFunctionBeginHot;
26048e330a33SStefano Zampini   ierr = DMPlexGetTreeParent(dm, point, &parent,NULL);CHKERRQ(ierr);
26058e330a33SStefano Zampini   if (point != parent) {
26068e330a33SStefano Zampini     const PetscInt *cone;
26078e330a33SStefano Zampini     PetscInt       coneSize, c;
26088e330a33SStefano Zampini 
26098e330a33SStefano Zampini     ierr = DMPlexAddClosureTree_Up_Private(dm, ht, parent);CHKERRQ(ierr);
26108e330a33SStefano Zampini     ierr = DMPlexAddClosure_Private(dm, ht, parent);CHKERRQ(ierr);
26118e330a33SStefano Zampini     ierr = DMPlexGetCone(dm, parent, &cone);CHKERRQ(ierr);
26128e330a33SStefano Zampini     ierr = DMPlexGetConeSize(dm, parent, &coneSize);CHKERRQ(ierr);
26138e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
26148e330a33SStefano Zampini       const PetscInt cp = cone[c];
26158e330a33SStefano Zampini 
26168e330a33SStefano Zampini       ierr = DMPlexAddClosureTree_Up_Private(dm, ht, cp);CHKERRQ(ierr);
26178e330a33SStefano Zampini     }
26188e330a33SStefano Zampini   }
26198e330a33SStefano Zampini   PetscFunctionReturn(0);
26208e330a33SStefano Zampini }
26218e330a33SStefano Zampini 
26228e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point)
26238e330a33SStefano Zampini {
26248e330a33SStefano Zampini   PetscInt       i, numChildren;
26258e330a33SStefano Zampini   const PetscInt *children;
26268e330a33SStefano Zampini   PetscErrorCode ierr;
26278e330a33SStefano Zampini 
26288e330a33SStefano Zampini   PetscFunctionBeginHot;
26298e330a33SStefano Zampini   ierr = DMPlexGetTreeChildren(dm, point, &numChildren, &children);CHKERRQ(ierr);
26308e330a33SStefano Zampini   for (i = 0; i < numChildren; i++) {
26318e330a33SStefano Zampini     ierr = PetscHSetIAdd(ht, children[i]);CHKERRQ(ierr);
26328e330a33SStefano Zampini   }
26338e330a33SStefano Zampini   PetscFunctionReturn(0);
26348e330a33SStefano Zampini }
26358e330a33SStefano Zampini 
26368e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point)
26378e330a33SStefano Zampini {
26388e330a33SStefano Zampini   const PetscInt *cone;
26398e330a33SStefano Zampini   PetscInt       coneSize, c;
26408e330a33SStefano Zampini   PetscErrorCode ierr;
26418e330a33SStefano Zampini 
26428e330a33SStefano Zampini   PetscFunctionBeginHot;
26438e330a33SStefano Zampini   ierr = PetscHSetIAdd(ht, point);CHKERRQ(ierr);
26448e330a33SStefano Zampini   ierr = DMPlexAddClosureTree_Up_Private(dm, ht, point);CHKERRQ(ierr);
26458e330a33SStefano Zampini   ierr = DMPlexAddClosureTree_Down_Private(dm, ht, point);CHKERRQ(ierr);
26468e330a33SStefano Zampini   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
26478e330a33SStefano Zampini   ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
26488e330a33SStefano Zampini   for (c = 0; c < coneSize; c++) {
26498e330a33SStefano Zampini     ierr = DMPlexAddClosureTree_Private(dm, ht, cone[c]);CHKERRQ(ierr);
26508e330a33SStefano Zampini   }
26518e330a33SStefano Zampini   PetscFunctionReturn(0);
26528e330a33SStefano Zampini }
26538e330a33SStefano Zampini 
26548e330a33SStefano Zampini PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS)
2655825f8a23SLisandro Dalcin {
2656825f8a23SLisandro Dalcin   DM_Plex         *mesh = (DM_Plex *)dm->data;
26578e330a33SStefano Zampini   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
26588e330a33SStefano Zampini   PetscInt        nelems, *elems, off = 0, p;
2659825f8a23SLisandro Dalcin   PetscHSetI      ht;
2660825f8a23SLisandro Dalcin   PetscErrorCode  ierr;
2661825f8a23SLisandro Dalcin 
2662825f8a23SLisandro Dalcin   PetscFunctionBegin;
2663825f8a23SLisandro Dalcin   ierr = PetscHSetICreate(&ht);CHKERRQ(ierr);
2664825f8a23SLisandro Dalcin   ierr = PetscHSetIResize(ht, numPoints*16);CHKERRQ(ierr);
26658e330a33SStefano Zampini   if (!hasTree) {
26668e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
26678e330a33SStefano Zampini       ierr = DMPlexAddClosure_Private(dm, ht, points[p]);CHKERRQ(ierr);
26688e330a33SStefano Zampini     }
26698e330a33SStefano Zampini   } else {
26708e330a33SStefano Zampini #if 1
26718e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
26728e330a33SStefano Zampini       ierr = DMPlexAddClosureTree_Private(dm, ht, points[p]);CHKERRQ(ierr);
26738e330a33SStefano Zampini     }
26748e330a33SStefano Zampini #else
26758e330a33SStefano Zampini     PetscInt  *closure = NULL, closureSize, c;
2676825f8a23SLisandro Dalcin     for (p = 0; p < numPoints; ++p) {
2677825f8a23SLisandro Dalcin       ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2678825f8a23SLisandro Dalcin       for (c = 0; c < closureSize*2; c += 2) {
2679825f8a23SLisandro Dalcin         ierr = PetscHSetIAdd(ht, closure[c]);CHKERRQ(ierr);
2680825f8a23SLisandro Dalcin         if (hasTree) {ierr = DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE);CHKERRQ(ierr);}
2681825f8a23SLisandro Dalcin       }
2682825f8a23SLisandro Dalcin     }
2683825f8a23SLisandro Dalcin     if (closure) {ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure);CHKERRQ(ierr);}
26848e330a33SStefano Zampini #endif
26858e330a33SStefano Zampini   }
2686825f8a23SLisandro Dalcin   ierr = PetscHSetIGetSize(ht, &nelems);CHKERRQ(ierr);
2687825f8a23SLisandro Dalcin   ierr = PetscMalloc1(nelems, &elems);CHKERRQ(ierr);
2688825f8a23SLisandro Dalcin   ierr = PetscHSetIGetElems(ht, &off, elems);CHKERRQ(ierr);
2689825f8a23SLisandro Dalcin   ierr = PetscHSetIDestroy(&ht);CHKERRQ(ierr);
2690825f8a23SLisandro Dalcin   ierr = PetscSortInt(nelems, elems);CHKERRQ(ierr);
2691825f8a23SLisandro Dalcin   ierr = ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS);CHKERRQ(ierr);
2692825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
2693825f8a23SLisandro Dalcin }
2694825f8a23SLisandro Dalcin 
26955abbe4feSMichael Lange /*@
26965abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
26975abbe4feSMichael Lange 
26985abbe4feSMichael Lange   Input Parameters:
26995abbe4feSMichael Lange + dm     - The DM
27005abbe4feSMichael Lange - label  - DMLabel assinging ranks to remote roots
27015abbe4feSMichael Lange 
27025abbe4feSMichael Lange   Level: developer
27035abbe4feSMichael Lange 
270430b0ce1bSStefano Zampini .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
27055abbe4feSMichael Lange @*/
27065abbe4feSMichael Lange PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
27079ffc88e4SToby Isaac {
2708825f8a23SLisandro Dalcin   IS              rankIS,   pointIS, closureIS;
27095abbe4feSMichael Lange   const PetscInt *ranks,   *points;
2710825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
27119ffc88e4SToby Isaac   PetscErrorCode  ierr;
27129ffc88e4SToby Isaac 
27139ffc88e4SToby Isaac   PetscFunctionBegin;
27145abbe4feSMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
27155abbe4feSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
27165abbe4feSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
27175abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
27185abbe4feSMichael Lange     const PetscInt rank = ranks[r];
27195abbe4feSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
27205abbe4feSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
27215abbe4feSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
27228e330a33SStefano Zampini     ierr = DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS);CHKERRQ(ierr);
27235abbe4feSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
27245abbe4feSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2725825f8a23SLisandro Dalcin     ierr = DMLabelSetStratumIS(label, rank, closureIS);CHKERRQ(ierr);
2726825f8a23SLisandro Dalcin     ierr = ISDestroy(&closureIS);CHKERRQ(ierr);
27279ffc88e4SToby Isaac   }
27285abbe4feSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
27295abbe4feSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
27309ffc88e4SToby Isaac   PetscFunctionReturn(0);
27319ffc88e4SToby Isaac }
27329ffc88e4SToby Isaac 
273324d039d7SMichael Lange /*@
273424d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
273524d039d7SMichael Lange 
273624d039d7SMichael Lange   Input Parameters:
273724d039d7SMichael Lange + dm     - The DM
273824d039d7SMichael Lange - label  - DMLabel assinging ranks to remote roots
273924d039d7SMichael Lange 
274024d039d7SMichael Lange   Level: developer
274124d039d7SMichael Lange 
274224d039d7SMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
274324d039d7SMichael Lange @*/
274424d039d7SMichael Lange PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
274570034214SMatthew G. Knepley {
274624d039d7SMichael Lange   IS              rankIS,   pointIS;
274724d039d7SMichael Lange   const PetscInt *ranks,   *points;
274824d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
274924d039d7SMichael Lange   PetscInt       *adj = NULL;
275070034214SMatthew G. Knepley   PetscErrorCode  ierr;
275170034214SMatthew G. Knepley 
275270034214SMatthew G. Knepley   PetscFunctionBegin;
275324d039d7SMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
275424d039d7SMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
275524d039d7SMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
275624d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
275724d039d7SMichael Lange     const PetscInt rank = ranks[r];
275870034214SMatthew G. Knepley 
275924d039d7SMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
276024d039d7SMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
276124d039d7SMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
276270034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
276324d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
276424d039d7SMichael Lange       ierr = DMPlexGetAdjacency(dm, points[p], &adjSize, &adj);CHKERRQ(ierr);
276524d039d7SMichael Lange       for (a = 0; a < adjSize; ++a) {ierr = DMLabelSetValue(label, adj[a], rank);CHKERRQ(ierr);}
276670034214SMatthew G. Knepley     }
276724d039d7SMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
276824d039d7SMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
276970034214SMatthew G. Knepley   }
277024d039d7SMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
277124d039d7SMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
277224d039d7SMichael Lange   ierr = PetscFree(adj);CHKERRQ(ierr);
277324d039d7SMichael Lange   PetscFunctionReturn(0);
277470034214SMatthew G. Knepley }
277570034214SMatthew G. Knepley 
2776be200f8dSMichael Lange /*@
2777be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
2778be200f8dSMichael Lange 
2779be200f8dSMichael Lange   Input Parameters:
2780be200f8dSMichael Lange + dm     - The DM
2781be200f8dSMichael Lange - label  - DMLabel assinging ranks to remote roots
2782be200f8dSMichael Lange 
2783be200f8dSMichael Lange   Level: developer
2784be200f8dSMichael Lange 
2785be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
2786be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
2787be200f8dSMichael Lange 
2788be200f8dSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
2789be200f8dSMichael Lange @*/
2790be200f8dSMichael Lange PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
2791be200f8dSMichael Lange {
2792be200f8dSMichael Lange   MPI_Comm        comm;
2793be200f8dSMichael Lange   PetscMPIInt     rank;
2794be200f8dSMichael Lange   PetscSF         sfPoint;
27955d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
2796be200f8dSMichael Lange   IS              rankIS, pointIS;
2797be200f8dSMichael Lange   const PetscInt *ranks;
2798be200f8dSMichael Lange   PetscInt        numRanks, r;
2799be200f8dSMichael Lange   PetscErrorCode  ierr;
2800be200f8dSMichael Lange 
2801be200f8dSMichael Lange   PetscFunctionBegin;
2802be200f8dSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
2803be200f8dSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2804be200f8dSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
28055d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
28065d04f6ebSMichael Lange   ierr = DMLabelGather(label, sfPoint, &lblLeaves);CHKERRQ(ierr);
28075d04f6ebSMichael Lange   ierr = DMLabelGetValueIS(lblLeaves, &rankIS);CHKERRQ(ierr);
28085d04f6ebSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
28095d04f6ebSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
28105d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
28115d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
28125d04f6ebSMichael Lange     if (remoteRank == rank) continue;
28135d04f6ebSMichael Lange     ierr = DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS);CHKERRQ(ierr);
28145d04f6ebSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
28155d04f6ebSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
28165d04f6ebSMichael Lange   }
28175d04f6ebSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
28185d04f6ebSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
28195d04f6ebSMichael Lange   ierr = DMLabelDestroy(&lblLeaves);CHKERRQ(ierr);
2820be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
2821be200f8dSMichael Lange   ierr = DMLabelDistribute(label, sfPoint, &lblRoots);CHKERRQ(ierr);
2822be200f8dSMichael Lange   ierr = DMLabelGetValueIS(lblRoots, &rankIS);CHKERRQ(ierr);
2823be200f8dSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
2824be200f8dSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
2825be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
2826be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
2827be200f8dSMichael Lange     if (remoteRank == rank) continue;
2828be200f8dSMichael Lange     ierr = DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS);CHKERRQ(ierr);
2829be200f8dSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
2830be200f8dSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2831be200f8dSMichael Lange   }
2832be200f8dSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
2833be200f8dSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
2834be200f8dSMichael Lange   ierr = DMLabelDestroy(&lblRoots);CHKERRQ(ierr);
2835be200f8dSMichael Lange   PetscFunctionReturn(0);
2836be200f8dSMichael Lange }
2837be200f8dSMichael Lange 
28381fd9873aSMichael Lange /*@
28391fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
28401fd9873aSMichael Lange 
28411fd9873aSMichael Lange   Input Parameters:
28421fd9873aSMichael Lange + dm        - The DM
28431fd9873aSMichael Lange . rootLabel - DMLabel assinging ranks to local roots
2844fe2efc57SMark - processSF - A star forest mapping into the local index on each remote rank
28451fd9873aSMichael Lange 
28461fd9873aSMichael Lange   Output Parameter:
2847fe2efc57SMark . leafLabel - DMLabel assinging ranks to remote roots
28481fd9873aSMichael Lange 
28491fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
28501fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
28511fd9873aSMichael Lange 
28521fd9873aSMichael Lange   Level: developer
28531fd9873aSMichael Lange 
28541fd9873aSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
28551fd9873aSMichael Lange @*/
28561fd9873aSMichael Lange PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
28571fd9873aSMichael Lange {
28581fd9873aSMichael Lange   MPI_Comm           comm;
2859874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
2860874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
28611fd9873aSMichael Lange   PetscSF            sfPoint;
2862874ddda9SLisandro Dalcin   PetscSection       rootSection;
28631fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
28641fd9873aSMichael Lange   const PetscSFNode *remote;
28651fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
28661fd9873aSMichael Lange   IS                 valueIS;
2867874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
28681fd9873aSMichael Lange   PetscErrorCode     ierr;
28691fd9873aSMichael Lange 
28701fd9873aSMichael Lange   PetscFunctionBegin;
287130b0ce1bSStefano Zampini   ierr = PetscLogEventBegin(DMPLEX_PartLabelInvert,dm,0,0,0);CHKERRQ(ierr);
28721fd9873aSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
28731fd9873aSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
28749852e123SBarry Smith   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
28751fd9873aSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
28761fd9873aSMichael Lange 
28771fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
28781fd9873aSMichael Lange   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
28799852e123SBarry Smith   ierr = PetscSectionSetChart(rootSection, 0, size);CHKERRQ(ierr);
28801fd9873aSMichael Lange   ierr = DMLabelGetValueIS(rootLabel, &valueIS);CHKERRQ(ierr);
28811fd9873aSMichael Lange   ierr = ISGetLocalSize(valueIS, &numNeighbors);CHKERRQ(ierr);
28821fd9873aSMichael Lange   ierr = ISGetIndices(valueIS, &neighbors);CHKERRQ(ierr);
28831fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
28841fd9873aSMichael Lange     ierr = DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints);CHKERRQ(ierr);
28851fd9873aSMichael Lange     ierr = PetscSectionAddDof(rootSection, neighbors[n], numPoints);CHKERRQ(ierr);
28861fd9873aSMichael Lange   }
28871fd9873aSMichael Lange   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
2888874ddda9SLisandro Dalcin   ierr = PetscSectionGetStorageSize(rootSection, &rootSize);CHKERRQ(ierr);
2889874ddda9SLisandro Dalcin   ierr = PetscMalloc1(rootSize, &rootPoints);CHKERRQ(ierr);
28901fd9873aSMichael Lange   ierr = PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote);CHKERRQ(ierr);
28911fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
28921fd9873aSMichael Lange     IS              pointIS;
28931fd9873aSMichael Lange     const PetscInt *points;
28941fd9873aSMichael Lange 
28951fd9873aSMichael Lange     ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
28961fd9873aSMichael Lange     ierr = DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS);CHKERRQ(ierr);
28971fd9873aSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
28981fd9873aSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
28991fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
2900f8987ae8SMichael Lange       if (local) {ierr = PetscFindInt(points[p], nleaves, local, &l);CHKERRQ(ierr);}
2901f8987ae8SMichael Lange       else       {l = -1;}
29021fd9873aSMichael Lange       if (l >= 0) {rootPoints[off+p] = remote[l];}
29031fd9873aSMichael Lange       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
29041fd9873aSMichael Lange     }
29051fd9873aSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
29061fd9873aSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
29071fd9873aSMichael Lange   }
2908874ddda9SLisandro Dalcin 
2909874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
2910874ddda9SLisandro Dalcin   if (!processSF) {
2911874ddda9SLisandro Dalcin     PetscInt64  counter = 0;
2912874ddda9SLisandro Dalcin     PetscBool   locOverflow = PETSC_FALSE;
2913874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
2914874ddda9SLisandro Dalcin 
2915874ddda9SLisandro Dalcin     ierr = PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls);CHKERRQ(ierr);
2916874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
2917874ddda9SLisandro Dalcin       ierr = PetscSectionGetDof(rootSection, neighbors[n], &dof);CHKERRQ(ierr);
2918874ddda9SLisandro Dalcin       ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
2919874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
2920874ddda9SLisandro Dalcin       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2921874ddda9SLisandro Dalcin       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2922874ddda9SLisandro Dalcin #endif
2923874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt) dof;
2924874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt) off;
2925874ddda9SLisandro Dalcin     }
2926874ddda9SLisandro Dalcin     ierr = MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm);CHKERRQ(ierr);
2927874ddda9SLisandro Dalcin     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
2928874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
2929874ddda9SLisandro Dalcin     ierr = MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm);CHKERRQ(ierr);
2930874ddda9SLisandro Dalcin     if (!mpiOverflow) {
293194b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using Alltoallv for mesh distribution\n");CHKERRQ(ierr);
2932874ddda9SLisandro Dalcin       leafSize = (PetscInt) counter;
2933874ddda9SLisandro Dalcin       ierr = PetscMalloc1(leafSize, &leafPoints);CHKERRQ(ierr);
2934874ddda9SLisandro Dalcin       ierr = MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm);CHKERRQ(ierr);
2935874ddda9SLisandro Dalcin     }
2936874ddda9SLisandro Dalcin     ierr = PetscFree4(scounts, sdispls, rcounts, rdispls);CHKERRQ(ierr);
2937874ddda9SLisandro Dalcin   }
2938874ddda9SLisandro Dalcin 
2939874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
2940874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
2941874ddda9SLisandro Dalcin     PetscSF      procSF;
2942874ddda9SLisandro Dalcin     PetscSection leafSection;
2943874ddda9SLisandro Dalcin 
2944874ddda9SLisandro Dalcin     if (processSF) {
294594b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using processSF for mesh distribution\n");CHKERRQ(ierr);
2946874ddda9SLisandro Dalcin       ierr = PetscObjectReference((PetscObject)processSF);CHKERRQ(ierr);
2947874ddda9SLisandro Dalcin       procSF = processSF;
2948874ddda9SLisandro Dalcin     } else {
294994b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using processSF for mesh distribution (MPI overflow)\n");CHKERRQ(ierr);
2950874ddda9SLisandro Dalcin       ierr = PetscSFCreate(comm,&procSF);CHKERRQ(ierr);
2951900e0f05SJunchao Zhang       ierr = PetscSFSetGraphWithPattern(procSF,NULL,PETSCSF_PATTERN_ALLTOALL);CHKERRQ(ierr);
2952874ddda9SLisandro Dalcin     }
2953874ddda9SLisandro Dalcin 
2954874ddda9SLisandro Dalcin     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection);CHKERRQ(ierr);
2955900e0f05SJunchao Zhang     ierr = DMPlexDistributeData(dm, procSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints);CHKERRQ(ierr);
2956874ddda9SLisandro Dalcin     ierr = PetscSectionGetStorageSize(leafSection, &leafSize);CHKERRQ(ierr);
2957874ddda9SLisandro Dalcin     ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
2958874ddda9SLisandro Dalcin     ierr = PetscSFDestroy(&procSF);CHKERRQ(ierr);
2959874ddda9SLisandro Dalcin   }
2960874ddda9SLisandro Dalcin 
2961874ddda9SLisandro Dalcin   for (p = 0; p < leafSize; p++) {
29621fd9873aSMichael Lange     ierr = DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank);CHKERRQ(ierr);
29631fd9873aSMichael Lange   }
2964874ddda9SLisandro Dalcin 
2965874ddda9SLisandro Dalcin   ierr = ISRestoreIndices(valueIS, &neighbors);CHKERRQ(ierr);
2966874ddda9SLisandro Dalcin   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
29671fd9873aSMichael Lange   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
2968874ddda9SLisandro Dalcin   ierr = PetscFree(rootPoints);CHKERRQ(ierr);
29691fd9873aSMichael Lange   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
297030b0ce1bSStefano Zampini   ierr = PetscLogEventEnd(DMPLEX_PartLabelInvert,dm,0,0,0);CHKERRQ(ierr);
29711fd9873aSMichael Lange   PetscFunctionReturn(0);
29721fd9873aSMichael Lange }
29731fd9873aSMichael Lange 
2974aa3148a8SMichael Lange /*@
2975aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
2976aa3148a8SMichael Lange 
2977aa3148a8SMichael Lange   Input Parameters:
2978aa3148a8SMichael Lange + dm    - The DM
2979aa3148a8SMichael Lange . label - DMLabel assinging ranks to remote roots
2980aa3148a8SMichael Lange 
2981aa3148a8SMichael Lange   Output Parameter:
2982fe2efc57SMark . sf    - The star forest communication context encapsulating the defined mapping
2983aa3148a8SMichael Lange 
2984aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
2985aa3148a8SMichael Lange 
2986aa3148a8SMichael Lange   Level: developer
2987aa3148a8SMichael Lange 
298830b0ce1bSStefano Zampini .seealso: DMPlexDistribute(), DMPlexCreateOverlap()
2989aa3148a8SMichael Lange @*/
2990aa3148a8SMichael Lange PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
2991aa3148a8SMichael Lange {
29926e203dd9SStefano Zampini   PetscMPIInt     rank;
29936e203dd9SStefano Zampini   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
2994aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
29956e203dd9SStefano Zampini   IS              remoteRootIS, neighborsIS;
29966e203dd9SStefano Zampini   const PetscInt *remoteRoots, *neighbors;
2997aa3148a8SMichael Lange   PetscErrorCode ierr;
2998aa3148a8SMichael Lange 
2999aa3148a8SMichael Lange   PetscFunctionBegin;
300030b0ce1bSStefano Zampini   ierr = PetscLogEventBegin(DMPLEX_PartLabelCreateSF,dm,0,0,0);CHKERRQ(ierr);
300143f7d02bSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
3002aa3148a8SMichael Lange 
30036e203dd9SStefano Zampini   ierr = DMLabelGetValueIS(label, &neighborsIS);CHKERRQ(ierr);
30046e203dd9SStefano Zampini #if 0
30056e203dd9SStefano Zampini   {
30066e203dd9SStefano Zampini     IS is;
30076e203dd9SStefano Zampini     ierr = ISDuplicate(neighborsIS, &is);CHKERRQ(ierr);
30086e203dd9SStefano Zampini     ierr = ISSort(is);CHKERRQ(ierr);
30096e203dd9SStefano Zampini     ierr = ISDestroy(&neighborsIS);CHKERRQ(ierr);
30106e203dd9SStefano Zampini     neighborsIS = is;
30116e203dd9SStefano Zampini   }
30126e203dd9SStefano Zampini #endif
30136e203dd9SStefano Zampini   ierr = ISGetLocalSize(neighborsIS, &nNeighbors);CHKERRQ(ierr);
30146e203dd9SStefano Zampini   ierr = ISGetIndices(neighborsIS, &neighbors);CHKERRQ(ierr);
30156e203dd9SStefano Zampini   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
30166e203dd9SStefano Zampini     ierr = DMLabelGetStratumSize(label, neighbors[n], &numPoints);CHKERRQ(ierr);
3017aa3148a8SMichael Lange     numRemote += numPoints;
3018aa3148a8SMichael Lange   }
3019aa3148a8SMichael Lange   ierr = PetscMalloc1(numRemote, &remotePoints);CHKERRQ(ierr);
302043f7d02bSMichael Lange   /* Put owned points first */
302143f7d02bSMichael Lange   ierr = DMLabelGetStratumSize(label, rank, &numPoints);CHKERRQ(ierr);
302243f7d02bSMichael Lange   if (numPoints > 0) {
302343f7d02bSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &remoteRootIS);CHKERRQ(ierr);
302443f7d02bSMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
302543f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
302643f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
302743f7d02bSMichael Lange       remotePoints[idx].rank = rank;
302843f7d02bSMichael Lange       idx++;
302943f7d02bSMichael Lange     }
303043f7d02bSMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
303143f7d02bSMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
303243f7d02bSMichael Lange   }
303343f7d02bSMichael Lange   /* Now add remote points */
30346e203dd9SStefano Zampini   for (n = 0; n < nNeighbors; ++n) {
30356e203dd9SStefano Zampini     const PetscInt nn = neighbors[n];
30366e203dd9SStefano Zampini 
30376e203dd9SStefano Zampini     ierr = DMLabelGetStratumSize(label, nn, &numPoints);CHKERRQ(ierr);
30386e203dd9SStefano Zampini     if (nn == rank || numPoints <= 0) continue;
30396e203dd9SStefano Zampini     ierr = DMLabelGetStratumIS(label, nn, &remoteRootIS);CHKERRQ(ierr);
3040aa3148a8SMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
3041aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
3042aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
30436e203dd9SStefano Zampini       remotePoints[idx].rank = nn;
3044aa3148a8SMichael Lange       idx++;
3045aa3148a8SMichael Lange     }
3046aa3148a8SMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
3047aa3148a8SMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
3048aa3148a8SMichael Lange   }
3049aa3148a8SMichael Lange   ierr = PetscSFCreate(PetscObjectComm((PetscObject) dm), sf);CHKERRQ(ierr);
3050aa3148a8SMichael Lange   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3051aa3148a8SMichael Lange   ierr = PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
305230b0ce1bSStefano Zampini   ierr = PetscSFSetUp(*sf);CHKERRQ(ierr);
30536e203dd9SStefano Zampini   ierr = ISDestroy(&neighborsIS);CHKERRQ(ierr);
305430b0ce1bSStefano Zampini   ierr = PetscLogEventEnd(DMPLEX_PartLabelCreateSF,dm,0,0,0);CHKERRQ(ierr);
305570034214SMatthew G. Knepley   PetscFunctionReturn(0);
305670034214SMatthew G. Knepley }
3057cb87ef4cSFlorian Wechsung 
30586a3739e5SFlorian Wechsung /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
30596a3739e5SFlorian Wechsung  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
30606a3739e5SFlorian Wechsung  * them out in that case. */
30616a3739e5SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
30627a82c785SFlorian Wechsung /*@C
30637f57c1a4SFlorian Wechsung 
30647f57c1a4SFlorian Wechsung   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).
30657f57c1a4SFlorian Wechsung 
30667f57c1a4SFlorian Wechsung   Input parameters:
30677f57c1a4SFlorian Wechsung + dm                - The DMPlex object.
3068fe2efc57SMark . n                 - The number of points.
3069fe2efc57SMark . pointsToRewrite   - The points in the SF whose ownership will change.
3070fe2efc57SMark . targetOwners      - New owner for each element in pointsToRewrite.
3071fe2efc57SMark - degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.
30727f57c1a4SFlorian Wechsung 
30737f57c1a4SFlorian Wechsung   Level: developer
30747f57c1a4SFlorian Wechsung 
30757f57c1a4SFlorian Wechsung @*/
30767f57c1a4SFlorian Wechsung static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
30777f57c1a4SFlorian Wechsung {
30787f57c1a4SFlorian Wechsung   PetscInt      ierr, pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
30797f57c1a4SFlorian Wechsung   PetscInt     *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
30807f57c1a4SFlorian Wechsung   PetscSFNode  *leafLocationsNew;
30817f57c1a4SFlorian Wechsung   const         PetscSFNode *iremote;
30827f57c1a4SFlorian Wechsung   const         PetscInt *ilocal;
30837f57c1a4SFlorian Wechsung   PetscBool    *isLeaf;
30847f57c1a4SFlorian Wechsung   PetscSF       sf;
30857f57c1a4SFlorian Wechsung   MPI_Comm      comm;
30865a30b08bSFlorian Wechsung   PetscMPIInt   rank, size;
30877f57c1a4SFlorian Wechsung 
30887f57c1a4SFlorian Wechsung   PetscFunctionBegin;
30897f57c1a4SFlorian Wechsung   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
30907f57c1a4SFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
30917f57c1a4SFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
30927f57c1a4SFlorian Wechsung   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
30937f57c1a4SFlorian Wechsung 
30947f57c1a4SFlorian Wechsung   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
30957f57c1a4SFlorian Wechsung   ierr = PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote); CHKERRQ(ierr);
30967f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isLeaf);CHKERRQ(ierr);
30977f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
30987f57c1a4SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
30997f57c1a4SFlorian Wechsung   }
31007f57c1a4SFlorian Wechsung   for (i=0; i<nleafs; i++) {
31017f57c1a4SFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
31027f57c1a4SFlorian Wechsung   }
31037f57c1a4SFlorian Wechsung 
31047f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart+1, &cumSumDegrees);CHKERRQ(ierr);
31057f57c1a4SFlorian Wechsung   cumSumDegrees[0] = 0;
31067f57c1a4SFlorian Wechsung   for (i=1; i<=pEnd-pStart; i++) {
31077f57c1a4SFlorian Wechsung     cumSumDegrees[i] = cumSumDegrees[i-1] + degrees[i-1];
31087f57c1a4SFlorian Wechsung   }
31097f57c1a4SFlorian Wechsung   sumDegrees = cumSumDegrees[pEnd-pStart];
31107f57c1a4SFlorian Wechsung   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
31117f57c1a4SFlorian Wechsung 
31127f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(sumDegrees, &locationsOfLeafs);CHKERRQ(ierr);
31137f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &rankOnLeafs);CHKERRQ(ierr);
31147f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
31157f57c1a4SFlorian Wechsung     rankOnLeafs[i] = rank;
31167f57c1a4SFlorian Wechsung   }
31177f57c1a4SFlorian Wechsung   ierr = PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);CHKERRQ(ierr);
31187f57c1a4SFlorian Wechsung   ierr = PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);CHKERRQ(ierr);
31197f57c1a4SFlorian Wechsung   ierr = PetscFree(rankOnLeafs);CHKERRQ(ierr);
31207f57c1a4SFlorian Wechsung 
31217f57c1a4SFlorian Wechsung   /* get the remote local points of my leaves */
31227f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs);CHKERRQ(ierr);
31237f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &points);CHKERRQ(ierr);
31247f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
31257f57c1a4SFlorian Wechsung     points[i] = pStart+i;
31267f57c1a4SFlorian Wechsung   }
31277f57c1a4SFlorian Wechsung   ierr = PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs);CHKERRQ(ierr);
31287f57c1a4SFlorian Wechsung   ierr = PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs);CHKERRQ(ierr);
31297f57c1a4SFlorian Wechsung   ierr = PetscFree(points);CHKERRQ(ierr);
31307f57c1a4SFlorian Wechsung   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
31317f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &newOwners);CHKERRQ(ierr);
31327f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &newNumbers);CHKERRQ(ierr);
31337f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
31347f57c1a4SFlorian Wechsung     newOwners[i] = -1;
31357f57c1a4SFlorian Wechsung     newNumbers[i] = -1;
31367f57c1a4SFlorian Wechsung   }
31377f57c1a4SFlorian Wechsung   {
31387f57c1a4SFlorian Wechsung     PetscInt oldNumber, newNumber, oldOwner, newOwner;
31397f57c1a4SFlorian Wechsung     for (i=0; i<n; i++) {
31407f57c1a4SFlorian Wechsung       oldNumber = pointsToRewrite[i];
31417f57c1a4SFlorian Wechsung       newNumber = -1;
31427f57c1a4SFlorian Wechsung       oldOwner = rank;
31437f57c1a4SFlorian Wechsung       newOwner = targetOwners[i];
31447f57c1a4SFlorian Wechsung       if (oldOwner == newOwner) {
31457f57c1a4SFlorian Wechsung         newNumber = oldNumber;
31467f57c1a4SFlorian Wechsung       } else {
31477f57c1a4SFlorian Wechsung         for (j=0; j<degrees[oldNumber]; j++) {
31487f57c1a4SFlorian Wechsung           if (locationsOfLeafs[cumSumDegrees[oldNumber]+j] == newOwner) {
31497f57c1a4SFlorian Wechsung             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber]+j];
31507f57c1a4SFlorian Wechsung             break;
31517f57c1a4SFlorian Wechsung           }
31527f57c1a4SFlorian Wechsung         }
31537f57c1a4SFlorian Wechsung       }
31547f57c1a4SFlorian Wechsung       if (newNumber == -1) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
31557f57c1a4SFlorian Wechsung 
31567f57c1a4SFlorian Wechsung       newOwners[oldNumber] = newOwner;
31577f57c1a4SFlorian Wechsung       newNumbers[oldNumber] = newNumber;
31587f57c1a4SFlorian Wechsung     }
31597f57c1a4SFlorian Wechsung   }
31607f57c1a4SFlorian Wechsung   ierr = PetscFree(cumSumDegrees);CHKERRQ(ierr);
31617f57c1a4SFlorian Wechsung   ierr = PetscFree(locationsOfLeafs);CHKERRQ(ierr);
31627f57c1a4SFlorian Wechsung   ierr = PetscFree(remoteLocalPointOfLeafs);CHKERRQ(ierr);
31637f57c1a4SFlorian Wechsung 
31647f57c1a4SFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners);CHKERRQ(ierr);
31657f57c1a4SFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners);CHKERRQ(ierr);
31667f57c1a4SFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers);CHKERRQ(ierr);
31677f57c1a4SFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers);CHKERRQ(ierr);
31687f57c1a4SFlorian Wechsung 
31697f57c1a4SFlorian Wechsung   /* Now count how many leafs we have on each processor. */
31707f57c1a4SFlorian Wechsung   leafCounter=0;
31717f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
31727f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
31737f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
31747f57c1a4SFlorian Wechsung         leafCounter++;
31757f57c1a4SFlorian Wechsung       }
31767f57c1a4SFlorian Wechsung     } else {
31777f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
31787f57c1a4SFlorian Wechsung         leafCounter++;
31797f57c1a4SFlorian Wechsung       }
31807f57c1a4SFlorian Wechsung     }
31817f57c1a4SFlorian Wechsung   }
31827f57c1a4SFlorian Wechsung 
31837f57c1a4SFlorian Wechsung   /* Now set up the new sf by creating the leaf arrays */
31847f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(leafCounter, &leafsNew);CHKERRQ(ierr);
31857f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(leafCounter, &leafLocationsNew);CHKERRQ(ierr);
31867f57c1a4SFlorian Wechsung 
31877f57c1a4SFlorian Wechsung   leafCounter = 0;
31887f57c1a4SFlorian Wechsung   counter = 0;
31897f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
31907f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
31917f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
31927f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
31937f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = newOwners[i];
31947f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = newNumbers[i];
31957f57c1a4SFlorian Wechsung         leafCounter++;
31967f57c1a4SFlorian Wechsung       }
31977f57c1a4SFlorian Wechsung     } else {
31987f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
31997f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
32007f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = iremote[counter].rank;
32017f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = iremote[counter].index;
32027f57c1a4SFlorian Wechsung         leafCounter++;
32037f57c1a4SFlorian Wechsung       }
32047f57c1a4SFlorian Wechsung     }
32057f57c1a4SFlorian Wechsung     if (isLeaf[i]) {
32067f57c1a4SFlorian Wechsung       counter++;
32077f57c1a4SFlorian Wechsung     }
32087f57c1a4SFlorian Wechsung   }
32097f57c1a4SFlorian Wechsung 
32107f57c1a4SFlorian Wechsung   ierr = PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
32117f57c1a4SFlorian Wechsung   ierr = PetscFree(newOwners);CHKERRQ(ierr);
32127f57c1a4SFlorian Wechsung   ierr = PetscFree(newNumbers);CHKERRQ(ierr);
32137f57c1a4SFlorian Wechsung   ierr = PetscFree(isLeaf);CHKERRQ(ierr);
32147f57c1a4SFlorian Wechsung   PetscFunctionReturn(0);
32157f57c1a4SFlorian Wechsung }
32167f57c1a4SFlorian Wechsung 
3217125d2a8fSFlorian Wechsung static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
3218125d2a8fSFlorian Wechsung {
32195a30b08bSFlorian Wechsung   PetscInt *distribution, min, max, sum, i, ierr;
32205a30b08bSFlorian Wechsung   PetscMPIInt rank, size;
3221125d2a8fSFlorian Wechsung   PetscFunctionBegin;
3222125d2a8fSFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3223125d2a8fSFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3224125d2a8fSFlorian Wechsung   ierr = PetscCalloc1(size, &distribution);CHKERRQ(ierr);
3225125d2a8fSFlorian Wechsung   for (i=0; i<n; i++) {
3226125d2a8fSFlorian Wechsung     if (part) distribution[part[i]] += vtxwgt[skip*i];
3227125d2a8fSFlorian Wechsung     else distribution[rank] += vtxwgt[skip*i];
3228125d2a8fSFlorian Wechsung   }
3229125d2a8fSFlorian Wechsung   ierr = MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
3230125d2a8fSFlorian Wechsung   min = distribution[0];
3231125d2a8fSFlorian Wechsung   max = distribution[0];
3232125d2a8fSFlorian Wechsung   sum = distribution[0];
3233125d2a8fSFlorian Wechsung   for (i=1; i<size; i++) {
3234125d2a8fSFlorian Wechsung     if (distribution[i]<min) min=distribution[i];
3235125d2a8fSFlorian Wechsung     if (distribution[i]>max) max=distribution[i];
3236125d2a8fSFlorian Wechsung     sum += distribution[i];
3237125d2a8fSFlorian Wechsung   }
3238125d2a8fSFlorian Wechsung   ierr = PetscViewerASCIIPrintf(viewer, "Min: %D, Avg: %D, Max: %D, Balance: %f\n", min, sum/size, max, (max*1.*size)/sum);CHKERRQ(ierr);
3239125d2a8fSFlorian Wechsung   ierr = PetscFree(distribution);CHKERRQ(ierr);
3240125d2a8fSFlorian Wechsung   PetscFunctionReturn(0);
3241125d2a8fSFlorian Wechsung }
3242125d2a8fSFlorian Wechsung 
32436a3739e5SFlorian Wechsung #endif
32446a3739e5SFlorian Wechsung 
3245cb87ef4cSFlorian Wechsung /*@
32465dc86ac1SFlorian 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.
3247cb87ef4cSFlorian Wechsung 
3248cb87ef4cSFlorian Wechsung   Input parameters:
3249ed44d270SFlorian Wechsung + dm               - The DMPlex object.
3250fe2efc57SMark . entityDepth      - depth of the entity to balance (0 -> balance vertices).
3251fe2efc57SMark . useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
3252fe2efc57SMark - parallel         - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.
3253cb87ef4cSFlorian Wechsung 
32548b879b41SFlorian Wechsung   Output parameters:
3255fe2efc57SMark . success          - whether the graph partitioning was successful or not. If not, try useInitialGuess=True and parallel=True.
32568b879b41SFlorian Wechsung 
325790ea27d8SSatish Balay   Level: intermediate
3258cb87ef4cSFlorian Wechsung 
3259cb87ef4cSFlorian Wechsung @*/
3260cb87ef4cSFlorian Wechsung 
32618b879b41SFlorian Wechsung PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
3262cb87ef4cSFlorian Wechsung {
326341525646SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
3264cb87ef4cSFlorian Wechsung   PetscSF     sf;
32650faf6628SFlorian Wechsung   PetscInt    ierr, i, j, idx, jdx;
32667f57c1a4SFlorian Wechsung   PetscInt    eBegin, eEnd, nroots, nleafs, pStart, pEnd;
32677f57c1a4SFlorian Wechsung   const       PetscInt *degrees, *ilocal;
32687f57c1a4SFlorian Wechsung   const       PetscSFNode *iremote;
3269cb87ef4cSFlorian Wechsung   PetscBool   *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
3270cf818975SFlorian Wechsung   PetscInt    numExclusivelyOwned, numNonExclusivelyOwned;
3271cb87ef4cSFlorian Wechsung   PetscMPIInt rank, size;
32727f57c1a4SFlorian Wechsung   PetscInt    *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
32735dc86ac1SFlorian Wechsung   const       PetscInt *cumSumVertices;
3274cb87ef4cSFlorian Wechsung   PetscInt    offset, counter;
32757f57c1a4SFlorian Wechsung   PetscInt    lenadjncy;
3276cb87ef4cSFlorian Wechsung   PetscInt    *xadj, *adjncy, *vtxwgt;
3277cb87ef4cSFlorian Wechsung   PetscInt    lenxadj;
3278cb87ef4cSFlorian Wechsung   PetscInt    *adjwgt = NULL;
3279cb87ef4cSFlorian Wechsung   PetscInt    *part, *options;
3280cf818975SFlorian Wechsung   PetscInt    nparts, wgtflag, numflag, ncon, edgecut;
3281cb87ef4cSFlorian Wechsung   real_t      *ubvec;
3282cb87ef4cSFlorian Wechsung   PetscInt    *firstVertices, *renumbering;
3283cb87ef4cSFlorian Wechsung   PetscInt    failed, failedGlobal;
3284cb87ef4cSFlorian Wechsung   MPI_Comm    comm;
32854baf1206SFlorian Wechsung   Mat         A, Apre;
328612617df9SFlorian Wechsung   const char *prefix = NULL;
32877d197802SFlorian Wechsung   PetscViewer       viewer;
32887d197802SFlorian Wechsung   PetscViewerFormat format;
32895a30b08bSFlorian Wechsung   PetscLayout layout;
329012617df9SFlorian Wechsung 
329112617df9SFlorian Wechsung   PetscFunctionBegin;
32928b879b41SFlorian Wechsung   if (success) *success = PETSC_FALSE;
32937f57c1a4SFlorian Wechsung   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
32947f57c1a4SFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
32957f57c1a4SFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
32967f57c1a4SFlorian Wechsung   if (size==1) PetscFunctionReturn(0);
32977f57c1a4SFlorian Wechsung 
329841525646SFlorian Wechsung   ierr = PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
329941525646SFlorian Wechsung 
33005a30b08bSFlorian Wechsung   ierr = PetscOptionsGetViewer(comm,((PetscObject)dm)->options, prefix,"-dm_rebalance_partition_view",&viewer,&format,NULL);CHKERRQ(ierr);
33015dc86ac1SFlorian Wechsung   if (viewer) {
33025a30b08bSFlorian Wechsung     ierr = PetscViewerPushFormat(viewer,format);CHKERRQ(ierr);
33037d197802SFlorian Wechsung   }
33047d197802SFlorian Wechsung 
3305ed44d270SFlorian Wechsung   /* Figure out all points in the plex that we are interested in balancing. */
3306d5528e35SFlorian Wechsung   ierr = DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd);CHKERRQ(ierr);
3307cb87ef4cSFlorian Wechsung   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3308cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &toBalance);CHKERRQ(ierr);
3309cf818975SFlorian Wechsung 
3310cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
33115a7e692eSFlorian Wechsung     toBalance[i] = (PetscBool)(i-pStart>=eBegin && i-pStart<eEnd);
3312cb87ef4cSFlorian Wechsung   }
3313cb87ef4cSFlorian Wechsung 
3314cf818975SFlorian Wechsung   /* There are three types of points:
3315cf818975SFlorian Wechsung    * exclusivelyOwned: points that are owned by this process and only seen by this process
3316cf818975SFlorian Wechsung    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
3317cf818975SFlorian Wechsung    * leaf: a point that is seen by this process but owned by a different process
3318cf818975SFlorian Wechsung    */
3319cb87ef4cSFlorian Wechsung   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
3320cb87ef4cSFlorian Wechsung   ierr = PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote); CHKERRQ(ierr);
3321cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isLeaf);CHKERRQ(ierr);
3322cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isNonExclusivelyOwned);CHKERRQ(ierr);
3323cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isExclusivelyOwned);CHKERRQ(ierr);
3324cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
3325cb87ef4cSFlorian Wechsung     isNonExclusivelyOwned[i] = PETSC_FALSE;
3326cb87ef4cSFlorian Wechsung     isExclusivelyOwned[i] = PETSC_FALSE;
3327cf818975SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
3328cb87ef4cSFlorian Wechsung   }
3329cf818975SFlorian Wechsung 
3330cf818975SFlorian Wechsung   /* start by marking all the leafs */
3331cb87ef4cSFlorian Wechsung   for (i=0; i<nleafs; i++) {
3332cb87ef4cSFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
3333cb87ef4cSFlorian Wechsung   }
3334cb87ef4cSFlorian Wechsung 
3335cf818975SFlorian Wechsung   /* for an owned point, we can figure out whether another processor sees it or
3336cf818975SFlorian Wechsung    * not by calculating its degree */
33377f57c1a4SFlorian Wechsung   ierr = PetscSFComputeDegreeBegin(sf, &degrees);CHKERRQ(ierr);
33387f57c1a4SFlorian Wechsung   ierr = PetscSFComputeDegreeEnd(sf, &degrees);CHKERRQ(ierr);
3339cf818975SFlorian Wechsung 
3340cb87ef4cSFlorian Wechsung   numExclusivelyOwned = 0;
3341cb87ef4cSFlorian Wechsung   numNonExclusivelyOwned = 0;
3342cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
3343cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
33447f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
3345cb87ef4cSFlorian Wechsung         isNonExclusivelyOwned[i] = PETSC_TRUE;
3346cb87ef4cSFlorian Wechsung         numNonExclusivelyOwned += 1;
3347cb87ef4cSFlorian Wechsung       } else {
3348cb87ef4cSFlorian Wechsung         if (!isLeaf[i]) {
3349cb87ef4cSFlorian Wechsung           isExclusivelyOwned[i] = PETSC_TRUE;
3350cb87ef4cSFlorian Wechsung           numExclusivelyOwned += 1;
3351cb87ef4cSFlorian Wechsung         }
3352cb87ef4cSFlorian Wechsung       }
3353cb87ef4cSFlorian Wechsung     }
3354cb87ef4cSFlorian Wechsung   }
3355cb87ef4cSFlorian Wechsung 
3356cf818975SFlorian Wechsung   /* We are going to build a graph with one vertex per core representing the
3357cf818975SFlorian Wechsung    * exclusively owned points and then one vertex per nonExclusively owned
3358cf818975SFlorian Wechsung    * point. */
3359cb87ef4cSFlorian Wechsung 
33605dc86ac1SFlorian Wechsung   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
33615dc86ac1SFlorian Wechsung   ierr = PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned);CHKERRQ(ierr);
33625dc86ac1SFlorian Wechsung   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
33635dc86ac1SFlorian Wechsung   ierr = PetscLayoutGetRanges(layout, &cumSumVertices);CHKERRQ(ierr);
33645dc86ac1SFlorian Wechsung 
3365cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &globalNumbersOfLocalOwnedVertices);CHKERRQ(ierr);
33665a427404SJunchao Zhang   for (i=0; i<pEnd-pStart; i++) {globalNumbersOfLocalOwnedVertices[i] = pStart - 1;}
3367cb87ef4cSFlorian Wechsung   offset = cumSumVertices[rank];
3368cb87ef4cSFlorian Wechsung   counter = 0;
3369cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
3370cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
33717f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
3372cb87ef4cSFlorian Wechsung         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
3373cb87ef4cSFlorian Wechsung         counter++;
3374cb87ef4cSFlorian Wechsung       }
3375cb87ef4cSFlorian Wechsung     }
3376cb87ef4cSFlorian Wechsung   }
3377cb87ef4cSFlorian Wechsung 
3378cb87ef4cSFlorian Wechsung   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
3379cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &leafGlobalNumbers);CHKERRQ(ierr);
3380cb87ef4cSFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers);CHKERRQ(ierr);
3381cb87ef4cSFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers);CHKERRQ(ierr);
3382cb87ef4cSFlorian Wechsung 
33830faf6628SFlorian Wechsung   /* Now start building the data structure for ParMETIS */
3384cb87ef4cSFlorian Wechsung 
33854baf1206SFlorian Wechsung   ierr = MatCreate(comm, &Apre);CHKERRQ(ierr);
33864baf1206SFlorian Wechsung   ierr = MatSetType(Apre, MATPREALLOCATOR);CHKERRQ(ierr);
33874baf1206SFlorian Wechsung   ierr = MatSetSizes(Apre, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);CHKERRQ(ierr);
33884baf1206SFlorian Wechsung   ierr = MatSetUp(Apre);CHKERRQ(ierr);
33898c9a1619SFlorian Wechsung 
33908c9a1619SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
33918c9a1619SFlorian Wechsung     if (toBalance[i]) {
33920faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
33930faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
33940faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
33950faf6628SFlorian Wechsung       else continue;
33960faf6628SFlorian Wechsung       ierr = MatSetValue(Apre, idx, jdx, 1, INSERT_VALUES);CHKERRQ(ierr);
33970faf6628SFlorian Wechsung       ierr = MatSetValue(Apre, jdx, idx, 1, INSERT_VALUES);CHKERRQ(ierr);
33984baf1206SFlorian Wechsung     }
33994baf1206SFlorian Wechsung   }
34004baf1206SFlorian Wechsung 
34014baf1206SFlorian Wechsung   ierr = MatAssemblyBegin(Apre, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
34024baf1206SFlorian Wechsung   ierr = MatAssemblyEnd(Apre, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
34034baf1206SFlorian Wechsung 
34044baf1206SFlorian Wechsung   ierr = MatCreate(comm, &A);CHKERRQ(ierr);
34054baf1206SFlorian Wechsung   ierr = MatSetType(A, MATMPIAIJ);CHKERRQ(ierr);
34064baf1206SFlorian Wechsung   ierr = MatSetSizes(A, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);CHKERRQ(ierr);
34074baf1206SFlorian Wechsung   ierr = MatPreallocatorPreallocate(Apre, PETSC_FALSE, A);CHKERRQ(ierr);
34084baf1206SFlorian Wechsung   ierr = MatDestroy(&Apre);CHKERRQ(ierr);
34094baf1206SFlorian Wechsung 
34104baf1206SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
34114baf1206SFlorian Wechsung     if (toBalance[i]) {
34120faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
34130faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
34140faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
34150faf6628SFlorian Wechsung       else continue;
34160faf6628SFlorian Wechsung       ierr = MatSetValue(A, idx, jdx, 1, INSERT_VALUES);CHKERRQ(ierr);
34170faf6628SFlorian Wechsung       ierr = MatSetValue(A, jdx, idx, 1, INSERT_VALUES);CHKERRQ(ierr);
34180941debbSFlorian Wechsung     }
34190941debbSFlorian Wechsung   }
34208c9a1619SFlorian Wechsung 
34218c9a1619SFlorian Wechsung   ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
34228c9a1619SFlorian Wechsung   ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
34234baf1206SFlorian Wechsung   ierr = PetscFree(leafGlobalNumbers);CHKERRQ(ierr);
34244baf1206SFlorian Wechsung   ierr = PetscFree(globalNumbersOfLocalOwnedVertices);CHKERRQ(ierr);
34254baf1206SFlorian Wechsung 
342641525646SFlorian Wechsung   nparts = size;
342741525646SFlorian Wechsung   wgtflag = 2;
342841525646SFlorian Wechsung   numflag = 0;
342941525646SFlorian Wechsung   ncon = 2;
343041525646SFlorian Wechsung   real_t *tpwgts;
343141525646SFlorian Wechsung   ierr = PetscMalloc1(ncon * nparts, &tpwgts);CHKERRQ(ierr);
343241525646SFlorian Wechsung   for (i=0; i<ncon*nparts; i++) {
343341525646SFlorian Wechsung     tpwgts[i] = 1./(nparts);
343441525646SFlorian Wechsung   }
343541525646SFlorian Wechsung 
343641525646SFlorian Wechsung   ierr = PetscMalloc1(ncon, &ubvec);CHKERRQ(ierr);
343741525646SFlorian Wechsung   ubvec[0] = 1.01;
34385a30b08bSFlorian Wechsung   ubvec[1] = 1.01;
34398c9a1619SFlorian Wechsung   lenadjncy = 0;
34408c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
34418c9a1619SFlorian Wechsung     PetscInt temp=0;
34428c9a1619SFlorian Wechsung     ierr = MatGetRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);CHKERRQ(ierr);
34438c9a1619SFlorian Wechsung     lenadjncy += temp;
34448c9a1619SFlorian Wechsung     ierr = MatRestoreRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);CHKERRQ(ierr);
34458c9a1619SFlorian Wechsung   }
34468c9a1619SFlorian Wechsung   ierr = PetscMalloc1(lenadjncy, &adjncy);CHKERRQ(ierr);
34477407ba93SFlorian Wechsung   lenxadj = 2 + numNonExclusivelyOwned;
34480941debbSFlorian Wechsung   ierr = PetscMalloc1(lenxadj, &xadj);CHKERRQ(ierr);
34490941debbSFlorian Wechsung   xadj[0] = 0;
34508c9a1619SFlorian Wechsung   counter = 0;
34518c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
34522953a68cSFlorian Wechsung     PetscInt        temp=0;
34532953a68cSFlorian Wechsung     const PetscInt *cols;
34548c9a1619SFlorian Wechsung     ierr = MatGetRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);CHKERRQ(ierr);
3455580bdb30SBarry Smith     ierr = PetscArraycpy(&adjncy[counter], cols, temp);CHKERRQ(ierr);
34568c9a1619SFlorian Wechsung     counter += temp;
34570941debbSFlorian Wechsung     xadj[i+1] = counter;
34588c9a1619SFlorian Wechsung     ierr = MatRestoreRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);CHKERRQ(ierr);
34598c9a1619SFlorian Wechsung   }
34608c9a1619SFlorian Wechsung 
3461cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(cumSumVertices[rank+1]-cumSumVertices[rank], &part);CHKERRQ(ierr);
346241525646SFlorian Wechsung   ierr = PetscMalloc1(ncon*(1 + numNonExclusivelyOwned), &vtxwgt);CHKERRQ(ierr);
346341525646SFlorian Wechsung   vtxwgt[0] = numExclusivelyOwned;
346441525646SFlorian Wechsung   if (ncon>1) vtxwgt[1] = 1;
346541525646SFlorian Wechsung   for (i=0; i<numNonExclusivelyOwned; i++) {
346641525646SFlorian Wechsung     vtxwgt[ncon*(i+1)] = 1;
346741525646SFlorian Wechsung     if (ncon>1) vtxwgt[ncon*(i+1)+1] = 0;
346841525646SFlorian Wechsung   }
34698c9a1619SFlorian Wechsung 
34705dc86ac1SFlorian Wechsung   if (viewer) {
34717d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %D on interface of mesh distribution.\n", entityDepth);CHKERRQ(ierr);
34727d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %D\n", cumSumVertices[size]);CHKERRQ(ierr);
347312617df9SFlorian Wechsung   }
347441525646SFlorian Wechsung   if (parallel) {
34755a30b08bSFlorian Wechsung     ierr = PetscMalloc1(4, &options);CHKERRQ(ierr);
34765a30b08bSFlorian Wechsung     options[0] = 1;
34775a30b08bSFlorian Wechsung     options[1] = 0; /* Verbosity */
34785a30b08bSFlorian Wechsung     options[2] = 0; /* Seed */
34795a30b08bSFlorian Wechsung     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
34805dc86ac1SFlorian Wechsung     if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n");CHKERRQ(ierr); }
34818c9a1619SFlorian Wechsung     if (useInitialGuess) {
34825dc86ac1SFlorian Wechsung       if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n");CHKERRQ(ierr); }
34838c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_RefineKway");
34845dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_RefineKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
348506b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
34868c9a1619SFlorian Wechsung       PetscStackPop;
34878c9a1619SFlorian Wechsung     } else {
34888c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_PartKway");
34895dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_PartKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
34908c9a1619SFlorian Wechsung       PetscStackPop;
349106b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
34928c9a1619SFlorian Wechsung     }
3493ef74bcceSFlorian Wechsung     ierr = PetscFree(options);CHKERRQ(ierr);
349441525646SFlorian Wechsung   } else {
34955dc86ac1SFlorian Wechsung     if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n");CHKERRQ(ierr); }
349641525646SFlorian Wechsung     Mat As;
349741525646SFlorian Wechsung     PetscInt numRows;
349841525646SFlorian Wechsung     PetscInt *partGlobal;
349941525646SFlorian Wechsung     ierr = MatCreateRedundantMatrix(A, size, MPI_COMM_NULL, MAT_INITIAL_MATRIX, &As);CHKERRQ(ierr);
3500cb87ef4cSFlorian Wechsung 
350141525646SFlorian Wechsung     PetscInt *numExclusivelyOwnedAll;
350241525646SFlorian Wechsung     ierr = PetscMalloc1(size, &numExclusivelyOwnedAll);CHKERRQ(ierr);
350341525646SFlorian Wechsung     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
35042953a68cSFlorian Wechsung     ierr = MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,numExclusivelyOwnedAll,1,MPIU_INT,comm);CHKERRQ(ierr);
3505cb87ef4cSFlorian Wechsung 
350641525646SFlorian Wechsung     ierr = MatGetSize(As, &numRows, NULL);CHKERRQ(ierr);
350741525646SFlorian Wechsung     ierr = PetscMalloc1(numRows, &partGlobal);CHKERRQ(ierr);
35085dc86ac1SFlorian Wechsung     if (!rank) {
350941525646SFlorian Wechsung       PetscInt *adjncy_g, *xadj_g, *vtxwgt_g;
351041525646SFlorian Wechsung       lenadjncy = 0;
351141525646SFlorian Wechsung 
351241525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
351341525646SFlorian Wechsung         PetscInt temp=0;
351441525646SFlorian Wechsung         ierr = MatGetRow(As, i, &temp, NULL, NULL);CHKERRQ(ierr);
351541525646SFlorian Wechsung         lenadjncy += temp;
351641525646SFlorian Wechsung         ierr = MatRestoreRow(As, i, &temp, NULL, NULL);CHKERRQ(ierr);
351741525646SFlorian Wechsung       }
351841525646SFlorian Wechsung       ierr = PetscMalloc1(lenadjncy, &adjncy_g);CHKERRQ(ierr);
351941525646SFlorian Wechsung       lenxadj = 1 + numRows;
352041525646SFlorian Wechsung       ierr = PetscMalloc1(lenxadj, &xadj_g);CHKERRQ(ierr);
352141525646SFlorian Wechsung       xadj_g[0] = 0;
352241525646SFlorian Wechsung       counter = 0;
352341525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
35242953a68cSFlorian Wechsung         PetscInt        temp=0;
35252953a68cSFlorian Wechsung         const PetscInt *cols;
352641525646SFlorian Wechsung         ierr = MatGetRow(As, i, &temp, &cols, NULL);CHKERRQ(ierr);
3527580bdb30SBarry Smith         ierr = PetscArraycpy(&adjncy_g[counter], cols, temp);CHKERRQ(ierr);
352841525646SFlorian Wechsung         counter += temp;
352941525646SFlorian Wechsung         xadj_g[i+1] = counter;
353041525646SFlorian Wechsung         ierr = MatRestoreRow(As, i, &temp, &cols, NULL);CHKERRQ(ierr);
353141525646SFlorian Wechsung       }
353241525646SFlorian Wechsung       ierr = PetscMalloc1(2*numRows, &vtxwgt_g);CHKERRQ(ierr);
353341525646SFlorian Wechsung       for (i=0; i<size; i++){
353441525646SFlorian Wechsung         vtxwgt_g[ncon*cumSumVertices[i]] = numExclusivelyOwnedAll[i];
353541525646SFlorian Wechsung         if (ncon>1) vtxwgt_g[ncon*cumSumVertices[i]+1] = 1;
353641525646SFlorian Wechsung         for (j=cumSumVertices[i]+1; j<cumSumVertices[i+1]; j++) {
353741525646SFlorian Wechsung           vtxwgt_g[ncon*j] = 1;
353841525646SFlorian Wechsung           if (ncon>1) vtxwgt_g[2*j+1] = 0;
353941525646SFlorian Wechsung         }
354041525646SFlorian Wechsung       }
354141525646SFlorian Wechsung       ierr = PetscMalloc1(64, &options);CHKERRQ(ierr);
354241525646SFlorian Wechsung       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
354306b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
354441525646SFlorian Wechsung       options[METIS_OPTION_CONTIG] = 1;
354541525646SFlorian Wechsung       PetscStackPush("METIS_PartGraphKway");
354606b3913eSFlorian Wechsung       ierr = METIS_PartGraphKway(&numRows, &ncon, xadj_g, adjncy_g, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
354741525646SFlorian Wechsung       PetscStackPop;
354806b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
3549ef74bcceSFlorian Wechsung       ierr = PetscFree(options);CHKERRQ(ierr);
355041525646SFlorian Wechsung       ierr = PetscFree(xadj_g);CHKERRQ(ierr);
355141525646SFlorian Wechsung       ierr = PetscFree(adjncy_g);CHKERRQ(ierr);
355241525646SFlorian Wechsung       ierr = PetscFree(vtxwgt_g);CHKERRQ(ierr);
355341525646SFlorian Wechsung     }
355441525646SFlorian Wechsung     ierr = PetscFree(numExclusivelyOwnedAll);CHKERRQ(ierr);
355541525646SFlorian Wechsung 
35565dc86ac1SFlorian Wechsung     /* Now scatter the parts array. */
35575dc86ac1SFlorian Wechsung     {
355881a13b52SFlorian Wechsung       PetscMPIInt *counts, *mpiCumSumVertices;
35595dc86ac1SFlorian Wechsung       ierr = PetscMalloc1(size, &counts);CHKERRQ(ierr);
356081a13b52SFlorian Wechsung       ierr = PetscMalloc1(size+1, &mpiCumSumVertices);CHKERRQ(ierr);
35615dc86ac1SFlorian Wechsung       for(i=0; i<size; i++) {
356281a13b52SFlorian Wechsung         ierr = PetscMPIIntCast(cumSumVertices[i+1] - cumSumVertices[i], &(counts[i]));CHKERRQ(ierr);
356341525646SFlorian Wechsung       }
356481a13b52SFlorian Wechsung       for(i=0; i<=size; i++) {
356581a13b52SFlorian Wechsung         ierr = PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i]));CHKERRQ(ierr);
356681a13b52SFlorian Wechsung       }
356781a13b52SFlorian Wechsung       ierr = MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm);CHKERRQ(ierr);
35685dc86ac1SFlorian Wechsung       ierr = PetscFree(counts);CHKERRQ(ierr);
356981a13b52SFlorian Wechsung       ierr = PetscFree(mpiCumSumVertices);CHKERRQ(ierr);
35705dc86ac1SFlorian Wechsung     }
35715dc86ac1SFlorian Wechsung 
357241525646SFlorian Wechsung     ierr = PetscFree(partGlobal);CHKERRQ(ierr);
35732953a68cSFlorian Wechsung     ierr = MatDestroy(&As);CHKERRQ(ierr);
357441525646SFlorian Wechsung   }
3575cb87ef4cSFlorian Wechsung 
35762953a68cSFlorian Wechsung   ierr = MatDestroy(&A);CHKERRQ(ierr);
3577cb87ef4cSFlorian Wechsung   ierr = PetscFree(ubvec);CHKERRQ(ierr);
3578cb87ef4cSFlorian Wechsung   ierr = PetscFree(tpwgts);CHKERRQ(ierr);
3579cb87ef4cSFlorian Wechsung 
3580cb87ef4cSFlorian Wechsung   /* Now rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
3581cb87ef4cSFlorian Wechsung 
3582cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(size, &firstVertices);CHKERRQ(ierr);
3583cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(size, &renumbering);CHKERRQ(ierr);
3584cb87ef4cSFlorian Wechsung   firstVertices[rank] = part[0];
35852953a68cSFlorian Wechsung   ierr = MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,firstVertices,1,MPIU_INT,comm);CHKERRQ(ierr);
3586cb87ef4cSFlorian Wechsung   for (i=0; i<size; i++) {
3587cb87ef4cSFlorian Wechsung     renumbering[firstVertices[i]] = i;
3588cb87ef4cSFlorian Wechsung   }
3589cb87ef4cSFlorian Wechsung   for (i=0; i<cumSumVertices[rank+1]-cumSumVertices[rank]; i++) {
3590cb87ef4cSFlorian Wechsung     part[i] = renumbering[part[i]];
3591cb87ef4cSFlorian Wechsung   }
3592cb87ef4cSFlorian Wechsung   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
3593cb87ef4cSFlorian Wechsung   failed = (PetscInt)(part[0] != rank);
35942953a68cSFlorian Wechsung   ierr = MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
3595cb87ef4cSFlorian Wechsung 
35967f57c1a4SFlorian Wechsung   ierr = PetscFree(firstVertices);CHKERRQ(ierr);
35977f57c1a4SFlorian Wechsung   ierr = PetscFree(renumbering);CHKERRQ(ierr);
35987f57c1a4SFlorian Wechsung 
3599cb87ef4cSFlorian Wechsung   if (failedGlobal > 0) {
36007f57c1a4SFlorian Wechsung     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
36017f57c1a4SFlorian Wechsung     ierr = PetscFree(xadj);CHKERRQ(ierr);
36027f57c1a4SFlorian Wechsung     ierr = PetscFree(adjncy);CHKERRQ(ierr);
36037f57c1a4SFlorian Wechsung     ierr = PetscFree(vtxwgt);CHKERRQ(ierr);
36047f57c1a4SFlorian Wechsung     ierr = PetscFree(toBalance);CHKERRQ(ierr);
36057f57c1a4SFlorian Wechsung     ierr = PetscFree(isLeaf);CHKERRQ(ierr);
36067f57c1a4SFlorian Wechsung     ierr = PetscFree(isNonExclusivelyOwned);CHKERRQ(ierr);
36077f57c1a4SFlorian Wechsung     ierr = PetscFree(isExclusivelyOwned);CHKERRQ(ierr);
36087f57c1a4SFlorian Wechsung     ierr = PetscFree(part);CHKERRQ(ierr);
36097f57c1a4SFlorian Wechsung     if (viewer) {
361006b3913eSFlorian Wechsung       ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
361106b3913eSFlorian Wechsung       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
36127f57c1a4SFlorian Wechsung     }
36137f57c1a4SFlorian Wechsung     ierr = PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
36148b879b41SFlorian Wechsung     PetscFunctionReturn(0);
3615cb87ef4cSFlorian Wechsung   }
3616cb87ef4cSFlorian Wechsung 
36177407ba93SFlorian Wechsung   /*Let's check how well we did distributing points*/
36185dc86ac1SFlorian Wechsung   if (viewer) {
36197d197802SFlorian 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);
3620125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Initial.     ");CHKERRQ(ierr);
3621125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, NULL, viewer);CHKERRQ(ierr);
3622125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Rebalanced.  ");CHKERRQ(ierr);
3623125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);CHKERRQ(ierr);
36247407ba93SFlorian Wechsung   }
36257407ba93SFlorian Wechsung 
3626cb87ef4cSFlorian Wechsung   /* Now check that every vertex is owned by a process that it is actually connected to. */
362741525646SFlorian Wechsung   for (i=1; i<=numNonExclusivelyOwned; i++) {
3628cb87ef4cSFlorian Wechsung     PetscInt loc = 0;
362941525646SFlorian Wechsung     ierr = PetscFindInt(cumSumVertices[part[i]], xadj[i+1]-xadj[i], &adjncy[xadj[i]], &loc);CHKERRQ(ierr);
36307407ba93SFlorian Wechsung     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
3631cb87ef4cSFlorian Wechsung     if (loc<0) {
363241525646SFlorian Wechsung       part[i] = rank;
3633cb87ef4cSFlorian Wechsung     }
3634cb87ef4cSFlorian Wechsung   }
3635cb87ef4cSFlorian Wechsung 
36367407ba93SFlorian Wechsung   /* Let's see how significant the influences of the previous fixing up step was.*/
36375dc86ac1SFlorian Wechsung   if (viewer) {
3638125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "After.       ");CHKERRQ(ierr);
3639125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);CHKERRQ(ierr);
36407407ba93SFlorian Wechsung   }
36417407ba93SFlorian Wechsung 
36425dc86ac1SFlorian Wechsung   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3643cb87ef4cSFlorian Wechsung   ierr = PetscFree(xadj);CHKERRQ(ierr);
3644cb87ef4cSFlorian Wechsung   ierr = PetscFree(adjncy);CHKERRQ(ierr);
364541525646SFlorian Wechsung   ierr = PetscFree(vtxwgt);CHKERRQ(ierr);
3646cb87ef4cSFlorian Wechsung 
36477f57c1a4SFlorian Wechsung   /* Almost done, now rewrite the SF to reflect the new ownership. */
3648cf818975SFlorian Wechsung   {
36497f57c1a4SFlorian Wechsung     PetscInt *pointsToRewrite;
365006b3913eSFlorian Wechsung     ierr = PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite);CHKERRQ(ierr);
36517f57c1a4SFlorian Wechsung     counter = 0;
3652cb87ef4cSFlorian Wechsung     for(i=0; i<pEnd-pStart; i++) {
3653cb87ef4cSFlorian Wechsung       if (toBalance[i]) {
3654cb87ef4cSFlorian Wechsung         if (isNonExclusivelyOwned[i]) {
36557f57c1a4SFlorian Wechsung           pointsToRewrite[counter] = i + pStart;
3656cb87ef4cSFlorian Wechsung           counter++;
3657cb87ef4cSFlorian Wechsung         }
3658cb87ef4cSFlorian Wechsung       }
3659cb87ef4cSFlorian Wechsung     }
36607f57c1a4SFlorian Wechsung     ierr = DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part+1, degrees);CHKERRQ(ierr);
36617f57c1a4SFlorian Wechsung     ierr = PetscFree(pointsToRewrite);CHKERRQ(ierr);
3662cf818975SFlorian Wechsung   }
3663cb87ef4cSFlorian Wechsung 
3664cb87ef4cSFlorian Wechsung   ierr = PetscFree(toBalance);CHKERRQ(ierr);
3665cb87ef4cSFlorian Wechsung   ierr = PetscFree(isLeaf);CHKERRQ(ierr);
3666cf818975SFlorian Wechsung   ierr = PetscFree(isNonExclusivelyOwned);CHKERRQ(ierr);
3667cf818975SFlorian Wechsung   ierr = PetscFree(isExclusivelyOwned);CHKERRQ(ierr);
36687f57c1a4SFlorian Wechsung   ierr = PetscFree(part);CHKERRQ(ierr);
36695dc86ac1SFlorian Wechsung   if (viewer) {
367006b3913eSFlorian Wechsung     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
367106b3913eSFlorian Wechsung     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
36727d197802SFlorian Wechsung   }
36738b879b41SFlorian Wechsung   if (success) *success = PETSC_TRUE;
367441525646SFlorian Wechsung   ierr = PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
3675240408d3SFlorian Wechsung #else
36765f441e9bSFlorian Wechsung   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
367741525646SFlorian Wechsung #endif
3678cb87ef4cSFlorian Wechsung   PetscFunctionReturn(0);
3679cb87ef4cSFlorian Wechsung }
3680