xref: /petsc/src/dm/impls/plex/plexpartition.c (revision 4e468a9381cf607c8ea4905e3c5366a5e229fb72)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2e8f14785SLisandro Dalcin #include <petsc/private/hashseti.h>
370034214SMatthew G. Knepley 
477623264SMatthew G. Knepley PetscClassId PETSCPARTITIONER_CLASSID = 0;
577623264SMatthew G. Knepley 
677623264SMatthew G. Knepley PetscFunctionList PetscPartitionerList              = NULL;
777623264SMatthew G. Knepley PetscBool         PetscPartitionerRegisterAllCalled = PETSC_FALSE;
877623264SMatthew G. Knepley 
977623264SMatthew G. Knepley PetscBool ChacoPartitionercite = PETSC_FALSE;
1077623264SMatthew G. Knepley const char ChacoPartitionerCitation[] = "@inproceedings{Chaco95,\n"
1177623264SMatthew G. Knepley                                "  author    = {Bruce Hendrickson and Robert Leland},\n"
1277623264SMatthew G. Knepley                                "  title     = {A multilevel algorithm for partitioning graphs},\n"
1377623264SMatthew G. Knepley                                "  booktitle = {Supercomputing '95: Proceedings of the 1995 ACM/IEEE Conference on Supercomputing (CDROM)},"
1477623264SMatthew G. Knepley                                "  isbn      = {0-89791-816-9},\n"
1577623264SMatthew G. Knepley                                "  pages     = {28},\n"
1677623264SMatthew G. Knepley                                "  doi       = {http://doi.acm.org/10.1145/224170.224228},\n"
1777623264SMatthew G. Knepley                                "  publisher = {ACM Press},\n"
1877623264SMatthew G. Knepley                                "  address   = {New York},\n"
1977623264SMatthew G. Knepley                                "  year      = {1995}\n}\n";
2077623264SMatthew G. Knepley 
2177623264SMatthew G. Knepley PetscBool ParMetisPartitionercite = PETSC_FALSE;
2277623264SMatthew G. Knepley const char ParMetisPartitionerCitation[] = "@article{KarypisKumar98,\n"
2377623264SMatthew G. Knepley                                "  author  = {George Karypis and Vipin Kumar},\n"
2477623264SMatthew G. Knepley                                "  title   = {A Parallel Algorithm for Multilevel Graph Partitioning and Sparse Matrix Ordering},\n"
2577623264SMatthew G. Knepley                                "  journal = {Journal of Parallel and Distributed Computing},\n"
2677623264SMatthew G. Knepley                                "  volume  = {48},\n"
2777623264SMatthew G. Knepley                                "  pages   = {71--85},\n"
2877623264SMatthew G. Knepley                                "  year    = {1998}\n}\n";
2977623264SMatthew G. Knepley 
300134a67bSLisandro Dalcin PETSC_STATIC_INLINE PetscInt DMPlex_GlobalID(PetscInt point) { return point >= 0 ? point : -(point+1); }
310134a67bSLisandro Dalcin 
32532c4e7dSMichael Lange /*@C
33532c4e7dSMichael Lange   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
34532c4e7dSMichael Lange 
35532c4e7dSMichael Lange   Input Parameters:
36532c4e7dSMichael Lange + dm      - The mesh DM dm
37532c4e7dSMichael Lange - height  - Height of the strata from which to construct the graph
38532c4e7dSMichael Lange 
39532c4e7dSMichael Lange   Output Parameter:
40532c4e7dSMichael Lange + numVertices     - Number of vertices in the graph
413fa7752dSToby Isaac . offsets         - Point offsets in the graph
423fa7752dSToby Isaac . adjacency       - Point connectivity in the graph
433fa7752dSToby Isaac - 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.
44532c4e7dSMichael Lange 
45b0441da4SMatthew G. Knepley   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
46532c4e7dSMichael Lange   representation on the mesh.
47532c4e7dSMichael Lange 
48532c4e7dSMichael Lange   Level: developer
49532c4e7dSMichael Lange 
50b0441da4SMatthew G. Knepley .seealso: PetscPartitionerGetType(), PetscPartitionerCreate(), DMSetAdjacency()
51532c4e7dSMichael Lange @*/
523fa7752dSToby Isaac PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
53532c4e7dSMichael Lange {
54ffbd6163SMatthew G. Knepley   PetscInt       dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
55389e55d8SMichael Lange   PetscInt      *adj = NULL, *vOffsets = NULL, *graph = NULL;
568cfe4c1fSMichael Lange   IS             cellNumbering;
578cfe4c1fSMichael Lange   const PetscInt *cellNum;
58532c4e7dSMichael Lange   PetscBool      useCone, useClosure;
59532c4e7dSMichael Lange   PetscSection   section;
60532c4e7dSMichael Lange   PetscSegBuffer adjBuffer;
618cfe4c1fSMichael Lange   PetscSF        sfPoint;
628f4e72b9SMatthew G. Knepley   PetscInt       *adjCells = NULL, *remoteCells = NULL;
638f4e72b9SMatthew G. Knepley   const PetscInt *local;
648f4e72b9SMatthew G. Knepley   PetscInt       nroots, nleaves, l;
65532c4e7dSMichael Lange   PetscMPIInt    rank;
66532c4e7dSMichael Lange   PetscErrorCode ierr;
67532c4e7dSMichael Lange 
68532c4e7dSMichael Lange   PetscFunctionBegin;
69532c4e7dSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
70ffbd6163SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
71ffbd6163SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
72ffbd6163SMatthew G. Knepley   if (dim != depth) {
73ffbd6163SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
74ffbd6163SMatthew G. Knepley     ierr = DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);CHKERRQ(ierr);
75ffbd6163SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
76ffbd6163SMatthew G. Knepley     if (globalNumbering) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);CHKERRQ(ierr);}
77ffbd6163SMatthew G. Knepley     /* Different behavior for empty graphs */
78ffbd6163SMatthew G. Knepley     if (!*numVertices) {
79ffbd6163SMatthew G. Knepley       ierr = PetscMalloc1(1, offsets);CHKERRQ(ierr);
80ffbd6163SMatthew G. Knepley       (*offsets)[0] = 0;
81ffbd6163SMatthew G. Knepley     }
82ffbd6163SMatthew G. Knepley     /* Broken in parallel */
83ffbd6163SMatthew G. Knepley     if (rank && *numVertices) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
84ffbd6163SMatthew G. Knepley     PetscFunctionReturn(0);
85ffbd6163SMatthew G. Knepley   }
868cfe4c1fSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
870134a67bSLisandro Dalcin   ierr = DMPlexGetHeightStratum(dm, height, &pStart, &pEnd);CHKERRQ(ierr);
88532c4e7dSMichael Lange   /* Build adjacency graph via a section/segbuffer */
89532c4e7dSMichael Lange   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &section);CHKERRQ(ierr);
90532c4e7dSMichael Lange   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
91532c4e7dSMichael Lange   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&adjBuffer);CHKERRQ(ierr);
92532c4e7dSMichael Lange   /* Always use FVM adjacency to create partitioner graph */
93b0441da4SMatthew G. Knepley   ierr = DMGetBasicAdjacency(dm, &useCone, &useClosure);CHKERRQ(ierr);
94b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE);CHKERRQ(ierr);
950134a67bSLisandro Dalcin   ierr = DMPlexCreateNumbering_Internal(dm, pStart, pEnd, 0, NULL, sfPoint, &cellNumbering);CHKERRQ(ierr);
963fa7752dSToby Isaac   if (globalNumbering) {
973fa7752dSToby Isaac     ierr = PetscObjectReference((PetscObject)cellNumbering);CHKERRQ(ierr);
983fa7752dSToby Isaac     *globalNumbering = cellNumbering;
993fa7752dSToby Isaac   }
1008cfe4c1fSMichael Lange   ierr = ISGetIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
1018f4e72b9SMatthew G. Knepley   /* For all boundary faces (including faces adjacent to a ghost cell), record the local cell in adjCells
1028f4e72b9SMatthew G. Knepley      Broadcast adjCells to remoteCells (to get cells from roots) and Reduce adjCells to remoteCells (to get cells from leaves)
1038f4e72b9SMatthew G. Knepley    */
1040134a67bSLisandro Dalcin   ierr = PetscSFGetGraph(sfPoint, &nroots, &nleaves, &local, NULL);CHKERRQ(ierr);
1058f4e72b9SMatthew G. Knepley   if (nroots >= 0) {
1068f4e72b9SMatthew G. Knepley     PetscInt fStart, fEnd, f;
1078f4e72b9SMatthew G. Knepley 
1088f4e72b9SMatthew G. Knepley     ierr = PetscCalloc2(nroots, &adjCells, nroots, &remoteCells);CHKERRQ(ierr);
1090134a67bSLisandro Dalcin     ierr = DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);CHKERRQ(ierr);
1108f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) adjCells[l] = -3;
1118f4e72b9SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
1128f4e72b9SMatthew G. Knepley       const PetscInt *support;
1138f4e72b9SMatthew G. Knepley       PetscInt        supportSize;
1148f4e72b9SMatthew G. Knepley 
1158f4e72b9SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1168f4e72b9SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1170134a67bSLisandro Dalcin       if (supportSize == 1) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
1188f4e72b9SMatthew G. Knepley       else if (supportSize == 2) {
1198f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
1200134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1]]);
1218f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
1220134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
1230134a67bSLisandro Dalcin       }
1240134a67bSLisandro Dalcin       /* Handle non-conforming meshes */
1250134a67bSLisandro Dalcin       if (supportSize > 2) {
1260134a67bSLisandro Dalcin         PetscInt        numChildren, i;
1270134a67bSLisandro Dalcin         const PetscInt *children;
1280134a67bSLisandro Dalcin 
1290134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, f, &numChildren, &children);CHKERRQ(ierr);
1300134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1310134a67bSLisandro Dalcin           const PetscInt child = children[i];
1320134a67bSLisandro Dalcin           if (fStart <= child && child < fEnd) {
1330134a67bSLisandro Dalcin             ierr = DMPlexGetSupport(dm, child, &support);CHKERRQ(ierr);
1340134a67bSLisandro Dalcin             ierr = DMPlexGetSupportSize(dm, child, &supportSize);CHKERRQ(ierr);
1350134a67bSLisandro Dalcin             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
1360134a67bSLisandro Dalcin             else if (supportSize == 2) {
1370134a67bSLisandro Dalcin               ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
1380134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1]]);
1390134a67bSLisandro Dalcin               ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
1400134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
1410134a67bSLisandro Dalcin             }
1420134a67bSLisandro Dalcin           }
1430134a67bSLisandro Dalcin         }
1448f4e72b9SMatthew G. Knepley       }
1458f4e72b9SMatthew G. Knepley     }
1468f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) remoteCells[l] = -1;
1478f4e72b9SMatthew G. Knepley     ierr = PetscSFBcastBegin(dm->sf, MPIU_INT, adjCells, remoteCells);CHKERRQ(ierr);
1488f4e72b9SMatthew G. Knepley     ierr = PetscSFBcastEnd(dm->sf, MPIU_INT, adjCells, remoteCells);CHKERRQ(ierr);
1498f4e72b9SMatthew G. Knepley     ierr = PetscSFReduceBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);CHKERRQ(ierr);
1508f4e72b9SMatthew G. Knepley     ierr = PetscSFReduceEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);CHKERRQ(ierr);
1518f4e72b9SMatthew G. Knepley   }
1528f4e72b9SMatthew G. Knepley   /* Combine local and global adjacencies */
1538cfe4c1fSMichael Lange   for (*numVertices = 0, p = pStart; p < pEnd; p++) {
1548cfe4c1fSMichael Lange     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
1558cfe4c1fSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
1568f4e72b9SMatthew G. Knepley     /* Add remote cells */
1578f4e72b9SMatthew G. Knepley     if (remoteCells) {
1580134a67bSLisandro Dalcin       const PetscInt gp = DMPlex_GlobalID(cellNum[p]);
1590134a67bSLisandro Dalcin       PetscInt       coneSize, numChildren, c, i;
1600134a67bSLisandro Dalcin       const PetscInt *cone, *children;
1610134a67bSLisandro Dalcin 
1628f4e72b9SMatthew G. Knepley       ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1638f4e72b9SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1648f4e72b9SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
1650134a67bSLisandro Dalcin         const PetscInt point = cone[c];
1660134a67bSLisandro Dalcin         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
1678f4e72b9SMatthew G. Knepley           PetscInt *PETSC_RESTRICT pBuf;
1688f4e72b9SMatthew G. Knepley           ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
1698f4e72b9SMatthew G. Knepley           ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1700134a67bSLisandro Dalcin           *pBuf = remoteCells[point];
1710134a67bSLisandro Dalcin         }
1720134a67bSLisandro Dalcin         /* Handle non-conforming meshes */
1730134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, point, &numChildren, &children);CHKERRQ(ierr);
1740134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1750134a67bSLisandro Dalcin           const PetscInt child = children[i];
1760134a67bSLisandro Dalcin           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
1770134a67bSLisandro Dalcin             PetscInt *PETSC_RESTRICT pBuf;
1780134a67bSLisandro Dalcin             ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
1790134a67bSLisandro Dalcin             ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1800134a67bSLisandro Dalcin             *pBuf = remoteCells[child];
1810134a67bSLisandro Dalcin           }
1828f4e72b9SMatthew G. Knepley         }
1838f4e72b9SMatthew G. Knepley       }
1848f4e72b9SMatthew G. Knepley     }
1858f4e72b9SMatthew G. Knepley     /* Add local cells */
186532c4e7dSMichael Lange     adjSize = PETSC_DETERMINE;
187532c4e7dSMichael Lange     ierr = DMPlexGetAdjacency(dm, p, &adjSize, &adj);CHKERRQ(ierr);
188532c4e7dSMichael Lange     for (a = 0; a < adjSize; ++a) {
189532c4e7dSMichael Lange       const PetscInt point = adj[a];
190532c4e7dSMichael Lange       if (point != p && pStart <= point && point < pEnd) {
191532c4e7dSMichael Lange         PetscInt *PETSC_RESTRICT pBuf;
192532c4e7dSMichael Lange         ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
193532c4e7dSMichael Lange         ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1940134a67bSLisandro Dalcin         *pBuf = DMPlex_GlobalID(cellNum[point]);
195532c4e7dSMichael Lange       }
196532c4e7dSMichael Lange     }
1978cfe4c1fSMichael Lange     (*numVertices)++;
198532c4e7dSMichael Lange   }
199*4e468a93SLisandro Dalcin   ierr = PetscFree(adj);CHKERRQ(ierr);
2008f4e72b9SMatthew G. Knepley   ierr = PetscFree2(adjCells, remoteCells);CHKERRQ(ierr);
201b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, useCone, useClosure);CHKERRQ(ierr);
202*4e468a93SLisandro Dalcin 
203532c4e7dSMichael Lange   /* Derive CSR graph from section/segbuffer */
204532c4e7dSMichael Lange   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
205532c4e7dSMichael Lange   ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
206389e55d8SMichael Lange   ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
20743f7d02bSMichael Lange   for (idx = 0, p = pStart; p < pEnd; p++) {
20843f7d02bSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
20943f7d02bSMichael Lange     ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
21043f7d02bSMichael Lange   }
211532c4e7dSMichael Lange   vOffsets[*numVertices] = size;
212389e55d8SMichael Lange   ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
213*4e468a93SLisandro Dalcin 
214*4e468a93SLisandro Dalcin   if (nroots >= 0) {
215*4e468a93SLisandro Dalcin     /* Filter out duplicate edges using section/segbuffer */
216*4e468a93SLisandro Dalcin     ierr = PetscSectionReset(section);CHKERRQ(ierr);
217*4e468a93SLisandro Dalcin     ierr = PetscSectionSetChart(section, 0, *numVertices);CHKERRQ(ierr);
218*4e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
219*4e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
220*4e468a93SLisandro Dalcin       PetscInt numEdges = end-start, *PETSC_RESTRICT edges;
221*4e468a93SLisandro Dalcin       ierr = PetscSortRemoveDupsInt(&numEdges, &graph[start]);CHKERRQ(ierr);
222*4e468a93SLisandro Dalcin       ierr = PetscSectionSetDof(section, p, numEdges);CHKERRQ(ierr);
223*4e468a93SLisandro Dalcin       ierr = PetscSegBufferGetInts(adjBuffer, numEdges, &edges);CHKERRQ(ierr);
224*4e468a93SLisandro Dalcin       ierr = PetscMemcpy(edges, &graph[start], numEdges*sizeof(*edges));CHKERRQ(ierr);
225*4e468a93SLisandro Dalcin     }
226*4e468a93SLisandro Dalcin     ierr = PetscFree(vOffsets);CHKERRQ(ierr);
227*4e468a93SLisandro Dalcin     ierr = PetscFree(graph);CHKERRQ(ierr);
228*4e468a93SLisandro Dalcin     /* Derive CSR graph from section/segbuffer */
229*4e468a93SLisandro Dalcin     ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
230*4e468a93SLisandro Dalcin     ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
231*4e468a93SLisandro Dalcin     ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
232*4e468a93SLisandro Dalcin     for (idx = 0, p = 0; p < *numVertices; p++) {
233*4e468a93SLisandro Dalcin       ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
234*4e468a93SLisandro Dalcin     }
235*4e468a93SLisandro Dalcin     vOffsets[*numVertices] = size;
236*4e468a93SLisandro Dalcin     ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
237*4e468a93SLisandro Dalcin   } else {
238*4e468a93SLisandro Dalcin     /* Sort adjacencies (not strictly necessary) */
239*4e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
240*4e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
241*4e468a93SLisandro Dalcin       ierr = PetscSortInt(end-start, &graph[start]);CHKERRQ(ierr);
242*4e468a93SLisandro Dalcin     }
243*4e468a93SLisandro Dalcin   }
244*4e468a93SLisandro Dalcin 
245*4e468a93SLisandro Dalcin   if (offsets) *offsets = vOffsets;
246389e55d8SMichael Lange   if (adjacency) *adjacency = graph;
247*4e468a93SLisandro Dalcin 
248532c4e7dSMichael Lange   /* Cleanup */
249532c4e7dSMichael Lange   ierr = PetscSegBufferDestroy(&adjBuffer);CHKERRQ(ierr);
250532c4e7dSMichael Lange   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
251*4e468a93SLisandro Dalcin   ierr = ISRestoreIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
252*4e468a93SLisandro Dalcin   ierr = ISDestroy(&cellNumbering);CHKERRQ(ierr);
253532c4e7dSMichael Lange   PetscFunctionReturn(0);
254532c4e7dSMichael Lange }
255532c4e7dSMichael Lange 
256d5577e40SMatthew G. Knepley /*@C
257d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
258d5577e40SMatthew G. Knepley 
259d5577e40SMatthew G. Knepley   Collective
260d5577e40SMatthew G. Knepley 
261d5577e40SMatthew G. Knepley   Input Arguments:
262d5577e40SMatthew G. Knepley + dm - The DMPlex
263d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
264d5577e40SMatthew G. Knepley 
265d5577e40SMatthew G. Knepley   Output Arguments:
266d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
267d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
268d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
269d5577e40SMatthew G. Knepley 
270d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
271d5577e40SMatthew G. Knepley 
272d5577e40SMatthew G. Knepley   Level: advanced
273d5577e40SMatthew G. Knepley 
274d5577e40SMatthew G. Knepley .seealso: DMPlexCreate()
275d5577e40SMatthew G. Knepley @*/
27670034214SMatthew G. Knepley PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
27770034214SMatthew G. Knepley {
27870034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
27970034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
28070034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
28170034214SMatthew G. Knepley   PetscInt      *off, *adj;
28270034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
28370034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
28470034214SMatthew G. Knepley   PetscErrorCode ierr;
28570034214SMatthew G. Knepley 
28670034214SMatthew G. Knepley   PetscFunctionBegin;
28770034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
288c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
28970034214SMatthew G. Knepley   cellDim = dim - cellHeight;
29070034214SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
29170034214SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
29270034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
29370034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
29470034214SMatthew G. Knepley     if (offsets)   *offsets   = NULL;
29570034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
29670034214SMatthew G. Knepley     PetscFunctionReturn(0);
29770034214SMatthew G. Knepley   }
29870034214SMatthew G. Knepley   numCells  = cEnd - cStart;
29970034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
30070034214SMatthew G. Knepley   if (dim == depth) {
30170034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
30270034214SMatthew G. Knepley 
30370034214SMatthew G. Knepley     ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
30470034214SMatthew G. Knepley     /* Count neighboring cells */
30570034214SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr);
30670034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
30770034214SMatthew G. Knepley       const PetscInt *support;
30870034214SMatthew G. Knepley       PetscInt        supportSize;
30970034214SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
31070034214SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
31170034214SMatthew G. Knepley       if (supportSize == 2) {
3129ffc88e4SToby Isaac         PetscInt numChildren;
3139ffc88e4SToby Isaac 
3149ffc88e4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
3159ffc88e4SToby Isaac         if (!numChildren) {
31670034214SMatthew G. Knepley           ++off[support[0]-cStart+1];
31770034214SMatthew G. Knepley           ++off[support[1]-cStart+1];
31870034214SMatthew G. Knepley         }
31970034214SMatthew G. Knepley       }
3209ffc88e4SToby Isaac     }
32170034214SMatthew G. Knepley     /* Prefix sum */
32270034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
32370034214SMatthew G. Knepley     if (adjacency) {
32470034214SMatthew G. Knepley       PetscInt *tmp;
32570034214SMatthew G. Knepley 
32670034214SMatthew G. Knepley       ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
327854ce69bSBarry Smith       ierr = PetscMalloc1(numCells+1, &tmp);CHKERRQ(ierr);
32870034214SMatthew G. Knepley       ierr = PetscMemcpy(tmp, off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
32970034214SMatthew G. Knepley       /* Get neighboring cells */
33070034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
33170034214SMatthew G. Knepley         const PetscInt *support;
33270034214SMatthew G. Knepley         PetscInt        supportSize;
33370034214SMatthew G. Knepley         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
33470034214SMatthew G. Knepley         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
33570034214SMatthew G. Knepley         if (supportSize == 2) {
3369ffc88e4SToby Isaac           PetscInt numChildren;
3379ffc88e4SToby Isaac 
3389ffc88e4SToby Isaac           ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
3399ffc88e4SToby Isaac           if (!numChildren) {
34070034214SMatthew G. Knepley             adj[tmp[support[0]-cStart]++] = support[1];
34170034214SMatthew G. Knepley             adj[tmp[support[1]-cStart]++] = support[0];
34270034214SMatthew G. Knepley           }
34370034214SMatthew G. Knepley         }
3449ffc88e4SToby Isaac       }
34570034214SMatthew G. Knepley #if defined(PETSC_USE_DEBUG)
34670034214SMatthew 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);
34770034214SMatthew G. Knepley #endif
34870034214SMatthew G. Knepley       ierr = PetscFree(tmp);CHKERRQ(ierr);
34970034214SMatthew G. Knepley     }
35070034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
35170034214SMatthew G. Knepley     if (offsets)   *offsets   = off;
35270034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
35370034214SMatthew G. Knepley     PetscFunctionReturn(0);
35470034214SMatthew G. Knepley   }
35570034214SMatthew G. Knepley   /* Setup face recognition */
35670034214SMatthew G. Knepley   if (faceDepth == 1) {
35770034214SMatthew 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 */
35870034214SMatthew G. Knepley 
35970034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
36070034214SMatthew G. Knepley       PetscInt corners;
36170034214SMatthew G. Knepley 
36270034214SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
36370034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
36470034214SMatthew G. Knepley         PetscInt nFV;
36570034214SMatthew G. Knepley 
36670034214SMatthew G. Knepley         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
36770034214SMatthew G. Knepley         cornersSeen[corners] = 1;
36870034214SMatthew G. Knepley 
36970034214SMatthew G. Knepley         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
37070034214SMatthew G. Knepley 
37170034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
37270034214SMatthew G. Knepley       }
37370034214SMatthew G. Knepley     }
37470034214SMatthew G. Knepley   }
37570034214SMatthew G. Knepley   ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
37670034214SMatthew G. Knepley   /* Count neighboring cells */
37770034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
37870034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
37970034214SMatthew G. Knepley 
3808b0b4c70SToby Isaac     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
38170034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
38270034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
38370034214SMatthew G. Knepley       PetscInt        cellPair[2];
38470034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
38570034214SMatthew G. Knepley       PetscInt        meetSize = 0;
38670034214SMatthew G. Knepley       const PetscInt *meet    = NULL;
38770034214SMatthew G. Knepley 
38870034214SMatthew G. Knepley       cellPair[0] = cell; cellPair[1] = neighborCells[n];
38970034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
39070034214SMatthew G. Knepley       if (!found) {
39170034214SMatthew G. Knepley         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
39270034214SMatthew G. Knepley         if (meetSize) {
39370034214SMatthew G. Knepley           PetscInt f;
39470034214SMatthew G. Knepley 
39570034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
39670034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
39770034214SMatthew G. Knepley               found = PETSC_TRUE;
39870034214SMatthew G. Knepley               break;
39970034214SMatthew G. Knepley             }
40070034214SMatthew G. Knepley           }
40170034214SMatthew G. Knepley         }
40270034214SMatthew G. Knepley         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
40370034214SMatthew G. Knepley       }
40470034214SMatthew G. Knepley       if (found) ++off[cell-cStart+1];
40570034214SMatthew G. Knepley     }
40670034214SMatthew G. Knepley   }
40770034214SMatthew G. Knepley   /* Prefix sum */
40870034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
40970034214SMatthew G. Knepley 
41070034214SMatthew G. Knepley   if (adjacency) {
41170034214SMatthew G. Knepley     ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
41270034214SMatthew G. Knepley     /* Get neighboring cells */
41370034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
41470034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
41570034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
41670034214SMatthew G. Knepley 
4178b0b4c70SToby Isaac       ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
41870034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
41970034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
42070034214SMatthew G. Knepley         PetscInt        cellPair[2];
42170034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
42270034214SMatthew G. Knepley         PetscInt        meetSize = 0;
42370034214SMatthew G. Knepley         const PetscInt *meet    = NULL;
42470034214SMatthew G. Knepley 
42570034214SMatthew G. Knepley         cellPair[0] = cell; cellPair[1] = neighborCells[n];
42670034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
42770034214SMatthew G. Knepley         if (!found) {
42870034214SMatthew G. Knepley           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
42970034214SMatthew G. Knepley           if (meetSize) {
43070034214SMatthew G. Knepley             PetscInt f;
43170034214SMatthew G. Knepley 
43270034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
43370034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
43470034214SMatthew G. Knepley                 found = PETSC_TRUE;
43570034214SMatthew G. Knepley                 break;
43670034214SMatthew G. Knepley               }
43770034214SMatthew G. Knepley             }
43870034214SMatthew G. Knepley           }
43970034214SMatthew G. Knepley           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
44070034214SMatthew G. Knepley         }
44170034214SMatthew G. Knepley         if (found) {
44270034214SMatthew G. Knepley           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
44370034214SMatthew G. Knepley           ++cellOffset;
44470034214SMatthew G. Knepley         }
44570034214SMatthew G. Knepley       }
44670034214SMatthew G. Knepley     }
44770034214SMatthew G. Knepley   }
44870034214SMatthew G. Knepley   ierr = PetscFree(neighborCells);CHKERRQ(ierr);
44970034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
45070034214SMatthew G. Knepley   if (offsets)   *offsets   = off;
45170034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
45270034214SMatthew G. Knepley   PetscFunctionReturn(0);
45370034214SMatthew G. Knepley }
45470034214SMatthew G. Knepley 
45577623264SMatthew G. Knepley /*@C
45677623264SMatthew G. Knepley   PetscPartitionerRegister - Adds a new PetscPartitioner implementation
45777623264SMatthew G. Knepley 
45877623264SMatthew G. Knepley   Not Collective
45977623264SMatthew G. Knepley 
46077623264SMatthew G. Knepley   Input Parameters:
46177623264SMatthew G. Knepley + name        - The name of a new user-defined creation routine
46277623264SMatthew G. Knepley - create_func - The creation routine itself
46377623264SMatthew G. Knepley 
46477623264SMatthew G. Knepley   Notes:
46577623264SMatthew G. Knepley   PetscPartitionerRegister() may be called multiple times to add several user-defined PetscPartitioners
46677623264SMatthew G. Knepley 
46777623264SMatthew G. Knepley   Sample usage:
46877623264SMatthew G. Knepley .vb
46977623264SMatthew G. Knepley     PetscPartitionerRegister("my_part", MyPetscPartitionerCreate);
47077623264SMatthew G. Knepley .ve
47177623264SMatthew G. Knepley 
47277623264SMatthew G. Knepley   Then, your PetscPartitioner type can be chosen with the procedural interface via
47377623264SMatthew G. Knepley .vb
47477623264SMatthew G. Knepley     PetscPartitionerCreate(MPI_Comm, PetscPartitioner *);
47577623264SMatthew G. Knepley     PetscPartitionerSetType(PetscPartitioner, "my_part");
47677623264SMatthew G. Knepley .ve
47777623264SMatthew G. Knepley    or at runtime via the option
47877623264SMatthew G. Knepley .vb
47977623264SMatthew G. Knepley     -petscpartitioner_type my_part
48077623264SMatthew G. Knepley .ve
48177623264SMatthew G. Knepley 
48277623264SMatthew G. Knepley   Level: advanced
48377623264SMatthew G. Knepley 
48477623264SMatthew G. Knepley .keywords: PetscPartitioner, register
48577623264SMatthew G. Knepley .seealso: PetscPartitionerRegisterAll(), PetscPartitionerRegisterDestroy()
48677623264SMatthew G. Knepley 
48777623264SMatthew G. Knepley @*/
48877623264SMatthew G. Knepley PetscErrorCode PetscPartitionerRegister(const char sname[], PetscErrorCode (*function)(PetscPartitioner))
48977623264SMatthew G. Knepley {
49077623264SMatthew G. Knepley   PetscErrorCode ierr;
49177623264SMatthew G. Knepley 
49277623264SMatthew G. Knepley   PetscFunctionBegin;
49377623264SMatthew G. Knepley   ierr = PetscFunctionListAdd(&PetscPartitionerList, sname, function);CHKERRQ(ierr);
49477623264SMatthew G. Knepley   PetscFunctionReturn(0);
49577623264SMatthew G. Knepley }
49677623264SMatthew G. Knepley 
49777623264SMatthew G. Knepley /*@C
49877623264SMatthew G. Knepley   PetscPartitionerSetType - Builds a particular PetscPartitioner
49977623264SMatthew G. Knepley 
50077623264SMatthew G. Knepley   Collective on PetscPartitioner
50177623264SMatthew G. Knepley 
50277623264SMatthew G. Knepley   Input Parameters:
50377623264SMatthew G. Knepley + part - The PetscPartitioner object
50477623264SMatthew G. Knepley - name - The kind of partitioner
50577623264SMatthew G. Knepley 
50677623264SMatthew G. Knepley   Options Database Key:
50777623264SMatthew G. Knepley . -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types
50877623264SMatthew G. Knepley 
50977623264SMatthew G. Knepley   Level: intermediate
51077623264SMatthew G. Knepley 
51177623264SMatthew G. Knepley .keywords: PetscPartitioner, set, type
51277623264SMatthew G. Knepley .seealso: PetscPartitionerGetType(), PetscPartitionerCreate()
51377623264SMatthew G. Knepley @*/
51477623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name)
51577623264SMatthew G. Knepley {
51677623264SMatthew G. Knepley   PetscErrorCode (*r)(PetscPartitioner);
51777623264SMatthew G. Knepley   PetscBool      match;
51877623264SMatthew G. Knepley   PetscErrorCode ierr;
51977623264SMatthew G. Knepley 
52077623264SMatthew G. Knepley   PetscFunctionBegin;
52177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
52277623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) part, name, &match);CHKERRQ(ierr);
52377623264SMatthew G. Knepley   if (match) PetscFunctionReturn(0);
52477623264SMatthew G. Knepley 
5250f51fdf8SToby Isaac   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
52677623264SMatthew G. Knepley   ierr = PetscFunctionListFind(PetscPartitionerList, name, &r);CHKERRQ(ierr);
52777623264SMatthew G. Knepley   if (!r) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name);
52877623264SMatthew G. Knepley 
52977623264SMatthew G. Knepley   if (part->ops->destroy) {
53077623264SMatthew G. Knepley     ierr              = (*part->ops->destroy)(part);CHKERRQ(ierr);
53177623264SMatthew G. Knepley   }
53209161815SVaclav Hapla   ierr = PetscMemzero(part->ops, sizeof(struct _PetscPartitionerOps));CHKERRQ(ierr);
53377623264SMatthew G. Knepley   ierr = (*r)(part);CHKERRQ(ierr);
53477623264SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) part, name);CHKERRQ(ierr);
53577623264SMatthew G. Knepley   PetscFunctionReturn(0);
53677623264SMatthew G. Knepley }
53777623264SMatthew G. Knepley 
53877623264SMatthew G. Knepley /*@C
53977623264SMatthew G. Knepley   PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object.
54077623264SMatthew G. Knepley 
54177623264SMatthew G. Knepley   Not Collective
54277623264SMatthew G. Knepley 
54377623264SMatthew G. Knepley   Input Parameter:
54477623264SMatthew G. Knepley . part - The PetscPartitioner
54577623264SMatthew G. Knepley 
54677623264SMatthew G. Knepley   Output Parameter:
54777623264SMatthew G. Knepley . name - The PetscPartitioner type name
54877623264SMatthew G. Knepley 
54977623264SMatthew G. Knepley   Level: intermediate
55077623264SMatthew G. Knepley 
55177623264SMatthew G. Knepley .keywords: PetscPartitioner, get, type, name
55277623264SMatthew G. Knepley .seealso: PetscPartitionerSetType(), PetscPartitionerCreate()
55377623264SMatthew G. Knepley @*/
55477623264SMatthew G. Knepley PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name)
55577623264SMatthew G. Knepley {
55677623264SMatthew G. Knepley   PetscErrorCode ierr;
55777623264SMatthew G. Knepley 
55877623264SMatthew G. Knepley   PetscFunctionBegin;
55977623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
56077623264SMatthew G. Knepley   PetscValidPointer(name, 2);
5610f51fdf8SToby Isaac   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
56277623264SMatthew G. Knepley   *name = ((PetscObject) part)->type_name;
56377623264SMatthew G. Knepley   PetscFunctionReturn(0);
56477623264SMatthew G. Knepley }
56577623264SMatthew G. Knepley 
56677623264SMatthew G. Knepley /*@C
56777623264SMatthew G. Knepley   PetscPartitionerView - Views a PetscPartitioner
56877623264SMatthew G. Knepley 
56977623264SMatthew G. Knepley   Collective on PetscPartitioner
57077623264SMatthew G. Knepley 
57177623264SMatthew G. Knepley   Input Parameter:
57277623264SMatthew G. Knepley + part - the PetscPartitioner object to view
57377623264SMatthew G. Knepley - v    - the viewer
57477623264SMatthew G. Knepley 
57577623264SMatthew G. Knepley   Level: developer
57677623264SMatthew G. Knepley 
57777623264SMatthew G. Knepley .seealso: PetscPartitionerDestroy()
57877623264SMatthew G. Knepley @*/
57977623264SMatthew G. Knepley PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v)
58077623264SMatthew G. Knepley {
581ffc59708SMatthew G. Knepley   PetscMPIInt    size;
5822abdaa70SMatthew G. Knepley   PetscBool      isascii;
58377623264SMatthew G. Knepley   PetscErrorCode ierr;
58477623264SMatthew G. Knepley 
58577623264SMatthew G. Knepley   PetscFunctionBegin;
58677623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
58777623264SMatthew G. Knepley   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v);CHKERRQ(ierr);}
5882abdaa70SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
5892abdaa70SMatthew G. Knepley   if (isascii) {
5902abdaa70SMatthew G. Knepley     ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
591ffc59708SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "Graph Partitioner: %d MPI Process%s\n", size, size > 1 ? "es" : "");CHKERRQ(ierr);
5922abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "  type: %s\n", part->hdr.type_name);CHKERRQ(ierr);
5932abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr);
5942abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "edge cut: %D\n", part->edgeCut);CHKERRQ(ierr);
5952abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "balance:  %.2g\n", part->balance);CHKERRQ(ierr);
5962abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr);
5972abdaa70SMatthew G. Knepley   }
59877623264SMatthew G. Knepley   if (part->ops->view) {ierr = (*part->ops->view)(part, v);CHKERRQ(ierr);}
59977623264SMatthew G. Knepley   PetscFunctionReturn(0);
60077623264SMatthew G. Knepley }
60177623264SMatthew G. Knepley 
602a0058e54SToby Isaac static PetscErrorCode PetscPartitionerGetDefaultType(const char *currentType, const char **defaultType)
603a0058e54SToby Isaac {
604a0058e54SToby Isaac   PetscFunctionBegin;
605a0058e54SToby Isaac   if (!currentType) {
606a0058e54SToby Isaac #if defined(PETSC_HAVE_CHACO)
607a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERCHACO;
608a0058e54SToby Isaac #elif defined(PETSC_HAVE_PARMETIS)
609a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERPARMETIS;
610137cd93aSLisandro Dalcin #elif defined(PETSC_HAVE_PTSCOTCH)
611137cd93aSLisandro Dalcin     *defaultType = PETSCPARTITIONERPTSCOTCH;
612a0058e54SToby Isaac #else
613a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERSIMPLE;
614a0058e54SToby Isaac #endif
615a0058e54SToby Isaac   } else {
616a0058e54SToby Isaac     *defaultType = currentType;
617a0058e54SToby Isaac   }
618a0058e54SToby Isaac   PetscFunctionReturn(0);
619a0058e54SToby Isaac }
620a0058e54SToby Isaac 
62177623264SMatthew G. Knepley /*@
62277623264SMatthew G. Knepley   PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database
62377623264SMatthew G. Knepley 
62477623264SMatthew G. Knepley   Collective on PetscPartitioner
62577623264SMatthew G. Knepley 
62677623264SMatthew G. Knepley   Input Parameter:
62777623264SMatthew G. Knepley . part - the PetscPartitioner object to set options for
62877623264SMatthew G. Knepley 
62977623264SMatthew G. Knepley   Level: developer
63077623264SMatthew G. Knepley 
63177623264SMatthew G. Knepley .seealso: PetscPartitionerView()
63277623264SMatthew G. Knepley @*/
63377623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part)
63477623264SMatthew G. Knepley {
6356bb9daa8SLisandro Dalcin   const char    *defaultType;
6366bb9daa8SLisandro Dalcin   char           name[256];
6376bb9daa8SLisandro Dalcin   PetscBool      flg;
63877623264SMatthew G. Knepley   PetscErrorCode ierr;
63977623264SMatthew G. Knepley 
64077623264SMatthew G. Knepley   PetscFunctionBegin;
64177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
6426bb9daa8SLisandro Dalcin   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
6436bb9daa8SLisandro Dalcin   ierr = PetscPartitionerGetDefaultType(((PetscObject) part)->type_name,&defaultType);CHKERRQ(ierr);
64477623264SMatthew G. Knepley   ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr);
6456bb9daa8SLisandro Dalcin   ierr = PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, defaultType, name, sizeof(name), &flg);CHKERRQ(ierr);
6466bb9daa8SLisandro Dalcin   if (flg) {
6476bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, name);CHKERRQ(ierr);
6486bb9daa8SLisandro Dalcin   } else if (!((PetscObject) part)->type_name) {
6496bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, defaultType);CHKERRQ(ierr);
6506bb9daa8SLisandro Dalcin   }
6516bb9daa8SLisandro Dalcin   if (part->ops->setfromoptions) {
6526bb9daa8SLisandro Dalcin     ierr = (*part->ops->setfromoptions)(PetscOptionsObject,part);CHKERRQ(ierr);
6536bb9daa8SLisandro Dalcin   }
654783e1fb6SStefano Zampini   ierr = PetscViewerDestroy(&part->viewerGraph);CHKERRQ(ierr);
6550358368aSMatthew G. Knepley   ierr = PetscOptionsGetViewer(((PetscObject) part)->comm, ((PetscObject) part)->options, ((PetscObject) part)->prefix, "-petscpartitioner_view_graph", &part->viewerGraph, &part->formatGraph, &part->viewGraph);CHKERRQ(ierr);
65677623264SMatthew G. Knepley   /* process any options handlers added with PetscObjectAddOptionsHandler() */
6570633abcbSJed Brown   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) part);CHKERRQ(ierr);
65877623264SMatthew G. Knepley   ierr = PetscOptionsEnd();CHKERRQ(ierr);
65977623264SMatthew G. Knepley   PetscFunctionReturn(0);
66077623264SMatthew G. Knepley }
66177623264SMatthew G. Knepley 
66277623264SMatthew G. Knepley /*@C
66377623264SMatthew G. Knepley   PetscPartitionerSetUp - Construct data structures for the PetscPartitioner
66477623264SMatthew G. Knepley 
66577623264SMatthew G. Knepley   Collective on PetscPartitioner
66677623264SMatthew G. Knepley 
66777623264SMatthew G. Knepley   Input Parameter:
66877623264SMatthew G. Knepley . part - the PetscPartitioner object to setup
66977623264SMatthew G. Knepley 
67077623264SMatthew G. Knepley   Level: developer
67177623264SMatthew G. Knepley 
67277623264SMatthew G. Knepley .seealso: PetscPartitionerView(), PetscPartitionerDestroy()
67377623264SMatthew G. Knepley @*/
67477623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part)
67577623264SMatthew G. Knepley {
67677623264SMatthew G. Knepley   PetscErrorCode ierr;
67777623264SMatthew G. Knepley 
67877623264SMatthew G. Knepley   PetscFunctionBegin;
67977623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
68077623264SMatthew G. Knepley   if (part->ops->setup) {ierr = (*part->ops->setup)(part);CHKERRQ(ierr);}
68177623264SMatthew G. Knepley   PetscFunctionReturn(0);
68277623264SMatthew G. Knepley }
68377623264SMatthew G. Knepley 
68477623264SMatthew G. Knepley /*@
68577623264SMatthew G. Knepley   PetscPartitionerDestroy - Destroys a PetscPartitioner object
68677623264SMatthew G. Knepley 
68777623264SMatthew G. Knepley   Collective on PetscPartitioner
68877623264SMatthew G. Knepley 
68977623264SMatthew G. Knepley   Input Parameter:
69077623264SMatthew G. Knepley . part - the PetscPartitioner object to destroy
69177623264SMatthew G. Knepley 
69277623264SMatthew G. Knepley   Level: developer
69377623264SMatthew G. Knepley 
69477623264SMatthew G. Knepley .seealso: PetscPartitionerView()
69577623264SMatthew G. Knepley @*/
69677623264SMatthew G. Knepley PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part)
69777623264SMatthew G. Knepley {
69877623264SMatthew G. Knepley   PetscErrorCode ierr;
69977623264SMatthew G. Knepley 
70077623264SMatthew G. Knepley   PetscFunctionBegin;
70177623264SMatthew G. Knepley   if (!*part) PetscFunctionReturn(0);
70277623264SMatthew G. Knepley   PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1);
70377623264SMatthew G. Knepley 
70477623264SMatthew G. Knepley   if (--((PetscObject)(*part))->refct > 0) {*part = 0; PetscFunctionReturn(0);}
70577623264SMatthew G. Knepley   ((PetscObject) (*part))->refct = 0;
70677623264SMatthew G. Knepley 
7070358368aSMatthew G. Knepley   ierr = PetscViewerDestroy(&(*part)->viewerGraph);CHKERRQ(ierr);
70877623264SMatthew G. Knepley   if ((*part)->ops->destroy) {ierr = (*(*part)->ops->destroy)(*part);CHKERRQ(ierr);}
70977623264SMatthew G. Knepley   ierr = PetscHeaderDestroy(part);CHKERRQ(ierr);
71077623264SMatthew G. Knepley   PetscFunctionReturn(0);
71177623264SMatthew G. Knepley }
71277623264SMatthew G. Knepley 
71377623264SMatthew G. Knepley /*@
71477623264SMatthew G. Knepley   PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType().
71577623264SMatthew G. Knepley 
71677623264SMatthew G. Knepley   Collective on MPI_Comm
71777623264SMatthew G. Knepley 
71877623264SMatthew G. Knepley   Input Parameter:
71977623264SMatthew G. Knepley . comm - The communicator for the PetscPartitioner object
72077623264SMatthew G. Knepley 
72177623264SMatthew G. Knepley   Output Parameter:
72277623264SMatthew G. Knepley . part - The PetscPartitioner object
72377623264SMatthew G. Knepley 
72477623264SMatthew G. Knepley   Level: beginner
72577623264SMatthew G. Knepley 
726dae52e14SToby Isaac .seealso: PetscPartitionerSetType(), PETSCPARTITIONERCHACO, PETSCPARTITIONERPARMETIS, PETSCPARTITIONERSHELL, PETSCPARTITIONERSIMPLE, PETSCPARTITIONERGATHER
72777623264SMatthew G. Knepley @*/
72877623264SMatthew G. Knepley PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
72977623264SMatthew G. Knepley {
73077623264SMatthew G. Knepley   PetscPartitioner p;
731a0058e54SToby Isaac   const char       *partitionerType = NULL;
73277623264SMatthew G. Knepley   PetscErrorCode   ierr;
73377623264SMatthew G. Knepley 
73477623264SMatthew G. Knepley   PetscFunctionBegin;
73577623264SMatthew G. Knepley   PetscValidPointer(part, 2);
73677623264SMatthew G. Knepley   *part = NULL;
73783cde681SMatthew G. Knepley   ierr = DMInitializePackage();CHKERRQ(ierr);
73877623264SMatthew G. Knepley 
73973107ff1SLisandro Dalcin   ierr = PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView);CHKERRQ(ierr);
740a0058e54SToby Isaac   ierr = PetscPartitionerGetDefaultType(NULL,&partitionerType);CHKERRQ(ierr);
741a0058e54SToby Isaac   ierr = PetscPartitionerSetType(p,partitionerType);CHKERRQ(ierr);
74277623264SMatthew G. Knepley 
74372379da4SMatthew G. Knepley   p->edgeCut = 0;
74472379da4SMatthew G. Knepley   p->balance = 0.0;
74572379da4SMatthew G. Knepley 
74677623264SMatthew G. Knepley   *part = p;
74777623264SMatthew G. Knepley   PetscFunctionReturn(0);
74877623264SMatthew G. Knepley }
74977623264SMatthew G. Knepley 
75077623264SMatthew G. Knepley /*@
75177623264SMatthew G. Knepley   PetscPartitionerPartition - Create a non-overlapping partition of the cells in the mesh
75277623264SMatthew G. Knepley 
75377623264SMatthew G. Knepley   Collective on DM
75477623264SMatthew G. Knepley 
75577623264SMatthew G. Knepley   Input Parameters:
75677623264SMatthew G. Knepley + part    - The PetscPartitioner
757f8987ae8SMichael Lange - dm      - The mesh DM
75877623264SMatthew G. Knepley 
75977623264SMatthew G. Knepley   Output Parameters:
76077623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
761f8987ae8SMichael Lange - partition       - The list of points by partition
76277623264SMatthew G. Knepley 
7630358368aSMatthew G. Knepley   Options Database:
7640358368aSMatthew G. Knepley . -petscpartitioner_view_graph - View the graph we are partitioning
7650358368aSMatthew G. Knepley 
76677623264SMatthew G. Knepley   Note: Instead of cells, points at a given height can be partitioned by calling PetscPartitionerSetPointHeight()
76777623264SMatthew G. Knepley 
76877623264SMatthew G. Knepley   Level: developer
76977623264SMatthew G. Knepley 
77077623264SMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerSetPointHeight(), PetscPartitionerCreate()
7714b15ede2SMatthew G. Knepley @*/
772f8987ae8SMichael Lange PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, DM dm, PetscSection partSection, IS *partition)
77377623264SMatthew G. Knepley {
77477623264SMatthew G. Knepley   PetscMPIInt    size;
77577623264SMatthew G. Knepley   PetscErrorCode ierr;
77677623264SMatthew G. Knepley 
77777623264SMatthew G. Knepley   PetscFunctionBegin;
77877623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
77977623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
78077623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
78177623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
78277623264SMatthew G. Knepley   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
78377623264SMatthew G. Knepley   if (size == 1) {
78477623264SMatthew G. Knepley     PetscInt *points;
78577623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
78677623264SMatthew G. Knepley 
78777623264SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
78877623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr);
78977623264SMatthew G. Knepley     ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr);
79077623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
79177623264SMatthew G. Knepley     ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr);
79277623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
79377623264SMatthew G. Knepley     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
79477623264SMatthew G. Knepley     PetscFunctionReturn(0);
79577623264SMatthew G. Knepley   }
79677623264SMatthew G. Knepley   if (part->height == 0) {
79777623264SMatthew G. Knepley     PetscInt numVertices;
79877623264SMatthew G. Knepley     PetscInt *start     = NULL;
79977623264SMatthew G. Knepley     PetscInt *adjacency = NULL;
8003fa7752dSToby Isaac     IS       globalNumbering;
80177623264SMatthew G. Knepley 
8023fa7752dSToby Isaac     ierr = DMPlexCreatePartitionerGraph(dm, 0, &numVertices, &start, &adjacency, &globalNumbering);CHKERRQ(ierr);
8030358368aSMatthew G. Knepley     if (part->viewGraph) {
8040358368aSMatthew G. Knepley       PetscViewer viewer = part->viewerGraph;
8050358368aSMatthew G. Knepley       PetscBool   isascii;
8060358368aSMatthew G. Knepley       PetscInt    v, i;
8070358368aSMatthew G. Knepley       PetscMPIInt rank;
8080358368aSMatthew G. Knepley 
8090358368aSMatthew G. Knepley       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) viewer), &rank);CHKERRQ(ierr);
8100358368aSMatthew G. Knepley       ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
8110358368aSMatthew G. Knepley       if (isascii) {
8120358368aSMatthew G. Knepley         ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
8130358368aSMatthew G. Knepley         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]Nv: %D\n", rank, numVertices);CHKERRQ(ierr);
8140358368aSMatthew G. Knepley         for (v = 0; v < numVertices; ++v) {
8150358368aSMatthew G. Knepley           const PetscInt s = start[v];
8160358368aSMatthew G. Knepley           const PetscInt e = start[v+1];
8170358368aSMatthew G. Knepley 
8180358368aSMatthew G. Knepley           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]  ", rank);CHKERRQ(ierr);
8190358368aSMatthew G. Knepley           for (i = s; i < e; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%D ", adjacency[i]);CHKERRQ(ierr);}
8200358368aSMatthew G. Knepley           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D-%D)\n", s, e);CHKERRQ(ierr);
8210358368aSMatthew G. Knepley         }
8220358368aSMatthew G. Knepley         ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
8230358368aSMatthew G. Knepley         ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
8240358368aSMatthew G. Knepley       }
8250358368aSMatthew G. Knepley     }
82677623264SMatthew G. Knepley     if (!part->ops->partition) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_WRONGSTATE, "PetscPartitioner has no type");
82777623264SMatthew G. Knepley     ierr = (*part->ops->partition)(part, dm, size, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
82877623264SMatthew G. Knepley     ierr = PetscFree(start);CHKERRQ(ierr);
82977623264SMatthew G. Knepley     ierr = PetscFree(adjacency);CHKERRQ(ierr);
8303fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
8313fa7752dSToby Isaac       const PetscInt *globalNum;
8323fa7752dSToby Isaac       const PetscInt *partIdx;
8333fa7752dSToby Isaac       PetscInt *map, cStart, cEnd;
8343fa7752dSToby Isaac       PetscInt *adjusted, i, localSize, offset;
8353fa7752dSToby Isaac       IS    newPartition;
8363fa7752dSToby Isaac 
8373fa7752dSToby Isaac       ierr = ISGetLocalSize(*partition,&localSize);CHKERRQ(ierr);
8383fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&adjusted);CHKERRQ(ierr);
8393fa7752dSToby Isaac       ierr = ISGetIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
8403fa7752dSToby Isaac       ierr = ISGetIndices(*partition,&partIdx);CHKERRQ(ierr);
8413fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&map);CHKERRQ(ierr);
8423fa7752dSToby Isaac       ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
8433fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
8443fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
8453fa7752dSToby Isaac       }
8463fa7752dSToby Isaac       for (i = 0; i < localSize; i++) {
8473fa7752dSToby Isaac         adjusted[i] = map[partIdx[i]];
8483fa7752dSToby Isaac       }
8493fa7752dSToby Isaac       ierr = PetscFree(map);CHKERRQ(ierr);
8503fa7752dSToby Isaac       ierr = ISRestoreIndices(*partition,&partIdx);CHKERRQ(ierr);
8513fa7752dSToby Isaac       ierr = ISRestoreIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
8523fa7752dSToby Isaac       ierr = ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition);CHKERRQ(ierr);
8533fa7752dSToby Isaac       ierr = ISDestroy(&globalNumbering);CHKERRQ(ierr);
8543fa7752dSToby Isaac       ierr = ISDestroy(partition);CHKERRQ(ierr);
8553fa7752dSToby Isaac       *partition = newPartition;
8563fa7752dSToby Isaac     }
85777623264SMatthew G. Knepley   } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height);
8582abdaa70SMatthew G. Knepley   ierr = PetscPartitionerViewFromOptions(part, NULL, "-petscpartitioner_view");CHKERRQ(ierr);
85977623264SMatthew G. Knepley   PetscFunctionReturn(0);
86077623264SMatthew G. Knepley }
86177623264SMatthew G. Knepley 
862d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Shell(PetscPartitioner part)
86377623264SMatthew G. Knepley {
86477623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
86577623264SMatthew G. Knepley   PetscErrorCode          ierr;
86677623264SMatthew G. Knepley 
86777623264SMatthew G. Knepley   PetscFunctionBegin;
86877623264SMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
86977623264SMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
87077623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
87177623264SMatthew G. Knepley   PetscFunctionReturn(0);
87277623264SMatthew G. Knepley }
87377623264SMatthew G. Knepley 
874d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell_Ascii(PetscPartitioner part, PetscViewer viewer)
87577623264SMatthew G. Knepley {
876077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
87777623264SMatthew G. Knepley   PetscErrorCode          ierr;
87877623264SMatthew G. Knepley 
87977623264SMatthew G. Knepley   PetscFunctionBegin;
880077101c0SMatthew G. Knepley   if (p->random) {
881077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
882077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(viewer, "using random partition\n");CHKERRQ(ierr);
883077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
884077101c0SMatthew G. Knepley   }
88577623264SMatthew G. Knepley   PetscFunctionReturn(0);
88677623264SMatthew G. Knepley }
88777623264SMatthew G. Knepley 
888d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell(PetscPartitioner part, PetscViewer viewer)
88977623264SMatthew G. Knepley {
89077623264SMatthew G. Knepley   PetscBool      iascii;
89177623264SMatthew G. Knepley   PetscErrorCode ierr;
89277623264SMatthew G. Knepley 
89377623264SMatthew G. Knepley   PetscFunctionBegin;
89477623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
89577623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
89677623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
89777623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Shell_Ascii(part, viewer);CHKERRQ(ierr);}
89877623264SMatthew G. Knepley   PetscFunctionReturn(0);
89977623264SMatthew G. Knepley }
90077623264SMatthew G. Knepley 
901d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerSetFromOptions_Shell(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
902077101c0SMatthew G. Knepley {
903077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
904077101c0SMatthew G. Knepley   PetscErrorCode          ierr;
905077101c0SMatthew G. Knepley 
906077101c0SMatthew G. Knepley   PetscFunctionBegin;
907077101c0SMatthew G. Knepley   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner Shell Options");CHKERRQ(ierr);
908077101c0SMatthew G. Knepley   ierr = PetscOptionsBool("-petscpartitioner_shell_random", "Use a random partition", "PetscPartitionerView", PETSC_FALSE, &p->random, NULL);CHKERRQ(ierr);
909077101c0SMatthew G. Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
910077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
911077101c0SMatthew G. Knepley }
912077101c0SMatthew G. Knepley 
913d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Shell(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
91477623264SMatthew G. Knepley {
91577623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
91677623264SMatthew G. Knepley   PetscInt                np;
91777623264SMatthew G. Knepley   PetscErrorCode          ierr;
91877623264SMatthew G. Knepley 
91977623264SMatthew G. Knepley   PetscFunctionBegin;
920077101c0SMatthew G. Knepley   if (p->random) {
921077101c0SMatthew G. Knepley     PetscRandom r;
922aa1d5631SMatthew G. Knepley     PetscInt   *sizes, *points, v, p;
923aa1d5631SMatthew G. Knepley     PetscMPIInt rank;
924077101c0SMatthew G. Knepley 
925aa1d5631SMatthew G. Knepley     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
926077101c0SMatthew G. Knepley     ierr = PetscRandomCreate(PETSC_COMM_SELF, &r);CHKERRQ(ierr);
927c717d290SMatthew G. Knepley     ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) nparts);CHKERRQ(ierr);
928077101c0SMatthew G. Knepley     ierr = PetscRandomSetFromOptions(r);CHKERRQ(ierr);
929077101c0SMatthew G. Knepley     ierr = PetscCalloc2(nparts, &sizes, numVertices, &points);CHKERRQ(ierr);
930aa1d5631SMatthew G. Knepley     for (v = 0; v < numVertices; ++v) {points[v] = v;}
931ac9a96f1SMichael Lange     for (p = 0; p < nparts; ++p) {sizes[p] = numVertices/nparts + (PetscInt) (p < numVertices % nparts);}
932aa1d5631SMatthew G. Knepley     for (v = numVertices-1; v > 0; --v) {
933077101c0SMatthew G. Knepley       PetscReal val;
934aa1d5631SMatthew G. Knepley       PetscInt  w, tmp;
935077101c0SMatthew G. Knepley 
936aa1d5631SMatthew G. Knepley       ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) (v+1));CHKERRQ(ierr);
937077101c0SMatthew G. Knepley       ierr = PetscRandomGetValueReal(r, &val);CHKERRQ(ierr);
938aa1d5631SMatthew G. Knepley       w    = PetscFloorReal(val);
939aa1d5631SMatthew G. Knepley       tmp       = points[v];
940aa1d5631SMatthew G. Knepley       points[v] = points[w];
941aa1d5631SMatthew G. Knepley       points[w] = tmp;
942077101c0SMatthew G. Knepley     }
943077101c0SMatthew G. Knepley     ierr = PetscRandomDestroy(&r);CHKERRQ(ierr);
944077101c0SMatthew G. Knepley     ierr = PetscPartitionerShellSetPartition(part, nparts, sizes, points);CHKERRQ(ierr);
945077101c0SMatthew G. Knepley     ierr = PetscFree2(sizes, points);CHKERRQ(ierr);
946077101c0SMatthew G. Knepley   }
947c717d290SMatthew G. Knepley   if (!p->section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Shell partitioner information not provided. Please call PetscPartitionerShellSetPartition()");
94877623264SMatthew G. Knepley   ierr = PetscSectionGetChart(p->section, NULL, &np);CHKERRQ(ierr);
94977623264SMatthew G. Knepley   if (nparts != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of requested partitions %d != configured partitions %d", nparts, np);
95077623264SMatthew G. Knepley   ierr = ISGetLocalSize(p->partition, &np);CHKERRQ(ierr);
95177623264SMatthew G. Knepley   if (numVertices != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input vertices %d != configured vertices %d", numVertices, np);
9525680f57bSMatthew G. Knepley   ierr = PetscSectionCopy(p->section, partSection);CHKERRQ(ierr);
95377623264SMatthew G. Knepley   *partition = p->partition;
95477623264SMatthew G. Knepley   ierr = PetscObjectReference((PetscObject) p->partition);CHKERRQ(ierr);
95577623264SMatthew G. Knepley   PetscFunctionReturn(0);
95677623264SMatthew G. Knepley }
95777623264SMatthew G. Knepley 
958d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Shell(PetscPartitioner part)
95977623264SMatthew G. Knepley {
96077623264SMatthew G. Knepley   PetscFunctionBegin;
96177623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_Shell;
962077101c0SMatthew G. Knepley   part->ops->setfromoptions = PetscPartitionerSetFromOptions_Shell;
96377623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_Shell;
96477623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_Shell;
96577623264SMatthew G. Knepley   PetscFunctionReturn(0);
96677623264SMatthew G. Knepley }
96777623264SMatthew G. Knepley 
96877623264SMatthew G. Knepley /*MC
96977623264SMatthew G. Knepley   PETSCPARTITIONERSHELL = "shell" - A PetscPartitioner object
97077623264SMatthew G. Knepley 
97177623264SMatthew G. Knepley   Level: intermediate
97277623264SMatthew G. Knepley 
97377623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
97477623264SMatthew G. Knepley M*/
97577623264SMatthew G. Knepley 
97677623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Shell(PetscPartitioner part)
97777623264SMatthew G. Knepley {
97877623264SMatthew G. Knepley   PetscPartitioner_Shell *p;
97977623264SMatthew G. Knepley   PetscErrorCode          ierr;
98077623264SMatthew G. Knepley 
98177623264SMatthew G. Knepley   PetscFunctionBegin;
98277623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
98377623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
98477623264SMatthew G. Knepley   part->data = p;
98577623264SMatthew G. Knepley 
98677623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Shell(part);CHKERRQ(ierr);
987077101c0SMatthew G. Knepley   p->random = PETSC_FALSE;
98877623264SMatthew G. Knepley   PetscFunctionReturn(0);
98977623264SMatthew G. Knepley }
99077623264SMatthew G. Knepley 
9915680f57bSMatthew G. Knepley /*@C
9925680f57bSMatthew G. Knepley   PetscPartitionerShellSetPartition - Set an artifical partition for a mesh
9935680f57bSMatthew G. Knepley 
994077101c0SMatthew G. Knepley   Collective on Part
9955680f57bSMatthew G. Knepley 
9965680f57bSMatthew G. Knepley   Input Parameters:
9975680f57bSMatthew G. Knepley + part     - The PetscPartitioner
9989852e123SBarry Smith . size - The number of partitions
9999852e123SBarry Smith . sizes    - array of size size (or NULL) providing the number of points in each partition
10009758bf69SToby Isaac - points   - array of size sum(sizes) (may be NULL iff sizes is NULL), a permutation of the points that groups those assigned to each partition in order (i.e., partition 0 first, partition 1 next, etc.)
10015680f57bSMatthew G. Knepley 
10025680f57bSMatthew G. Knepley   Level: developer
10035680f57bSMatthew G. Knepley 
1004b7e49471SLawrence Mitchell   Notes:
1005b7e49471SLawrence Mitchell 
1006b7e49471SLawrence Mitchell     It is safe to free the sizes and points arrays after use in this routine.
1007b7e49471SLawrence Mitchell 
10085680f57bSMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerCreate()
10095680f57bSMatthew G. Knepley @*/
10109852e123SBarry Smith PetscErrorCode PetscPartitionerShellSetPartition(PetscPartitioner part, PetscInt size, const PetscInt sizes[], const PetscInt points[])
10115680f57bSMatthew G. Knepley {
10125680f57bSMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
10135680f57bSMatthew G. Knepley   PetscInt                proc, numPoints;
10145680f57bSMatthew G. Knepley   PetscErrorCode          ierr;
10155680f57bSMatthew G. Knepley 
10165680f57bSMatthew G. Knepley   PetscFunctionBegin;
10175680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
10185680f57bSMatthew G. Knepley   if (sizes)  {PetscValidPointer(sizes, 3);}
1019c717d290SMatthew G. Knepley   if (points) {PetscValidPointer(points, 4);}
10205680f57bSMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
10215680f57bSMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
10225680f57bSMatthew G. Knepley   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) part), &p->section);CHKERRQ(ierr);
10239852e123SBarry Smith   ierr = PetscSectionSetChart(p->section, 0, size);CHKERRQ(ierr);
10245680f57bSMatthew G. Knepley   if (sizes) {
10259852e123SBarry Smith     for (proc = 0; proc < size; ++proc) {
10265680f57bSMatthew G. Knepley       ierr = PetscSectionSetDof(p->section, proc, sizes[proc]);CHKERRQ(ierr);
10275680f57bSMatthew G. Knepley     }
10285680f57bSMatthew G. Knepley   }
10295680f57bSMatthew G. Knepley   ierr = PetscSectionSetUp(p->section);CHKERRQ(ierr);
10305680f57bSMatthew G. Knepley   ierr = PetscSectionGetStorageSize(p->section, &numPoints);CHKERRQ(ierr);
10315680f57bSMatthew G. Knepley   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), numPoints, points, PETSC_COPY_VALUES, &p->partition);CHKERRQ(ierr);
10325680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
10335680f57bSMatthew G. Knepley }
10345680f57bSMatthew G. Knepley 
1035077101c0SMatthew G. Knepley /*@
1036077101c0SMatthew G. Knepley   PetscPartitionerShellSetRandom - Set the flag to use a random partition
1037077101c0SMatthew G. Knepley 
1038077101c0SMatthew G. Knepley   Collective on Part
1039077101c0SMatthew G. Knepley 
1040077101c0SMatthew G. Knepley   Input Parameters:
1041077101c0SMatthew G. Knepley + part   - The PetscPartitioner
1042077101c0SMatthew G. Knepley - random - The flag to use a random partition
1043077101c0SMatthew G. Knepley 
1044077101c0SMatthew G. Knepley   Level: intermediate
1045077101c0SMatthew G. Knepley 
1046077101c0SMatthew G. Knepley .seealso PetscPartitionerShellGetRandom(), PetscPartitionerCreate()
1047077101c0SMatthew G. Knepley @*/
1048077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellSetRandom(PetscPartitioner part, PetscBool random)
1049077101c0SMatthew G. Knepley {
1050077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1051077101c0SMatthew G. Knepley 
1052077101c0SMatthew G. Knepley   PetscFunctionBegin;
1053077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1054077101c0SMatthew G. Knepley   p->random = random;
1055077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1056077101c0SMatthew G. Knepley }
1057077101c0SMatthew G. Knepley 
1058077101c0SMatthew G. Knepley /*@
1059077101c0SMatthew G. Knepley   PetscPartitionerShellGetRandom - get the flag to use a random partition
1060077101c0SMatthew G. Knepley 
1061077101c0SMatthew G. Knepley   Collective on Part
1062077101c0SMatthew G. Knepley 
1063077101c0SMatthew G. Knepley   Input Parameter:
1064077101c0SMatthew G. Knepley . part   - The PetscPartitioner
1065077101c0SMatthew G. Knepley 
1066077101c0SMatthew G. Knepley   Output Parameter
1067077101c0SMatthew G. Knepley . random - The flag to use a random partition
1068077101c0SMatthew G. Knepley 
1069077101c0SMatthew G. Knepley   Level: intermediate
1070077101c0SMatthew G. Knepley 
1071077101c0SMatthew G. Knepley .seealso PetscPartitionerShellSetRandom(), PetscPartitionerCreate()
1072077101c0SMatthew G. Knepley @*/
1073077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellGetRandom(PetscPartitioner part, PetscBool *random)
1074077101c0SMatthew G. Knepley {
1075077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1076077101c0SMatthew G. Knepley 
1077077101c0SMatthew G. Knepley   PetscFunctionBegin;
1078077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1079077101c0SMatthew G. Knepley   PetscValidPointer(random, 2);
1080077101c0SMatthew G. Knepley   *random = p->random;
1081077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1082077101c0SMatthew G. Knepley }
1083077101c0SMatthew G. Knepley 
1084d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Simple(PetscPartitioner part)
1085555a9cf8SMatthew G. Knepley {
1086555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p = (PetscPartitioner_Simple *) part->data;
1087555a9cf8SMatthew G. Knepley   PetscErrorCode          ierr;
1088555a9cf8SMatthew G. Knepley 
1089555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1090555a9cf8SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
1091555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1092555a9cf8SMatthew G. Knepley }
1093555a9cf8SMatthew G. Knepley 
1094d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple_Ascii(PetscPartitioner part, PetscViewer viewer)
1095555a9cf8SMatthew G. Knepley {
1096555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1097555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1098555a9cf8SMatthew G. Knepley }
1099555a9cf8SMatthew G. Knepley 
1100d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple(PetscPartitioner part, PetscViewer viewer)
1101555a9cf8SMatthew G. Knepley {
1102555a9cf8SMatthew G. Knepley   PetscBool      iascii;
1103555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1104555a9cf8SMatthew G. Knepley 
1105555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1106555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1107555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1108555a9cf8SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1109555a9cf8SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Simple_Ascii(part, viewer);CHKERRQ(ierr);}
1110555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1111555a9cf8SMatthew G. Knepley }
1112555a9cf8SMatthew G. Knepley 
1113d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Simple(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1114555a9cf8SMatthew G. Knepley {
1115cead94edSToby Isaac   MPI_Comm       comm;
1116555a9cf8SMatthew G. Knepley   PetscInt       np;
1117cead94edSToby Isaac   PetscMPIInt    size;
1118555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1119555a9cf8SMatthew G. Knepley 
1120555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
112104ba2274SStefano Zampini   comm = PetscObjectComm((PetscObject)part);
1122cead94edSToby Isaac   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1123555a9cf8SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1124555a9cf8SMatthew G. Knepley   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1125cead94edSToby Isaac   if (size == 1) {
1126cead94edSToby Isaac     for (np = 0; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, numVertices/nparts + ((numVertices % nparts) > np));CHKERRQ(ierr);}
112704ba2274SStefano Zampini   } else {
1128cead94edSToby Isaac     PetscMPIInt rank;
1129cead94edSToby Isaac     PetscInt nvGlobal, *offsets, myFirst, myLast;
1130cead94edSToby Isaac 
1131a679a563SToby Isaac     ierr = PetscMalloc1(size+1,&offsets);CHKERRQ(ierr);
1132cead94edSToby Isaac     offsets[0] = 0;
1133cead94edSToby Isaac     ierr = MPI_Allgather(&numVertices,1,MPIU_INT,&offsets[1],1,MPIU_INT,comm);CHKERRQ(ierr);
1134cead94edSToby Isaac     for (np = 2; np <= size; np++) {
1135cead94edSToby Isaac       offsets[np] += offsets[np-1];
1136cead94edSToby Isaac     }
1137cead94edSToby Isaac     nvGlobal = offsets[size];
1138cead94edSToby Isaac     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1139cead94edSToby Isaac     myFirst = offsets[rank];
1140cead94edSToby Isaac     myLast  = offsets[rank + 1] - 1;
1141cead94edSToby Isaac     ierr = PetscFree(offsets);CHKERRQ(ierr);
1142cead94edSToby Isaac     if (numVertices) {
1143cead94edSToby Isaac       PetscInt firstPart = 0, firstLargePart = 0;
1144cead94edSToby Isaac       PetscInt lastPart = 0, lastLargePart = 0;
1145cead94edSToby Isaac       PetscInt rem = nvGlobal % nparts;
1146cead94edSToby Isaac       PetscInt pSmall = nvGlobal/nparts;
1147cead94edSToby Isaac       PetscInt pBig = nvGlobal/nparts + 1;
1148cead94edSToby Isaac 
1149cead94edSToby Isaac 
1150cead94edSToby Isaac       if (rem) {
1151cead94edSToby Isaac         firstLargePart = myFirst / pBig;
1152cead94edSToby Isaac         lastLargePart  = myLast  / pBig;
1153cead94edSToby Isaac 
1154cead94edSToby Isaac         if (firstLargePart < rem) {
1155cead94edSToby Isaac           firstPart = firstLargePart;
115604ba2274SStefano Zampini         } else {
1157cead94edSToby Isaac           firstPart = rem + (myFirst - (rem * pBig)) / pSmall;
1158cead94edSToby Isaac         }
1159cead94edSToby Isaac         if (lastLargePart < rem) {
1160cead94edSToby Isaac           lastPart = lastLargePart;
116104ba2274SStefano Zampini         } else {
1162cead94edSToby Isaac           lastPart = rem + (myLast - (rem * pBig)) / pSmall;
1163cead94edSToby Isaac         }
116404ba2274SStefano Zampini       } else {
1165cead94edSToby Isaac         firstPart = myFirst / (nvGlobal/nparts);
1166cead94edSToby Isaac         lastPart  = myLast  / (nvGlobal/nparts);
1167cead94edSToby Isaac       }
1168cead94edSToby Isaac 
1169cead94edSToby Isaac       for (np = firstPart; np <= lastPart; np++) {
1170cead94edSToby Isaac         PetscInt PartStart =  np    * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np);
1171cead94edSToby Isaac         PetscInt PartEnd   = (np+1) * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np+1);
1172cead94edSToby Isaac 
1173cead94edSToby Isaac         PartStart = PetscMax(PartStart,myFirst);
1174cead94edSToby Isaac         PartEnd   = PetscMin(PartEnd,myLast+1);
1175cead94edSToby Isaac         ierr = PetscSectionSetDof(partSection,np,PartEnd-PartStart);CHKERRQ(ierr);
1176cead94edSToby Isaac       }
1177cead94edSToby Isaac     }
1178cead94edSToby Isaac   }
1179cead94edSToby Isaac   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1180555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1181555a9cf8SMatthew G. Knepley }
1182555a9cf8SMatthew G. Knepley 
1183d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Simple(PetscPartitioner part)
1184555a9cf8SMatthew G. Knepley {
1185555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1186555a9cf8SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Simple;
1187555a9cf8SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Simple;
1188555a9cf8SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Simple;
1189555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1190555a9cf8SMatthew G. Knepley }
1191555a9cf8SMatthew G. Knepley 
1192555a9cf8SMatthew G. Knepley /*MC
1193555a9cf8SMatthew G. Knepley   PETSCPARTITIONERSIMPLE = "simple" - A PetscPartitioner object
1194555a9cf8SMatthew G. Knepley 
1195555a9cf8SMatthew G. Knepley   Level: intermediate
1196555a9cf8SMatthew G. Knepley 
1197555a9cf8SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1198555a9cf8SMatthew G. Knepley M*/
1199555a9cf8SMatthew G. Knepley 
1200555a9cf8SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Simple(PetscPartitioner part)
1201555a9cf8SMatthew G. Knepley {
1202555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p;
1203555a9cf8SMatthew G. Knepley   PetscErrorCode           ierr;
1204555a9cf8SMatthew G. Knepley 
1205555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1206555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1207555a9cf8SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1208555a9cf8SMatthew G. Knepley   part->data = p;
1209555a9cf8SMatthew G. Knepley 
1210555a9cf8SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Simple(part);CHKERRQ(ierr);
1211555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1212555a9cf8SMatthew G. Knepley }
1213555a9cf8SMatthew G. Knepley 
1214d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Gather(PetscPartitioner part)
1215dae52e14SToby Isaac {
1216dae52e14SToby Isaac   PetscPartitioner_Gather *p = (PetscPartitioner_Gather *) part->data;
1217dae52e14SToby Isaac   PetscErrorCode          ierr;
1218dae52e14SToby Isaac 
1219dae52e14SToby Isaac   PetscFunctionBegin;
1220dae52e14SToby Isaac   ierr = PetscFree(p);CHKERRQ(ierr);
1221dae52e14SToby Isaac   PetscFunctionReturn(0);
1222dae52e14SToby Isaac }
1223dae52e14SToby Isaac 
1224d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather_Ascii(PetscPartitioner part, PetscViewer viewer)
1225dae52e14SToby Isaac {
1226dae52e14SToby Isaac   PetscFunctionBegin;
1227dae52e14SToby Isaac   PetscFunctionReturn(0);
1228dae52e14SToby Isaac }
1229dae52e14SToby Isaac 
1230d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather(PetscPartitioner part, PetscViewer viewer)
1231dae52e14SToby Isaac {
1232dae52e14SToby Isaac   PetscBool      iascii;
1233dae52e14SToby Isaac   PetscErrorCode ierr;
1234dae52e14SToby Isaac 
1235dae52e14SToby Isaac   PetscFunctionBegin;
1236dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1237dae52e14SToby Isaac   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1238dae52e14SToby Isaac   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1239dae52e14SToby Isaac   if (iascii) {ierr = PetscPartitionerView_Gather_Ascii(part, viewer);CHKERRQ(ierr);}
1240dae52e14SToby Isaac   PetscFunctionReturn(0);
1241dae52e14SToby Isaac }
1242dae52e14SToby Isaac 
1243d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Gather(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1244dae52e14SToby Isaac {
1245dae52e14SToby Isaac   PetscInt       np;
1246dae52e14SToby Isaac   PetscErrorCode ierr;
1247dae52e14SToby Isaac 
1248dae52e14SToby Isaac   PetscFunctionBegin;
1249dae52e14SToby Isaac   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1250dae52e14SToby Isaac   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1251dae52e14SToby Isaac   ierr = PetscSectionSetDof(partSection,0,numVertices);CHKERRQ(ierr);
1252dae52e14SToby Isaac   for (np = 1; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, 0);CHKERRQ(ierr);}
1253dae52e14SToby Isaac   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1254dae52e14SToby Isaac   PetscFunctionReturn(0);
1255dae52e14SToby Isaac }
1256dae52e14SToby Isaac 
1257d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Gather(PetscPartitioner part)
1258dae52e14SToby Isaac {
1259dae52e14SToby Isaac   PetscFunctionBegin;
1260dae52e14SToby Isaac   part->ops->view      = PetscPartitionerView_Gather;
1261dae52e14SToby Isaac   part->ops->destroy   = PetscPartitionerDestroy_Gather;
1262dae52e14SToby Isaac   part->ops->partition = PetscPartitionerPartition_Gather;
1263dae52e14SToby Isaac   PetscFunctionReturn(0);
1264dae52e14SToby Isaac }
1265dae52e14SToby Isaac 
1266dae52e14SToby Isaac /*MC
1267dae52e14SToby Isaac   PETSCPARTITIONERGATHER = "gather" - A PetscPartitioner object
1268dae52e14SToby Isaac 
1269dae52e14SToby Isaac   Level: intermediate
1270dae52e14SToby Isaac 
1271dae52e14SToby Isaac .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1272dae52e14SToby Isaac M*/
1273dae52e14SToby Isaac 
1274dae52e14SToby Isaac PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Gather(PetscPartitioner part)
1275dae52e14SToby Isaac {
1276dae52e14SToby Isaac   PetscPartitioner_Gather *p;
1277dae52e14SToby Isaac   PetscErrorCode           ierr;
1278dae52e14SToby Isaac 
1279dae52e14SToby Isaac   PetscFunctionBegin;
1280dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1281dae52e14SToby Isaac   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1282dae52e14SToby Isaac   part->data = p;
1283dae52e14SToby Isaac 
1284dae52e14SToby Isaac   ierr = PetscPartitionerInitialize_Gather(part);CHKERRQ(ierr);
1285dae52e14SToby Isaac   PetscFunctionReturn(0);
1286dae52e14SToby Isaac }
1287dae52e14SToby Isaac 
1288dae52e14SToby Isaac 
1289d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Chaco(PetscPartitioner part)
129077623264SMatthew G. Knepley {
129177623264SMatthew G. Knepley   PetscPartitioner_Chaco *p = (PetscPartitioner_Chaco *) part->data;
129277623264SMatthew G. Knepley   PetscErrorCode          ierr;
129377623264SMatthew G. Knepley 
129477623264SMatthew G. Knepley   PetscFunctionBegin;
129577623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
129677623264SMatthew G. Knepley   PetscFunctionReturn(0);
129777623264SMatthew G. Knepley }
129877623264SMatthew G. Knepley 
1299d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco_Ascii(PetscPartitioner part, PetscViewer viewer)
130077623264SMatthew G. Knepley {
130177623264SMatthew G. Knepley   PetscFunctionBegin;
130277623264SMatthew G. Knepley   PetscFunctionReturn(0);
130377623264SMatthew G. Knepley }
130477623264SMatthew G. Knepley 
1305d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco(PetscPartitioner part, PetscViewer viewer)
130677623264SMatthew G. Knepley {
130777623264SMatthew G. Knepley   PetscBool      iascii;
130877623264SMatthew G. Knepley   PetscErrorCode ierr;
130977623264SMatthew G. Knepley 
131077623264SMatthew G. Knepley   PetscFunctionBegin;
131177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
131277623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
131377623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
131477623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Chaco_Ascii(part, viewer);CHKERRQ(ierr);}
131577623264SMatthew G. Knepley   PetscFunctionReturn(0);
131677623264SMatthew G. Knepley }
131777623264SMatthew G. Knepley 
131870034214SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
131970034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
132070034214SMatthew G. Knepley #include <unistd.h>
132170034214SMatthew G. Knepley #endif
132211d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
132311d1e910SBarry Smith #include <chaco.h>
132411d1e910SBarry Smith #else
132511d1e910SBarry Smith /* Older versions of Chaco do not have an include file */
132670034214SMatthew G. Knepley PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
132770034214SMatthew G. Knepley                        float *ewgts, float *x, float *y, float *z, char *outassignname,
132870034214SMatthew G. Knepley                        char *outfilename, short *assignment, int architecture, int ndims_tot,
132970034214SMatthew G. Knepley                        int mesh_dims[3], double *goal, int global_method, int local_method,
133070034214SMatthew G. Knepley                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
133111d1e910SBarry Smith #endif
133270034214SMatthew G. Knepley extern int FREE_GRAPH;
133377623264SMatthew G. Knepley #endif
133470034214SMatthew G. Knepley 
1335d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Chaco(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
133670034214SMatthew G. Knepley {
133777623264SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
133870034214SMatthew G. Knepley   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
133970034214SMatthew G. Knepley   MPI_Comm       comm;
134070034214SMatthew G. Knepley   int            nvtxs          = numVertices; /* number of vertices in full graph */
134170034214SMatthew G. Knepley   int           *vwgts          = NULL;   /* weights for all vertices */
134270034214SMatthew G. Knepley   float         *ewgts          = NULL;   /* weights for all edges */
134370034214SMatthew G. Knepley   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
134470034214SMatthew G. Knepley   char          *outassignname  = NULL;   /*  name of assignment output file */
134570034214SMatthew G. Knepley   char          *outfilename    = NULL;   /* output file name */
134670034214SMatthew G. Knepley   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
134770034214SMatthew G. Knepley   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
134870034214SMatthew G. Knepley   int            mesh_dims[3];            /* dimensions of mesh of processors */
134970034214SMatthew G. Knepley   double        *goal          = NULL;    /* desired set sizes for each set */
135070034214SMatthew G. Knepley   int            global_method = 1;       /* global partitioning algorithm */
135170034214SMatthew G. Knepley   int            local_method  = 1;       /* local partitioning algorithm */
135270034214SMatthew G. Knepley   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
135370034214SMatthew G. Knepley   int            vmax          = 200;     /* how many vertices to coarsen down to? */
135470034214SMatthew G. Knepley   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
135570034214SMatthew G. Knepley   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
135670034214SMatthew G. Knepley   long           seed          = 123636512; /* for random graph mutations */
135711d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
135811d1e910SBarry Smith   int           *assignment;              /* Output partition */
135911d1e910SBarry Smith #else
136070034214SMatthew G. Knepley   short int     *assignment;              /* Output partition */
136111d1e910SBarry Smith #endif
136270034214SMatthew G. Knepley   int            fd_stdout, fd_pipe[2];
136370034214SMatthew G. Knepley   PetscInt      *points;
136470034214SMatthew G. Knepley   int            i, v, p;
136570034214SMatthew G. Knepley   PetscErrorCode ierr;
136670034214SMatthew G. Knepley 
136770034214SMatthew G. Knepley   PetscFunctionBegin;
136870034214SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
136907ed3857SLisandro Dalcin #if defined (PETSC_USE_DEBUG)
137007ed3857SLisandro Dalcin   {
137107ed3857SLisandro Dalcin     int ival,isum;
137207ed3857SLisandro Dalcin     PetscBool distributed;
137307ed3857SLisandro Dalcin 
137407ed3857SLisandro Dalcin     ival = (numVertices > 0);
137507ed3857SLisandro Dalcin     ierr = MPI_Allreduce(&ival, &isum, 1, MPI_INT, MPI_SUM, comm);CHKERRQ(ierr);
137607ed3857SLisandro Dalcin     distributed = (isum > 1) ? PETSC_TRUE : PETSC_FALSE;
137707ed3857SLisandro Dalcin     if (distributed) SETERRQ(comm, PETSC_ERR_SUP, "Chaco cannot partition a distributed graph");
137807ed3857SLisandro Dalcin   }
137907ed3857SLisandro Dalcin #endif
138070034214SMatthew G. Knepley   if (!numVertices) {
138177623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
138277623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
138370034214SMatthew G. Knepley     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
138470034214SMatthew G. Knepley     PetscFunctionReturn(0);
138570034214SMatthew G. Knepley   }
138670034214SMatthew G. Knepley   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
138770034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
138870034214SMatthew G. Knepley 
138970034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
139070034214SMatthew G. Knepley     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
139170034214SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
139270034214SMatthew G. Knepley   }
139377623264SMatthew G. Knepley   mesh_dims[0] = nparts;
139470034214SMatthew G. Knepley   mesh_dims[1] = 1;
139570034214SMatthew G. Knepley   mesh_dims[2] = 1;
139670034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &assignment);CHKERRQ(ierr);
139770034214SMatthew G. Knepley   /* Chaco outputs to stdout. We redirect this to a buffer. */
139870034214SMatthew G. Knepley   /* TODO: check error codes for UNIX calls */
139970034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
140070034214SMatthew G. Knepley   {
140170034214SMatthew G. Knepley     int piperet;
140270034214SMatthew G. Knepley     piperet = pipe(fd_pipe);
140370034214SMatthew G. Knepley     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
140470034214SMatthew G. Knepley     fd_stdout = dup(1);
140570034214SMatthew G. Knepley     close(1);
140670034214SMatthew G. Knepley     dup2(fd_pipe[1], 1);
140770034214SMatthew G. Knepley   }
140870034214SMatthew G. Knepley #endif
140970034214SMatthew G. Knepley   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
141070034214SMatthew G. Knepley                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
141170034214SMatthew G. Knepley                    vmax, ndims, eigtol, seed);
141270034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
141370034214SMatthew G. Knepley   {
141470034214SMatthew G. Knepley     char msgLog[10000];
141570034214SMatthew G. Knepley     int  count;
141670034214SMatthew G. Knepley 
141770034214SMatthew G. Knepley     fflush(stdout);
141870034214SMatthew G. Knepley     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
141970034214SMatthew G. Knepley     if (count < 0) count = 0;
142070034214SMatthew G. Knepley     msgLog[count] = 0;
142170034214SMatthew G. Knepley     close(1);
142270034214SMatthew G. Knepley     dup2(fd_stdout, 1);
142370034214SMatthew G. Knepley     close(fd_stdout);
142470034214SMatthew G. Knepley     close(fd_pipe[0]);
142570034214SMatthew G. Knepley     close(fd_pipe[1]);
142670034214SMatthew G. Knepley     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
142770034214SMatthew G. Knepley   }
142807ed3857SLisandro Dalcin #else
142907ed3857SLisandro Dalcin   if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", "error in stdout");
143070034214SMatthew G. Knepley #endif
143170034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
143277623264SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
143370034214SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {
143477623264SMatthew G. Knepley     ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);
143570034214SMatthew G. Knepley   }
143677623264SMatthew G. Knepley   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
143770034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
143877623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
143970034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
144070034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
144170034214SMatthew G. Knepley     }
144270034214SMatthew G. Knepley   }
144370034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
144470034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
144570034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
144670034214SMatthew G. Knepley     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
144770034214SMatthew G. Knepley   }
144870034214SMatthew G. Knepley   ierr = PetscFree(assignment);CHKERRQ(ierr);
144970034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
145070034214SMatthew G. Knepley   PetscFunctionReturn(0);
145177623264SMatthew G. Knepley #else
145277623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
145370034214SMatthew G. Knepley #endif
145477623264SMatthew G. Knepley }
145577623264SMatthew G. Knepley 
1456d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Chaco(PetscPartitioner part)
145777623264SMatthew G. Knepley {
145877623264SMatthew G. Knepley   PetscFunctionBegin;
145977623264SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Chaco;
146077623264SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Chaco;
146177623264SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Chaco;
146277623264SMatthew G. Knepley   PetscFunctionReturn(0);
146377623264SMatthew G. Knepley }
146477623264SMatthew G. Knepley 
146577623264SMatthew G. Knepley /*MC
146677623264SMatthew G. Knepley   PETSCPARTITIONERCHACO = "chaco" - A PetscPartitioner object using the Chaco library
146777623264SMatthew G. Knepley 
146877623264SMatthew G. Knepley   Level: intermediate
146977623264SMatthew G. Knepley 
147077623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
147177623264SMatthew G. Knepley M*/
147277623264SMatthew G. Knepley 
147377623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Chaco(PetscPartitioner part)
147477623264SMatthew G. Knepley {
147577623264SMatthew G. Knepley   PetscPartitioner_Chaco *p;
147677623264SMatthew G. Knepley   PetscErrorCode          ierr;
147777623264SMatthew G. Knepley 
147877623264SMatthew G. Knepley   PetscFunctionBegin;
147977623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
148077623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
148177623264SMatthew G. Knepley   part->data = p;
148277623264SMatthew G. Knepley 
148377623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Chaco(part);CHKERRQ(ierr);
148477623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ChacoPartitionerCitation, &ChacoPartitionercite);CHKERRQ(ierr);
148577623264SMatthew G. Knepley   PetscFunctionReturn(0);
148677623264SMatthew G. Knepley }
148777623264SMatthew G. Knepley 
14885b440754SMatthew G. Knepley static const char *ptypes[] = {"kway", "rb"};
14895b440754SMatthew G. Knepley 
1490d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_ParMetis(PetscPartitioner part)
149177623264SMatthew G. Knepley {
149277623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
149377623264SMatthew G. Knepley   PetscErrorCode             ierr;
149477623264SMatthew G. Knepley 
149577623264SMatthew G. Knepley   PetscFunctionBegin;
149677623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
149777623264SMatthew G. Knepley   PetscFunctionReturn(0);
149877623264SMatthew G. Knepley }
149977623264SMatthew G. Knepley 
1500d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis_Ascii(PetscPartitioner part, PetscViewer viewer)
150177623264SMatthew G. Knepley {
15022abdaa70SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
150377623264SMatthew G. Knepley   PetscErrorCode             ierr;
150477623264SMatthew G. Knepley 
150577623264SMatthew G. Knepley   PetscFunctionBegin;
15062abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
15072abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "ParMetis type: %s\n", ptypes[p->ptype]);CHKERRQ(ierr);
15082abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "load imbalance ratio %g\n", (double) p->imbalanceRatio);CHKERRQ(ierr);
15092abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "debug flag %D\n", p->debugFlag);CHKERRQ(ierr);
15102abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
151177623264SMatthew G. Knepley   PetscFunctionReturn(0);
151277623264SMatthew G. Knepley }
151377623264SMatthew G. Knepley 
1514d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis(PetscPartitioner part, PetscViewer viewer)
151577623264SMatthew G. Knepley {
151677623264SMatthew G. Knepley   PetscBool      iascii;
151777623264SMatthew G. Knepley   PetscErrorCode ierr;
151877623264SMatthew G. Knepley 
151977623264SMatthew G. Knepley   PetscFunctionBegin;
152077623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
152177623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
152277623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
152377623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_ParMetis_Ascii(part, viewer);CHKERRQ(ierr);}
152477623264SMatthew G. Knepley   PetscFunctionReturn(0);
152577623264SMatthew G. Knepley }
152670034214SMatthew G. Knepley 
152744d8be81SLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_ParMetis(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
152844d8be81SLisandro Dalcin {
152944d8be81SLisandro Dalcin   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
153042678178SLisandro Dalcin   PetscInt                  p_randomSeed = -1; /* TODO: Add this to PetscPartitioner_ParMetis */
153144d8be81SLisandro Dalcin   PetscErrorCode            ierr;
153244d8be81SLisandro Dalcin 
153344d8be81SLisandro Dalcin   PetscFunctionBegin;
153444d8be81SLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner ParMetis Options");CHKERRQ(ierr);
153544d8be81SLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_parmetis_type", "Partitioning method", "", ptypes, 2, ptypes[p->ptype], &p->ptype, NULL);CHKERRQ(ierr);
15365b440754SMatthew G. Knepley   ierr = PetscOptionsReal("-petscpartitioner_parmetis_imbalance_ratio", "Load imbalance ratio limit", "", p->imbalanceRatio, &p->imbalanceRatio, NULL);CHKERRQ(ierr);
15375b440754SMatthew G. Knepley   ierr = PetscOptionsInt("-petscpartitioner_parmetis_debug", "Debugging flag", "", p->debugFlag, &p->debugFlag, NULL);CHKERRQ(ierr);
153842678178SLisandro Dalcin   ierr = PetscOptionsInt("-petscpartitioner_parmetis_seed", "Random seed", "", p_randomSeed, &p_randomSeed, NULL);CHKERRQ(ierr);
153944d8be81SLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
154044d8be81SLisandro Dalcin   PetscFunctionReturn(0);
154144d8be81SLisandro Dalcin }
154244d8be81SLisandro Dalcin 
154370034214SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
154470034214SMatthew G. Knepley #include <parmetis.h>
154577623264SMatthew G. Knepley #endif
154670034214SMatthew G. Knepley 
1547d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_ParMetis(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
154870034214SMatthew G. Knepley {
154977623264SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
15505b440754SMatthew G. Knepley   PetscPartitioner_ParMetis *pm = (PetscPartitioner_ParMetis *) part->data;
155170034214SMatthew G. Knepley   MPI_Comm       comm;
1552deea36a5SMatthew G. Knepley   PetscSection   section;
155370034214SMatthew G. Knepley   PetscInt       nvtxs       = numVertices; /* The number of vertices in full graph */
155470034214SMatthew G. Knepley   PetscInt      *vtxdist;                   /* Distribution of vertices across processes */
155570034214SMatthew G. Knepley   PetscInt      *xadj        = start;       /* Start of edge list for each vertex */
155670034214SMatthew G. Knepley   PetscInt      *adjncy      = adjacency;   /* Edge lists for all vertices */
155770034214SMatthew G. Knepley   PetscInt      *vwgt        = NULL;        /* Vertex weights */
155870034214SMatthew G. Knepley   PetscInt      *adjwgt      = NULL;        /* Edge weights */
155970034214SMatthew G. Knepley   PetscInt       wgtflag     = 0;           /* Indicates which weights are present */
156070034214SMatthew G. Knepley   PetscInt       numflag     = 0;           /* Indicates initial offset (0 or 1) */
156170034214SMatthew G. Knepley   PetscInt       ncon        = 1;           /* The number of weights per vertex */
15625b440754SMatthew G. Knepley   PetscInt       metis_ptype = pm->ptype;   /* kway or recursive bisection */
1563fb83b9f2SMichael Gegg   real_t        *tpwgts;                    /* The fraction of vertex weights assigned to each partition */
1564fb83b9f2SMichael Gegg   real_t        *ubvec;                     /* The balance intolerance for vertex weights */
1565b3ce585bSLisandro Dalcin   PetscInt       options[64];               /* Options */
156670034214SMatthew G. Knepley   /* Outputs */
1567b3ce585bSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
1568b3ce585bSLisandro Dalcin   PetscMPIInt    size, rank, p;
156942678178SLisandro Dalcin   PetscInt       pm_randomSeed = -1;
157070034214SMatthew G. Knepley   PetscErrorCode ierr;
157170034214SMatthew G. Knepley 
157270034214SMatthew G. Knepley   PetscFunctionBegin;
157342678178SLisandro Dalcin   ierr = PetscOptionsGetInt(((PetscObject)part)->options,((PetscObject)part)->prefix,"-petscpartitioner_parmetis_seed", &pm_randomSeed, NULL);CHKERRQ(ierr);
157477623264SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) part, &comm);CHKERRQ(ierr);
1575b3ce585bSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
157670034214SMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
157770034214SMatthew G. Knepley   /* Calculate vertex distribution */
1578b3ce585bSLisandro Dalcin   ierr = PetscMalloc5(size+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment,nvtxs,&vwgt);CHKERRQ(ierr);
157970034214SMatthew G. Knepley   vtxdist[0] = 0;
158070034214SMatthew G. Knepley   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
1581b3ce585bSLisandro Dalcin   for (p = 2; p <= size; ++p) {
158270034214SMatthew G. Knepley     vtxdist[p] += vtxdist[p-1];
158370034214SMatthew G. Knepley   }
158444d8be81SLisandro Dalcin   /* Calculate partition weights */
158570034214SMatthew G. Knepley   for (p = 0; p < nparts; ++p) {
158670034214SMatthew G. Knepley     tpwgts[p] = 1.0/nparts;
158770034214SMatthew G. Knepley   }
15885b440754SMatthew G. Knepley   ubvec[0] = pm->imbalanceRatio;
1589deea36a5SMatthew G. Knepley   /* Weight cells by dofs on cell by default */
1590e87a4003SBarry Smith   ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
1591deea36a5SMatthew G. Knepley   if (section) {
1592deea36a5SMatthew G. Knepley     PetscInt cStart, cEnd, dof;
159370034214SMatthew G. Knepley 
1594deea36a5SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1595deea36a5SMatthew G. Knepley     for (v = cStart; v < cEnd; ++v) {
1596deea36a5SMatthew G. Knepley       ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr);
1597925b1076SLisandro Dalcin       /* WARNING: Assumes that meshes with overlap have the overlapped cells at the end of the stratum. */
1598925b1076SLisandro Dalcin       /* To do this properly, we should use the cell numbering created in DMPlexCreatePartitionerGraph. */
1599925b1076SLisandro Dalcin       if (v-cStart < numVertices) vwgt[v-cStart] = PetscMax(dof, 1);
1600deea36a5SMatthew G. Knepley     }
1601deea36a5SMatthew G. Knepley   } else {
1602deea36a5SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) vwgt[v] = 1;
1603cd0de0f2SShri   }
160444d8be81SLisandro Dalcin   wgtflag |= 2; /* have weights on graph vertices */
1605cd0de0f2SShri 
160670034214SMatthew G. Knepley   if (nparts == 1) {
16079fc93327SToby Isaac     ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));CHKERRQ(ierr);
160870034214SMatthew G. Knepley   } else {
1609b3ce585bSLisandro Dalcin     for (p = 0; !vtxdist[p+1] && p < size; ++p);
1610b3ce585bSLisandro Dalcin     if (vtxdist[p+1] == vtxdist[size]) {
1611b3ce585bSLisandro Dalcin       if (rank == p) {
161244d8be81SLisandro Dalcin         ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
161342678178SLisandro Dalcin         options[METIS_OPTION_DBGLVL] = pm->debugFlag;
161442678178SLisandro Dalcin         options[METIS_OPTION_SEED]   = pm_randomSeed;
161544d8be81SLisandro Dalcin         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
161644d8be81SLisandro Dalcin         if (metis_ptype == 1) {
161744d8be81SLisandro Dalcin           PetscStackPush("METIS_PartGraphRecursive");
161872379da4SMatthew G. Knepley           ierr = METIS_PartGraphRecursive(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
161944d8be81SLisandro Dalcin           PetscStackPop;
162044d8be81SLisandro Dalcin           if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphRecursive()");
162144d8be81SLisandro Dalcin         } else {
162244d8be81SLisandro Dalcin           /*
162344d8be81SLisandro Dalcin            It would be nice to activate the two options below, but they would need some actual testing.
162444d8be81SLisandro Dalcin            - Turning on these options may exercise path of the METIS code that have bugs and may break production runs.
162544d8be81SLisandro 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.
162644d8be81SLisandro Dalcin           */
162744d8be81SLisandro Dalcin           /* options[METIS_OPTION_CONTIG]  = 1; */ /* try to produce partitions that are contiguous */
162844d8be81SLisandro Dalcin           /* options[METIS_OPTION_MINCONN] = 1; */ /* minimize the maximum degree of the subdomain graph */
162970034214SMatthew G. Knepley           PetscStackPush("METIS_PartGraphKway");
163072379da4SMatthew G. Knepley           ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
163170034214SMatthew G. Knepley           PetscStackPop;
163270034214SMatthew G. Knepley           if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
163370034214SMatthew G. Knepley         }
163444d8be81SLisandro Dalcin       }
163570034214SMatthew G. Knepley     } else {
163642678178SLisandro Dalcin       options[0] = 1; /*use options */
16375b440754SMatthew G. Knepley       options[1] = pm->debugFlag;
163842678178SLisandro Dalcin       options[2] = (pm_randomSeed == -1) ? 15 : pm_randomSeed; /* default is GLOBAL_SEED=15 from `libparmetis/defs.h` */
163970034214SMatthew G. Knepley       PetscStackPush("ParMETIS_V3_PartKway");
164072379da4SMatthew G. Knepley       ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment, &comm);
164170034214SMatthew G. Knepley       PetscStackPop;
1642c717d290SMatthew G. Knepley       if (ierr != METIS_OK) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error %d in ParMETIS_V3_PartKway()", ierr);
164370034214SMatthew G. Knepley     }
164470034214SMatthew G. Knepley   }
164570034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
164677623264SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
164777623264SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
164877623264SMatthew G. Knepley   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
164970034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
165077623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
165170034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
165270034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
165370034214SMatthew G. Knepley     }
165470034214SMatthew G. Knepley   }
165570034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
165670034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
1657cd0de0f2SShri   ierr = PetscFree5(vtxdist,tpwgts,ubvec,assignment,vwgt);CHKERRQ(ierr);
16589b80ac48SMatthew G. Knepley   PetscFunctionReturn(0);
165970034214SMatthew G. Knepley #else
166077623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
166170034214SMatthew G. Knepley #endif
166270034214SMatthew G. Knepley }
166370034214SMatthew G. Knepley 
1664d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_ParMetis(PetscPartitioner part)
166577623264SMatthew G. Knepley {
166677623264SMatthew G. Knepley   PetscFunctionBegin;
166777623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_ParMetis;
166844d8be81SLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_ParMetis;
166977623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_ParMetis;
167077623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_ParMetis;
167177623264SMatthew G. Knepley   PetscFunctionReturn(0);
167277623264SMatthew G. Knepley }
167377623264SMatthew G. Knepley 
167477623264SMatthew G. Knepley /*MC
167577623264SMatthew G. Knepley   PETSCPARTITIONERPARMETIS = "parmetis" - A PetscPartitioner object using the ParMetis library
167677623264SMatthew G. Knepley 
167777623264SMatthew G. Knepley   Level: intermediate
167877623264SMatthew G. Knepley 
167977623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
168077623264SMatthew G. Knepley M*/
168177623264SMatthew G. Knepley 
168277623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_ParMetis(PetscPartitioner part)
168377623264SMatthew G. Knepley {
168477623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p;
168577623264SMatthew G. Knepley   PetscErrorCode          ierr;
168677623264SMatthew G. Knepley 
168777623264SMatthew G. Knepley   PetscFunctionBegin;
168877623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
168977623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
169077623264SMatthew G. Knepley   part->data = p;
169177623264SMatthew G. Knepley 
16925b440754SMatthew G. Knepley   p->ptype          = 0;
16935b440754SMatthew G. Knepley   p->imbalanceRatio = 1.05;
16945b440754SMatthew G. Knepley   p->debugFlag      = 0;
16955b440754SMatthew G. Knepley 
169677623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_ParMetis(part);CHKERRQ(ierr);
169777623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ParMetisPartitionerCitation, &ParMetisPartitionercite);CHKERRQ(ierr);
169870034214SMatthew G. Knepley   PetscFunctionReturn(0);
169970034214SMatthew G. Knepley }
170070034214SMatthew G. Knepley 
1701137cd93aSLisandro Dalcin 
1702137cd93aSLisandro Dalcin PetscBool PTScotchPartitionercite = PETSC_FALSE;
1703137cd93aSLisandro Dalcin const char PTScotchPartitionerCitation[] =
1704137cd93aSLisandro Dalcin   "@article{PTSCOTCH,\n"
1705137cd93aSLisandro Dalcin   "  author  = {C. Chevalier and F. Pellegrini},\n"
1706137cd93aSLisandro Dalcin   "  title   = {{PT-SCOTCH}: a tool for efficient parallel graph ordering},\n"
1707137cd93aSLisandro Dalcin   "  journal = {Parallel Computing},\n"
1708137cd93aSLisandro Dalcin   "  volume  = {34},\n"
1709137cd93aSLisandro Dalcin   "  number  = {6},\n"
1710137cd93aSLisandro Dalcin   "  pages   = {318--331},\n"
1711137cd93aSLisandro Dalcin   "  year    = {2008},\n"
1712137cd93aSLisandro Dalcin   "  doi     = {https://doi.org/10.1016/j.parco.2007.12.001}\n"
1713137cd93aSLisandro Dalcin   "}\n";
1714137cd93aSLisandro Dalcin 
1715137cd93aSLisandro Dalcin typedef struct {
1716137cd93aSLisandro Dalcin   PetscInt  strategy;
1717137cd93aSLisandro Dalcin   PetscReal imbalance;
1718137cd93aSLisandro Dalcin } PetscPartitioner_PTScotch;
1719137cd93aSLisandro Dalcin 
1720137cd93aSLisandro Dalcin static const char *const
1721137cd93aSLisandro Dalcin PTScotchStrategyList[] = {
1722137cd93aSLisandro Dalcin   "DEFAULT",
1723137cd93aSLisandro Dalcin   "QUALITY",
1724137cd93aSLisandro Dalcin   "SPEED",
1725137cd93aSLisandro Dalcin   "BALANCE",
1726137cd93aSLisandro Dalcin   "SAFETY",
1727137cd93aSLisandro Dalcin   "SCALABILITY",
1728137cd93aSLisandro Dalcin   "RECURSIVE",
1729137cd93aSLisandro Dalcin   "REMAP"
1730137cd93aSLisandro Dalcin };
1731137cd93aSLisandro Dalcin 
1732137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
1733137cd93aSLisandro Dalcin 
1734137cd93aSLisandro Dalcin EXTERN_C_BEGIN
1735137cd93aSLisandro Dalcin #include <ptscotch.h>
1736137cd93aSLisandro Dalcin EXTERN_C_END
1737137cd93aSLisandro Dalcin 
1738137cd93aSLisandro Dalcin #define CHKERRPTSCOTCH(ierr) do { if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error calling PT-Scotch library"); } while(0)
1739137cd93aSLisandro Dalcin 
1740137cd93aSLisandro Dalcin static int PTScotch_Strategy(PetscInt strategy)
1741137cd93aSLisandro Dalcin {
1742137cd93aSLisandro Dalcin   switch (strategy) {
1743137cd93aSLisandro Dalcin   case  0: return SCOTCH_STRATDEFAULT;
1744137cd93aSLisandro Dalcin   case  1: return SCOTCH_STRATQUALITY;
1745137cd93aSLisandro Dalcin   case  2: return SCOTCH_STRATSPEED;
1746137cd93aSLisandro Dalcin   case  3: return SCOTCH_STRATBALANCE;
1747137cd93aSLisandro Dalcin   case  4: return SCOTCH_STRATSAFETY;
1748137cd93aSLisandro Dalcin   case  5: return SCOTCH_STRATSCALABILITY;
1749137cd93aSLisandro Dalcin   case  6: return SCOTCH_STRATRECURSIVE;
1750137cd93aSLisandro Dalcin   case  7: return SCOTCH_STRATREMAP;
1751137cd93aSLisandro Dalcin   default: return SCOTCH_STRATDEFAULT;
1752137cd93aSLisandro Dalcin   }
1753137cd93aSLisandro Dalcin }
1754137cd93aSLisandro Dalcin 
1755137cd93aSLisandro Dalcin 
1756137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_Seq(SCOTCH_Num strategy, double imbalance, SCOTCH_Num n, SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
1757137cd93aSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num part[])
1758137cd93aSLisandro Dalcin {
1759137cd93aSLisandro Dalcin   SCOTCH_Graph   grafdat;
1760137cd93aSLisandro Dalcin   SCOTCH_Strat   stradat;
1761137cd93aSLisandro Dalcin   SCOTCH_Num     vertnbr = n;
1762137cd93aSLisandro Dalcin   SCOTCH_Num     edgenbr = xadj[n];
1763137cd93aSLisandro Dalcin   SCOTCH_Num*    velotab = vtxwgt;
1764137cd93aSLisandro Dalcin   SCOTCH_Num*    edlotab = adjwgt;
1765137cd93aSLisandro Dalcin   SCOTCH_Num     flagval = strategy;
1766137cd93aSLisandro Dalcin   double         kbalval = imbalance;
1767137cd93aSLisandro Dalcin   PetscErrorCode ierr;
1768137cd93aSLisandro Dalcin 
1769137cd93aSLisandro Dalcin   PetscFunctionBegin;
1770d99a0000SVaclav Hapla   {
1771d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
1772d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
1773d99a0000SVaclav Hapla     if (!flg) velotab = NULL;
1774d99a0000SVaclav Hapla   }
1775137cd93aSLisandro Dalcin   ierr = SCOTCH_graphInit(&grafdat);CHKERRPTSCOTCH(ierr);
1776137cd93aSLisandro Dalcin   ierr = SCOTCH_graphBuild(&grafdat, 0, vertnbr, xadj, xadj + 1, velotab, NULL, edgenbr, adjncy, edlotab);CHKERRPTSCOTCH(ierr);
1777137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
1778137cd93aSLisandro Dalcin   ierr = SCOTCH_stratGraphMapBuild(&stradat, flagval, nparts, kbalval);CHKERRPTSCOTCH(ierr);
1779137cd93aSLisandro Dalcin #if defined(PETSC_USE_DEBUG)
1780137cd93aSLisandro Dalcin   ierr = SCOTCH_graphCheck(&grafdat);CHKERRPTSCOTCH(ierr);
1781137cd93aSLisandro Dalcin #endif
1782137cd93aSLisandro Dalcin   ierr = SCOTCH_graphPart(&grafdat, nparts, &stradat, part);CHKERRPTSCOTCH(ierr);
1783137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
1784137cd93aSLisandro Dalcin   SCOTCH_graphExit(&grafdat);
1785137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1786137cd93aSLisandro Dalcin }
1787137cd93aSLisandro Dalcin 
1788137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_MPI(SCOTCH_Num strategy, double imbalance, SCOTCH_Num vtxdist[], SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
1789137cd93aSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num part[], MPI_Comm comm)
1790137cd93aSLisandro Dalcin {
1791137cd93aSLisandro Dalcin   PetscMPIInt     procglbnbr;
1792137cd93aSLisandro Dalcin   PetscMPIInt     proclocnum;
1793137cd93aSLisandro Dalcin   SCOTCH_Arch     archdat;
1794137cd93aSLisandro Dalcin   SCOTCH_Dgraph   grafdat;
1795137cd93aSLisandro Dalcin   SCOTCH_Dmapping mappdat;
1796137cd93aSLisandro Dalcin   SCOTCH_Strat    stradat;
1797137cd93aSLisandro Dalcin   SCOTCH_Num      vertlocnbr;
1798137cd93aSLisandro Dalcin   SCOTCH_Num      edgelocnbr;
1799137cd93aSLisandro Dalcin   SCOTCH_Num*     veloloctab = vtxwgt;
1800137cd93aSLisandro Dalcin   SCOTCH_Num*     edloloctab = adjwgt;
1801137cd93aSLisandro Dalcin   SCOTCH_Num      flagval = strategy;
1802137cd93aSLisandro Dalcin   double          kbalval = imbalance;
1803137cd93aSLisandro Dalcin   PetscErrorCode  ierr;
1804137cd93aSLisandro Dalcin 
1805137cd93aSLisandro Dalcin   PetscFunctionBegin;
1806d99a0000SVaclav Hapla   {
1807d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
1808d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
1809d99a0000SVaclav Hapla     if (!flg) veloloctab = NULL;
1810d99a0000SVaclav Hapla   }
1811137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &procglbnbr);CHKERRQ(ierr);
1812137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &proclocnum);CHKERRQ(ierr);
1813137cd93aSLisandro Dalcin   vertlocnbr = vtxdist[proclocnum + 1] - vtxdist[proclocnum];
1814137cd93aSLisandro Dalcin   edgelocnbr = xadj[vertlocnbr];
1815137cd93aSLisandro Dalcin 
1816137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphInit(&grafdat, comm);CHKERRPTSCOTCH(ierr);
1817137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphBuild(&grafdat, 0, vertlocnbr, vertlocnbr, xadj, xadj + 1, veloloctab, NULL, edgelocnbr, edgelocnbr, adjncy, NULL, edloloctab);CHKERRPTSCOTCH(ierr);
1818137cd93aSLisandro Dalcin #if defined(PETSC_USE_DEBUG)
1819137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphCheck(&grafdat);CHKERRPTSCOTCH(ierr);
1820137cd93aSLisandro Dalcin #endif
1821137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
1822137cd93aSLisandro Dalcin   ierr = SCOTCH_stratDgraphMapBuild(&stradat, flagval, procglbnbr, nparts, kbalval);CHKERRQ(ierr);
1823137cd93aSLisandro Dalcin   ierr = SCOTCH_archInit(&archdat);CHKERRPTSCOTCH(ierr);
1824137cd93aSLisandro Dalcin   ierr = SCOTCH_archCmplt(&archdat, nparts);CHKERRPTSCOTCH(ierr);
1825137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapInit(&grafdat, &mappdat, &archdat, part);CHKERRPTSCOTCH(ierr);
1826137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapCompute(&grafdat, &mappdat, &stradat);CHKERRPTSCOTCH(ierr);
1827137cd93aSLisandro Dalcin   SCOTCH_dgraphMapExit(&grafdat, &mappdat);
1828137cd93aSLisandro Dalcin   SCOTCH_archExit(&archdat);
1829137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
1830137cd93aSLisandro Dalcin   SCOTCH_dgraphExit(&grafdat);
1831137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1832137cd93aSLisandro Dalcin }
1833137cd93aSLisandro Dalcin 
1834137cd93aSLisandro Dalcin #endif /* PETSC_HAVE_PTSCOTCH */
1835137cd93aSLisandro Dalcin 
1836137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerDestroy_PTScotch(PetscPartitioner part)
1837137cd93aSLisandro Dalcin {
1838137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
1839137cd93aSLisandro Dalcin   PetscErrorCode             ierr;
1840137cd93aSLisandro Dalcin 
1841137cd93aSLisandro Dalcin   PetscFunctionBegin;
1842137cd93aSLisandro Dalcin   ierr = PetscFree(p);CHKERRQ(ierr);
1843137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1844137cd93aSLisandro Dalcin }
1845137cd93aSLisandro Dalcin 
1846137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch_Ascii(PetscPartitioner part, PetscViewer viewer)
1847137cd93aSLisandro Dalcin {
1848137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
1849137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
1850137cd93aSLisandro Dalcin 
1851137cd93aSLisandro Dalcin   PetscFunctionBegin;
1852137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1853137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer, "using partitioning strategy %s\n",PTScotchStrategyList[p->strategy]);CHKERRQ(ierr);
1854137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer, "using load imbalance ratio %g\n",(double)p->imbalance);CHKERRQ(ierr);
1855137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1856137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1857137cd93aSLisandro Dalcin }
1858137cd93aSLisandro Dalcin 
1859137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch(PetscPartitioner part, PetscViewer viewer)
1860137cd93aSLisandro Dalcin {
1861137cd93aSLisandro Dalcin   PetscBool      iascii;
1862137cd93aSLisandro Dalcin   PetscErrorCode ierr;
1863137cd93aSLisandro Dalcin 
1864137cd93aSLisandro Dalcin   PetscFunctionBegin;
1865137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1866137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1867137cd93aSLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1868137cd93aSLisandro Dalcin   if (iascii) {ierr = PetscPartitionerView_PTScotch_Ascii(part, viewer);CHKERRQ(ierr);}
1869137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1870137cd93aSLisandro Dalcin }
1871137cd93aSLisandro Dalcin 
1872137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_PTScotch(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
1873137cd93aSLisandro Dalcin {
1874137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
1875137cd93aSLisandro Dalcin   const char *const         *slist = PTScotchStrategyList;
1876137cd93aSLisandro Dalcin   PetscInt                  nlist = (PetscInt)(sizeof(PTScotchStrategyList)/sizeof(PTScotchStrategyList[0]));
1877137cd93aSLisandro Dalcin   PetscBool                 flag;
1878137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
1879137cd93aSLisandro Dalcin 
1880137cd93aSLisandro Dalcin   PetscFunctionBegin;
1881137cd93aSLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner PTScotch Options");CHKERRQ(ierr);
1882137cd93aSLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_ptscotch_strategy","Partitioning strategy","",slist,nlist,slist[p->strategy],&p->strategy,&flag);CHKERRQ(ierr);
1883137cd93aSLisandro Dalcin   ierr = PetscOptionsReal("-petscpartitioner_ptscotch_imbalance","Load imbalance ratio","",p->imbalance,&p->imbalance,&flag);CHKERRQ(ierr);
1884137cd93aSLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
1885137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1886137cd93aSLisandro Dalcin }
1887137cd93aSLisandro Dalcin 
1888137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerPartition_PTScotch(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1889137cd93aSLisandro Dalcin {
1890137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
1891137cd93aSLisandro Dalcin   MPI_Comm       comm       = PetscObjectComm((PetscObject)part);
1892137cd93aSLisandro Dalcin   PetscInt       nvtxs      = numVertices; /* The number of vertices in full graph */
1893137cd93aSLisandro Dalcin   PetscInt      *vtxdist;                  /* Distribution of vertices across processes */
1894137cd93aSLisandro Dalcin   PetscInt      *xadj       = start;       /* Start of edge list for each vertex */
1895137cd93aSLisandro Dalcin   PetscInt      *adjncy     = adjacency;   /* Edge lists for all vertices */
1896137cd93aSLisandro Dalcin   PetscInt      *vwgt       = NULL;        /* Vertex weights */
1897137cd93aSLisandro Dalcin   PetscInt      *adjwgt     = NULL;        /* Edge weights */
1898137cd93aSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
1899137cd93aSLisandro Dalcin   PetscMPIInt    size, rank, p;
1900137cd93aSLisandro Dalcin   PetscErrorCode ierr;
1901137cd93aSLisandro Dalcin 
1902137cd93aSLisandro Dalcin   PetscFunctionBegin;
1903137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
1904137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
190599b53901SStefano Zampini   ierr = PetscMalloc2(size+1,&vtxdist,PetscMax(nvtxs,1),&assignment);CHKERRQ(ierr);
1906137cd93aSLisandro Dalcin 
1907137cd93aSLisandro Dalcin   /* Calculate vertex distribution */
1908137cd93aSLisandro Dalcin   vtxdist[0] = 0;
1909137cd93aSLisandro Dalcin   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
1910137cd93aSLisandro Dalcin   for (p = 2; p <= size; ++p) {
1911137cd93aSLisandro Dalcin     vtxdist[p] += vtxdist[p-1];
1912137cd93aSLisandro Dalcin   }
1913137cd93aSLisandro Dalcin 
1914137cd93aSLisandro Dalcin   if (nparts == 1) {
1915137cd93aSLisandro Dalcin     ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));CHKERRQ(ierr);
1916137cd93aSLisandro Dalcin   } else {
1917137cd93aSLisandro Dalcin     PetscSection section;
1918137cd93aSLisandro Dalcin     /* Weight cells by dofs on cell by default */
1919137cd93aSLisandro Dalcin     ierr = PetscMalloc1(PetscMax(nvtxs,1),&vwgt);CHKERRQ(ierr);
1920e87a4003SBarry Smith     ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
1921137cd93aSLisandro Dalcin     if (section) {
1922137cd93aSLisandro Dalcin       PetscInt vStart, vEnd, dof;
1923137cd93aSLisandro Dalcin       ierr = DMPlexGetHeightStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1924137cd93aSLisandro Dalcin       for (v = vStart; v < vEnd; ++v) {
1925137cd93aSLisandro Dalcin         ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr);
1926137cd93aSLisandro Dalcin         /* WARNING: Assumes that meshes with overlap have the overlapped cells at the end of the stratum. */
1927137cd93aSLisandro Dalcin         /* To do this properly, we should use the cell numbering created in DMPlexCreatePartitionerGraph. */
1928137cd93aSLisandro Dalcin         if (v-vStart < numVertices) vwgt[v-vStart] = PetscMax(dof, 1);
1929137cd93aSLisandro Dalcin       }
1930137cd93aSLisandro Dalcin     } else {
1931137cd93aSLisandro Dalcin       for (v = 0; v < nvtxs; ++v) vwgt[v] = 1;
1932137cd93aSLisandro Dalcin     }
1933137cd93aSLisandro Dalcin     {
1934137cd93aSLisandro Dalcin       PetscPartitioner_PTScotch *pts = (PetscPartitioner_PTScotch *) part->data;
1935137cd93aSLisandro Dalcin       int                       strat = PTScotch_Strategy(pts->strategy);
1936137cd93aSLisandro Dalcin       double                    imbal = (double)pts->imbalance;
1937137cd93aSLisandro Dalcin 
1938137cd93aSLisandro Dalcin       for (p = 0; !vtxdist[p+1] && p < size; ++p);
1939137cd93aSLisandro Dalcin       if (vtxdist[p+1] == vtxdist[size]) {
1940137cd93aSLisandro Dalcin         if (rank == p) {
1941137cd93aSLisandro Dalcin           ierr = PTScotch_PartGraph_Seq(strat, imbal, nvtxs, xadj, adjncy, vwgt, adjwgt, nparts, assignment);CHKERRQ(ierr);
1942137cd93aSLisandro Dalcin         }
1943137cd93aSLisandro Dalcin       } else {
1944137cd93aSLisandro Dalcin         ierr = PTScotch_PartGraph_MPI(strat, imbal, vtxdist, xadj, adjncy, vwgt, adjwgt, nparts, assignment, comm);CHKERRQ(ierr);
1945137cd93aSLisandro Dalcin       }
1946137cd93aSLisandro Dalcin     }
1947137cd93aSLisandro Dalcin     ierr = PetscFree(vwgt);CHKERRQ(ierr);
1948137cd93aSLisandro Dalcin   }
1949137cd93aSLisandro Dalcin 
1950137cd93aSLisandro Dalcin   /* Convert to PetscSection+IS */
1951137cd93aSLisandro Dalcin   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1952137cd93aSLisandro Dalcin   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
1953137cd93aSLisandro Dalcin   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1954137cd93aSLisandro Dalcin   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
1955137cd93aSLisandro Dalcin   for (p = 0, i = 0; p < nparts; ++p) {
1956137cd93aSLisandro Dalcin     for (v = 0; v < nvtxs; ++v) {
1957137cd93aSLisandro Dalcin       if (assignment[v] == p) points[i++] = v;
1958137cd93aSLisandro Dalcin     }
1959137cd93aSLisandro Dalcin   }
1960137cd93aSLisandro Dalcin   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
1961137cd93aSLisandro Dalcin   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
1962137cd93aSLisandro Dalcin 
1963137cd93aSLisandro Dalcin   ierr = PetscFree2(vtxdist,assignment);CHKERRQ(ierr);
1964137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1965137cd93aSLisandro Dalcin #else
1966137cd93aSLisandro Dalcin   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-ptscotch.");
1967137cd93aSLisandro Dalcin #endif
1968137cd93aSLisandro Dalcin }
1969137cd93aSLisandro Dalcin 
1970137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerInitialize_PTScotch(PetscPartitioner part)
1971137cd93aSLisandro Dalcin {
1972137cd93aSLisandro Dalcin   PetscFunctionBegin;
1973137cd93aSLisandro Dalcin   part->ops->view           = PetscPartitionerView_PTScotch;
1974137cd93aSLisandro Dalcin   part->ops->destroy        = PetscPartitionerDestroy_PTScotch;
1975137cd93aSLisandro Dalcin   part->ops->partition      = PetscPartitionerPartition_PTScotch;
1976137cd93aSLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_PTScotch;
1977137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1978137cd93aSLisandro Dalcin }
1979137cd93aSLisandro Dalcin 
1980137cd93aSLisandro Dalcin /*MC
1981137cd93aSLisandro Dalcin   PETSCPARTITIONERPTSCOTCH = "ptscotch" - A PetscPartitioner object using the PT-Scotch library
1982137cd93aSLisandro Dalcin 
1983137cd93aSLisandro Dalcin   Level: intermediate
1984137cd93aSLisandro Dalcin 
1985137cd93aSLisandro Dalcin .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1986137cd93aSLisandro Dalcin M*/
1987137cd93aSLisandro Dalcin 
1988137cd93aSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_PTScotch(PetscPartitioner part)
1989137cd93aSLisandro Dalcin {
1990137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p;
1991137cd93aSLisandro Dalcin   PetscErrorCode          ierr;
1992137cd93aSLisandro Dalcin 
1993137cd93aSLisandro Dalcin   PetscFunctionBegin;
1994137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1995137cd93aSLisandro Dalcin   ierr = PetscNewLog(part, &p);CHKERRQ(ierr);
1996137cd93aSLisandro Dalcin   part->data = p;
1997137cd93aSLisandro Dalcin 
1998137cd93aSLisandro Dalcin   p->strategy  = 0;
1999137cd93aSLisandro Dalcin   p->imbalance = 0.01;
2000137cd93aSLisandro Dalcin 
2001137cd93aSLisandro Dalcin   ierr = PetscPartitionerInitialize_PTScotch(part);CHKERRQ(ierr);
2002137cd93aSLisandro Dalcin   ierr = PetscCitationsRegister(PTScotchPartitionerCitation, &PTScotchPartitionercite);CHKERRQ(ierr);
2003137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2004137cd93aSLisandro Dalcin }
2005137cd93aSLisandro Dalcin 
2006137cd93aSLisandro Dalcin 
20075680f57bSMatthew G. Knepley /*@
20085680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
20095680f57bSMatthew G. Knepley 
20105680f57bSMatthew G. Knepley   Not collective
20115680f57bSMatthew G. Knepley 
20125680f57bSMatthew G. Knepley   Input Parameter:
20135680f57bSMatthew G. Knepley . dm - The DM
20145680f57bSMatthew G. Knepley 
20155680f57bSMatthew G. Knepley   Output Parameter:
20165680f57bSMatthew G. Knepley . part - The PetscPartitioner
20175680f57bSMatthew G. Knepley 
20185680f57bSMatthew G. Knepley   Level: developer
20195680f57bSMatthew G. Knepley 
202098599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
202198599a47SLawrence Mitchell 
202298599a47SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerCreate()
20235680f57bSMatthew G. Knepley @*/
20245680f57bSMatthew G. Knepley PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
20255680f57bSMatthew G. Knepley {
20265680f57bSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex *) dm->data;
20275680f57bSMatthew G. Knepley 
20285680f57bSMatthew G. Knepley   PetscFunctionBegin;
20295680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20305680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
20315680f57bSMatthew G. Knepley   *part = mesh->partitioner;
20325680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
20335680f57bSMatthew G. Knepley }
20345680f57bSMatthew G. Knepley 
203571bb2955SLawrence Mitchell /*@
203671bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
203771bb2955SLawrence Mitchell 
203871bb2955SLawrence Mitchell   logically collective on dm and part
203971bb2955SLawrence Mitchell 
204071bb2955SLawrence Mitchell   Input Parameters:
204171bb2955SLawrence Mitchell + dm - The DM
204271bb2955SLawrence Mitchell - part - The partitioner
204371bb2955SLawrence Mitchell 
204471bb2955SLawrence Mitchell   Level: developer
204571bb2955SLawrence Mitchell 
204671bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
204771bb2955SLawrence Mitchell 
204871bb2955SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate()
204971bb2955SLawrence Mitchell @*/
205071bb2955SLawrence Mitchell PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
205171bb2955SLawrence Mitchell {
205271bb2955SLawrence Mitchell   DM_Plex       *mesh = (DM_Plex *) dm->data;
205371bb2955SLawrence Mitchell   PetscErrorCode ierr;
205471bb2955SLawrence Mitchell 
205571bb2955SLawrence Mitchell   PetscFunctionBegin;
205671bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
205771bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
205871bb2955SLawrence Mitchell   ierr = PetscObjectReference((PetscObject)part);CHKERRQ(ierr);
205971bb2955SLawrence Mitchell   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
206071bb2955SLawrence Mitchell   mesh->partitioner = part;
206171bb2955SLawrence Mitchell   PetscFunctionReturn(0);
206271bb2955SLawrence Mitchell }
206371bb2955SLawrence Mitchell 
2064e8f14785SLisandro Dalcin static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
2065270bba0cSToby Isaac {
2066270bba0cSToby Isaac   PetscErrorCode ierr;
2067270bba0cSToby Isaac 
2068270bba0cSToby Isaac   PetscFunctionBegin;
20696a5a2ffdSToby Isaac   if (up) {
20706a5a2ffdSToby Isaac     PetscInt parent;
20716a5a2ffdSToby Isaac 
2072270bba0cSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
20736a5a2ffdSToby Isaac     if (parent != point) {
20746a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
20756a5a2ffdSToby Isaac 
2076270bba0cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
2077270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
2078270bba0cSToby Isaac         PetscInt cpoint = closure[2*i];
2079270bba0cSToby Isaac 
2080e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
20811b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
2082270bba0cSToby Isaac       }
2083270bba0cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
20846a5a2ffdSToby Isaac     }
20856a5a2ffdSToby Isaac   }
20866a5a2ffdSToby Isaac   if (down) {
20876a5a2ffdSToby Isaac     PetscInt numChildren;
20886a5a2ffdSToby Isaac     const PetscInt *children;
20896a5a2ffdSToby Isaac 
20906a5a2ffdSToby Isaac     ierr = DMPlexGetTreeChildren(dm,point,&numChildren,&children);CHKERRQ(ierr);
20916a5a2ffdSToby Isaac     if (numChildren) {
20926a5a2ffdSToby Isaac       PetscInt i;
20936a5a2ffdSToby Isaac 
20946a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
20956a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
20966a5a2ffdSToby Isaac 
2097e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
20981b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
20996a5a2ffdSToby Isaac       }
21006a5a2ffdSToby Isaac     }
21016a5a2ffdSToby Isaac   }
2102270bba0cSToby Isaac   PetscFunctionReturn(0);
2103270bba0cSToby Isaac }
2104270bba0cSToby Isaac 
2105825f8a23SLisandro Dalcin PETSC_INTERN PetscErrorCode DMPlexPartitionLabelClosure_Private(DM,DMLabel,PetscInt,PetscInt,const PetscInt[],IS*);
2106825f8a23SLisandro Dalcin 
2107825f8a23SLisandro Dalcin PetscErrorCode DMPlexPartitionLabelClosure_Private(DM dm, DMLabel label, PetscInt rank, PetscInt numPoints, const PetscInt points[], IS *closureIS)
2108825f8a23SLisandro Dalcin {
2109825f8a23SLisandro Dalcin   DM_Plex        *mesh = (DM_Plex *)dm->data;
2110825f8a23SLisandro Dalcin   PetscBool      hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
2111825f8a23SLisandro Dalcin   PetscInt       *closure = NULL, closureSize, nelems, *elems, off = 0, p, c;
2112825f8a23SLisandro Dalcin   PetscHSetI     ht;
2113825f8a23SLisandro Dalcin   PetscErrorCode ierr;
2114825f8a23SLisandro Dalcin 
2115825f8a23SLisandro Dalcin   PetscFunctionBegin;
2116825f8a23SLisandro Dalcin   ierr = PetscHSetICreate(&ht);CHKERRQ(ierr);
2117825f8a23SLisandro Dalcin   ierr = PetscHSetIResize(ht, numPoints*16);CHKERRQ(ierr);
2118825f8a23SLisandro Dalcin   for (p = 0; p < numPoints; ++p) {
2119825f8a23SLisandro Dalcin     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2120825f8a23SLisandro Dalcin     for (c = 0; c < closureSize*2; c += 2) {
2121825f8a23SLisandro Dalcin       ierr = PetscHSetIAdd(ht, closure[c]);CHKERRQ(ierr);
2122825f8a23SLisandro Dalcin       if (hasTree) {ierr = DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE);CHKERRQ(ierr);}
2123825f8a23SLisandro Dalcin     }
2124825f8a23SLisandro Dalcin   }
2125825f8a23SLisandro Dalcin   if (closure) {ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure);CHKERRQ(ierr);}
2126825f8a23SLisandro Dalcin   ierr = PetscHSetIGetSize(ht, &nelems);CHKERRQ(ierr);
2127825f8a23SLisandro Dalcin   ierr = PetscMalloc1(nelems, &elems);CHKERRQ(ierr);
2128825f8a23SLisandro Dalcin   ierr = PetscHSetIGetElems(ht, &off, elems);CHKERRQ(ierr);
2129825f8a23SLisandro Dalcin   ierr = PetscHSetIDestroy(&ht);CHKERRQ(ierr);
2130825f8a23SLisandro Dalcin   ierr = PetscSortInt(nelems, elems);CHKERRQ(ierr);
2131825f8a23SLisandro Dalcin   ierr = ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS);CHKERRQ(ierr);
2132825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
2133825f8a23SLisandro Dalcin }
2134825f8a23SLisandro Dalcin 
21355abbe4feSMichael Lange /*@
21365abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
21375abbe4feSMichael Lange 
21385abbe4feSMichael Lange   Input Parameters:
21395abbe4feSMichael Lange + dm     - The DM
21405abbe4feSMichael Lange - label  - DMLabel assinging ranks to remote roots
21415abbe4feSMichael Lange 
21425abbe4feSMichael Lange   Level: developer
21435abbe4feSMichael Lange 
21445abbe4feSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
21455abbe4feSMichael Lange @*/
21465abbe4feSMichael Lange PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
21479ffc88e4SToby Isaac {
2148825f8a23SLisandro Dalcin   IS              rankIS,   pointIS, closureIS;
21495abbe4feSMichael Lange   const PetscInt *ranks,   *points;
2150825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
21519ffc88e4SToby Isaac   PetscErrorCode  ierr;
21529ffc88e4SToby Isaac 
21539ffc88e4SToby Isaac   PetscFunctionBegin;
21545abbe4feSMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
21555abbe4feSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
21565abbe4feSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
21575abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
21585abbe4feSMichael Lange     const PetscInt rank = ranks[r];
21595abbe4feSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
21605abbe4feSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
21615abbe4feSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
2162825f8a23SLisandro Dalcin     ierr = DMPlexPartitionLabelClosure_Private(dm, label, rank, numPoints, points, &closureIS);CHKERRQ(ierr);
21635abbe4feSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
21645abbe4feSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2165825f8a23SLisandro Dalcin     ierr = DMLabelSetStratumIS(label, rank, closureIS);CHKERRQ(ierr);
2166825f8a23SLisandro Dalcin     ierr = ISDestroy(&closureIS);CHKERRQ(ierr);
21679ffc88e4SToby Isaac   }
21685abbe4feSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
21695abbe4feSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
21709ffc88e4SToby Isaac   PetscFunctionReturn(0);
21719ffc88e4SToby Isaac }
21729ffc88e4SToby Isaac 
217324d039d7SMichael Lange /*@
217424d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
217524d039d7SMichael Lange 
217624d039d7SMichael Lange   Input Parameters:
217724d039d7SMichael Lange + dm     - The DM
217824d039d7SMichael Lange - label  - DMLabel assinging ranks to remote roots
217924d039d7SMichael Lange 
218024d039d7SMichael Lange   Level: developer
218124d039d7SMichael Lange 
218224d039d7SMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
218324d039d7SMichael Lange @*/
218424d039d7SMichael Lange PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
218570034214SMatthew G. Knepley {
218624d039d7SMichael Lange   IS              rankIS,   pointIS;
218724d039d7SMichael Lange   const PetscInt *ranks,   *points;
218824d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
218924d039d7SMichael Lange   PetscInt       *adj = NULL;
219070034214SMatthew G. Knepley   PetscErrorCode  ierr;
219170034214SMatthew G. Knepley 
219270034214SMatthew G. Knepley   PetscFunctionBegin;
219324d039d7SMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
219424d039d7SMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
219524d039d7SMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
219624d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
219724d039d7SMichael Lange     const PetscInt rank = ranks[r];
219870034214SMatthew G. Knepley 
219924d039d7SMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
220024d039d7SMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
220124d039d7SMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
220270034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
220324d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
220424d039d7SMichael Lange       ierr = DMPlexGetAdjacency(dm, points[p], &adjSize, &adj);CHKERRQ(ierr);
220524d039d7SMichael Lange       for (a = 0; a < adjSize; ++a) {ierr = DMLabelSetValue(label, adj[a], rank);CHKERRQ(ierr);}
220670034214SMatthew G. Knepley     }
220724d039d7SMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
220824d039d7SMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
220970034214SMatthew G. Knepley   }
221024d039d7SMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
221124d039d7SMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
221224d039d7SMichael Lange   ierr = PetscFree(adj);CHKERRQ(ierr);
221324d039d7SMichael Lange   PetscFunctionReturn(0);
221470034214SMatthew G. Knepley }
221570034214SMatthew G. Knepley 
2216be200f8dSMichael Lange /*@
2217be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
2218be200f8dSMichael Lange 
2219be200f8dSMichael Lange   Input Parameters:
2220be200f8dSMichael Lange + dm     - The DM
2221be200f8dSMichael Lange - label  - DMLabel assinging ranks to remote roots
2222be200f8dSMichael Lange 
2223be200f8dSMichael Lange   Level: developer
2224be200f8dSMichael Lange 
2225be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
2226be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
2227be200f8dSMichael Lange 
2228be200f8dSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
2229be200f8dSMichael Lange @*/
2230be200f8dSMichael Lange PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
2231be200f8dSMichael Lange {
2232be200f8dSMichael Lange   MPI_Comm        comm;
2233be200f8dSMichael Lange   PetscMPIInt     rank;
2234be200f8dSMichael Lange   PetscSF         sfPoint;
22355d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
2236be200f8dSMichael Lange   IS              rankIS, pointIS;
2237be200f8dSMichael Lange   const PetscInt *ranks;
2238be200f8dSMichael Lange   PetscInt        numRanks, r;
2239be200f8dSMichael Lange   PetscErrorCode  ierr;
2240be200f8dSMichael Lange 
2241be200f8dSMichael Lange   PetscFunctionBegin;
2242be200f8dSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
2243be200f8dSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2244be200f8dSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
22455d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
22465d04f6ebSMichael Lange   ierr = DMLabelGather(label, sfPoint, &lblLeaves);CHKERRQ(ierr);
22475d04f6ebSMichael Lange   ierr = DMLabelGetValueIS(lblLeaves, &rankIS);CHKERRQ(ierr);
22485d04f6ebSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
22495d04f6ebSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
22505d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
22515d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
22525d04f6ebSMichael Lange     if (remoteRank == rank) continue;
22535d04f6ebSMichael Lange     ierr = DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS);CHKERRQ(ierr);
22545d04f6ebSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
22555d04f6ebSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
22565d04f6ebSMichael Lange   }
22575d04f6ebSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
22585d04f6ebSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
22595d04f6ebSMichael Lange   ierr = DMLabelDestroy(&lblLeaves);CHKERRQ(ierr);
2260be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
2261be200f8dSMichael Lange   ierr = DMLabelDistribute(label, sfPoint, &lblRoots);CHKERRQ(ierr);
2262be200f8dSMichael Lange   ierr = DMLabelGetValueIS(lblRoots, &rankIS);CHKERRQ(ierr);
2263be200f8dSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
2264be200f8dSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
2265be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
2266be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
2267be200f8dSMichael Lange     if (remoteRank == rank) continue;
2268be200f8dSMichael Lange     ierr = DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS);CHKERRQ(ierr);
2269be200f8dSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
2270be200f8dSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2271be200f8dSMichael Lange   }
2272be200f8dSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
2273be200f8dSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
2274be200f8dSMichael Lange   ierr = DMLabelDestroy(&lblRoots);CHKERRQ(ierr);
2275be200f8dSMichael Lange   PetscFunctionReturn(0);
2276be200f8dSMichael Lange }
2277be200f8dSMichael Lange 
22781fd9873aSMichael Lange /*@
22791fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
22801fd9873aSMichael Lange 
22811fd9873aSMichael Lange   Input Parameters:
22821fd9873aSMichael Lange + dm        - The DM
22831fd9873aSMichael Lange . rootLabel - DMLabel assinging ranks to local roots
22841fd9873aSMichael Lange . processSF - A star forest mapping into the local index on each remote rank
22851fd9873aSMichael Lange 
22861fd9873aSMichael Lange   Output Parameter:
22871fd9873aSMichael Lange - leafLabel - DMLabel assinging ranks to remote roots
22881fd9873aSMichael Lange 
22891fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
22901fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
22911fd9873aSMichael Lange 
22921fd9873aSMichael Lange   Level: developer
22931fd9873aSMichael Lange 
22941fd9873aSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
22951fd9873aSMichael Lange @*/
22961fd9873aSMichael Lange PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
22971fd9873aSMichael Lange {
22981fd9873aSMichael Lange   MPI_Comm           comm;
2299874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
2300874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
23011fd9873aSMichael Lange   PetscSF            sfPoint;
2302874ddda9SLisandro Dalcin   PetscSection       rootSection;
23031fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
23041fd9873aSMichael Lange   const PetscSFNode *remote;
23051fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
23061fd9873aSMichael Lange   IS                 valueIS;
2307874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
23081fd9873aSMichael Lange   PetscErrorCode     ierr;
23091fd9873aSMichael Lange 
23101fd9873aSMichael Lange   PetscFunctionBegin;
23111fd9873aSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
23121fd9873aSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
23139852e123SBarry Smith   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
23141fd9873aSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
23151fd9873aSMichael Lange 
23161fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
23171fd9873aSMichael Lange   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
23189852e123SBarry Smith   ierr = PetscSectionSetChart(rootSection, 0, size);CHKERRQ(ierr);
23191fd9873aSMichael Lange   ierr = DMLabelGetValueIS(rootLabel, &valueIS);CHKERRQ(ierr);
23201fd9873aSMichael Lange   ierr = ISGetLocalSize(valueIS, &numNeighbors);CHKERRQ(ierr);
23211fd9873aSMichael Lange   ierr = ISGetIndices(valueIS, &neighbors);CHKERRQ(ierr);
23221fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
23231fd9873aSMichael Lange     ierr = DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints);CHKERRQ(ierr);
23241fd9873aSMichael Lange     ierr = PetscSectionAddDof(rootSection, neighbors[n], numPoints);CHKERRQ(ierr);
23251fd9873aSMichael Lange   }
23261fd9873aSMichael Lange   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
2327874ddda9SLisandro Dalcin   ierr = PetscSectionGetStorageSize(rootSection, &rootSize);CHKERRQ(ierr);
2328874ddda9SLisandro Dalcin   ierr = PetscMalloc1(rootSize, &rootPoints);CHKERRQ(ierr);
23291fd9873aSMichael Lange   ierr = PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote);CHKERRQ(ierr);
23301fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
23311fd9873aSMichael Lange     IS              pointIS;
23321fd9873aSMichael Lange     const PetscInt *points;
23331fd9873aSMichael Lange 
23341fd9873aSMichael Lange     ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
23351fd9873aSMichael Lange     ierr = DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS);CHKERRQ(ierr);
23361fd9873aSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
23371fd9873aSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
23381fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
2339f8987ae8SMichael Lange       if (local) {ierr = PetscFindInt(points[p], nleaves, local, &l);CHKERRQ(ierr);}
2340f8987ae8SMichael Lange       else       {l = -1;}
23411fd9873aSMichael Lange       if (l >= 0) {rootPoints[off+p] = remote[l];}
23421fd9873aSMichael Lange       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
23431fd9873aSMichael Lange     }
23441fd9873aSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
23451fd9873aSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
23461fd9873aSMichael Lange   }
2347874ddda9SLisandro Dalcin 
2348874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
2349874ddda9SLisandro Dalcin   if (!processSF) {
2350874ddda9SLisandro Dalcin     PetscInt64  counter = 0;
2351874ddda9SLisandro Dalcin     PetscBool   locOverflow = PETSC_FALSE;
2352874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
2353874ddda9SLisandro Dalcin 
2354874ddda9SLisandro Dalcin     ierr = PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls);CHKERRQ(ierr);
2355874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
2356874ddda9SLisandro Dalcin       ierr = PetscSectionGetDof(rootSection, neighbors[n], &dof);CHKERRQ(ierr);
2357874ddda9SLisandro Dalcin       ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
2358874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
2359874ddda9SLisandro Dalcin       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2360874ddda9SLisandro Dalcin       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2361874ddda9SLisandro Dalcin #endif
2362874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt) dof;
2363874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt) off;
2364874ddda9SLisandro Dalcin     }
2365874ddda9SLisandro Dalcin     ierr = MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm);CHKERRQ(ierr);
2366874ddda9SLisandro Dalcin     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
2367874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
2368874ddda9SLisandro Dalcin     ierr = MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm);CHKERRQ(ierr);
2369874ddda9SLisandro Dalcin     if (!mpiOverflow) {
2370874ddda9SLisandro Dalcin       leafSize = (PetscInt) counter;
2371874ddda9SLisandro Dalcin       ierr = PetscMalloc1(leafSize, &leafPoints);CHKERRQ(ierr);
2372874ddda9SLisandro Dalcin       ierr = MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm);CHKERRQ(ierr);
2373874ddda9SLisandro Dalcin     }
2374874ddda9SLisandro Dalcin     ierr = PetscFree4(scounts, sdispls, rcounts, rdispls);CHKERRQ(ierr);
2375874ddda9SLisandro Dalcin   }
2376874ddda9SLisandro Dalcin 
2377874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
2378874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
2379874ddda9SLisandro Dalcin     PetscSF      procSF;
2380874ddda9SLisandro Dalcin     PetscSFNode  *remote;
2381874ddda9SLisandro Dalcin     PetscSection leafSection;
2382874ddda9SLisandro Dalcin 
2383874ddda9SLisandro Dalcin     if (processSF) {
2384874ddda9SLisandro Dalcin       ierr = PetscObjectReference((PetscObject)processSF);CHKERRQ(ierr);
2385874ddda9SLisandro Dalcin       procSF = processSF;
2386874ddda9SLisandro Dalcin     } else {
2387874ddda9SLisandro Dalcin       ierr = PetscMalloc1(size, &remote);CHKERRQ(ierr);
2388874ddda9SLisandro Dalcin       for (r = 0; r < size; ++r) { remote[r].rank  = r; remote[r].index = rank; }
2389874ddda9SLisandro Dalcin       ierr = PetscSFCreate(comm, &procSF);CHKERRQ(ierr);
2390874ddda9SLisandro Dalcin       ierr = PetscSFSetGraph(procSF, size, size, NULL, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
2391874ddda9SLisandro Dalcin     }
2392874ddda9SLisandro Dalcin 
2393874ddda9SLisandro Dalcin     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection);CHKERRQ(ierr);
23941fd9873aSMichael Lange     ierr = DMPlexDistributeData(dm, processSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints);CHKERRQ(ierr);
2395874ddda9SLisandro Dalcin     ierr = PetscSectionGetStorageSize(leafSection, &leafSize);CHKERRQ(ierr);
2396874ddda9SLisandro Dalcin     ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
2397874ddda9SLisandro Dalcin     ierr = PetscSFDestroy(&procSF);CHKERRQ(ierr);
2398874ddda9SLisandro Dalcin   }
2399874ddda9SLisandro Dalcin 
2400874ddda9SLisandro Dalcin   for (p = 0; p < leafSize; p++) {
24011fd9873aSMichael Lange     ierr = DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank);CHKERRQ(ierr);
24021fd9873aSMichael Lange   }
2403874ddda9SLisandro Dalcin 
2404874ddda9SLisandro Dalcin   ierr = ISRestoreIndices(valueIS, &neighbors);CHKERRQ(ierr);
2405874ddda9SLisandro Dalcin   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
24061fd9873aSMichael Lange   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
2407874ddda9SLisandro Dalcin   ierr = PetscFree(rootPoints);CHKERRQ(ierr);
24081fd9873aSMichael Lange   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
24091fd9873aSMichael Lange   PetscFunctionReturn(0);
24101fd9873aSMichael Lange }
24111fd9873aSMichael Lange 
2412aa3148a8SMichael Lange /*@
2413aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
2414aa3148a8SMichael Lange 
2415aa3148a8SMichael Lange   Input Parameters:
2416aa3148a8SMichael Lange + dm    - The DM
2417aa3148a8SMichael Lange . label - DMLabel assinging ranks to remote roots
2418aa3148a8SMichael Lange 
2419aa3148a8SMichael Lange   Output Parameter:
2420aa3148a8SMichael Lange - sf    - The star forest communication context encapsulating the defined mapping
2421aa3148a8SMichael Lange 
2422aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
2423aa3148a8SMichael Lange 
2424aa3148a8SMichael Lange   Level: developer
2425aa3148a8SMichael Lange 
2426aa3148a8SMichael Lange .seealso: DMPlexDistribute(), DMPlexCreateOverlap
2427aa3148a8SMichael Lange @*/
2428aa3148a8SMichael Lange PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
2429aa3148a8SMichael Lange {
24309852e123SBarry Smith   PetscMPIInt     rank, size;
243143f7d02bSMichael Lange   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0;
2432aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
243343f7d02bSMichael Lange   IS              remoteRootIS;
243443f7d02bSMichael Lange   const PetscInt *remoteRoots;
2435aa3148a8SMichael Lange   PetscErrorCode ierr;
2436aa3148a8SMichael Lange 
2437aa3148a8SMichael Lange   PetscFunctionBegin;
243843f7d02bSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
24399852e123SBarry Smith   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
2440aa3148a8SMichael Lange 
24419852e123SBarry Smith   for (numRemote = 0, n = 0; n < size; ++n) {
2442aa3148a8SMichael Lange     ierr = DMLabelGetStratumSize(label, n, &numPoints);CHKERRQ(ierr);
2443aa3148a8SMichael Lange     numRemote += numPoints;
2444aa3148a8SMichael Lange   }
2445aa3148a8SMichael Lange   ierr = PetscMalloc1(numRemote, &remotePoints);CHKERRQ(ierr);
244643f7d02bSMichael Lange   /* Put owned points first */
244743f7d02bSMichael Lange   ierr = DMLabelGetStratumSize(label, rank, &numPoints);CHKERRQ(ierr);
244843f7d02bSMichael Lange   if (numPoints > 0) {
244943f7d02bSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &remoteRootIS);CHKERRQ(ierr);
245043f7d02bSMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
245143f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
245243f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
245343f7d02bSMichael Lange       remotePoints[idx].rank = rank;
245443f7d02bSMichael Lange       idx++;
245543f7d02bSMichael Lange     }
245643f7d02bSMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
245743f7d02bSMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
245843f7d02bSMichael Lange   }
245943f7d02bSMichael Lange   /* Now add remote points */
24609852e123SBarry Smith   for (n = 0; n < size; ++n) {
2461aa3148a8SMichael Lange     ierr = DMLabelGetStratumSize(label, n, &numPoints);CHKERRQ(ierr);
246243f7d02bSMichael Lange     if (numPoints <= 0 || n == rank) continue;
2463aa3148a8SMichael Lange     ierr = DMLabelGetStratumIS(label, n, &remoteRootIS);CHKERRQ(ierr);
2464aa3148a8SMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
2465aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
2466aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
2467aa3148a8SMichael Lange       remotePoints[idx].rank = n;
2468aa3148a8SMichael Lange       idx++;
2469aa3148a8SMichael Lange     }
2470aa3148a8SMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
2471aa3148a8SMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
2472aa3148a8SMichael Lange   }
2473aa3148a8SMichael Lange   ierr = PetscSFCreate(PetscObjectComm((PetscObject) dm), sf);CHKERRQ(ierr);
2474aa3148a8SMichael Lange   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2475aa3148a8SMichael Lange   ierr = PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
247670034214SMatthew G. Knepley   PetscFunctionReturn(0);
247770034214SMatthew G. Knepley }
2478